/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 *    Entry Points:     customizeUseDefaultParams(),
            customizeReadDevBoardParams(),
            customizeWriteDevBoardParams(),
            customizeGetMACAddress(), 
            customizeGetIPParameters(),
            customizeSaveIPParameters(), 
            customizeGetSerialNumber(),
            customizeSaveSerialNumber(), 
 *
 * Description.
 * =======================================================================
 *  This file contains the routines that read and write the development
 *  board configuration parameters in NVRAM.  THE CODE IN THIS FILE MUST 
 *  BE CUSTOMIZED TO SUPPORT YOUR APPLICATION HARDWARE.  The default 
 *  implementation supports the NET+OS development boards. This code should 
 *  NOT be used in customer end products since it generates Digi International 
 *  specific Ethernet MAC addresses.  At the very least, the routine 
 *  customizeGetMACAddress() must be rewritten to generate MAC addresses 
 *  in the range assigned to the customer by the IEEE.
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 *
 * JZW  07/27/00   In function NAReadDevBoardParams, if NVRAM is unavailable
 *                 for any reason, we default to the structure defaultParams. At
 *                 this contains hard-coded values. Customers (refer to SCR 1006)
 *                 would prefer to have the defaults default to the contents of
 *                 file appconf.h. Therefore I have changed the two references to
 *                 defaultParams to, instead, call UseDefaultParams, which pulls
 *                 values from appconf.h
 *                 I have chosen not to change the definition of defaultParams. The
 *                 contents will be overwritten upon the first call to UseDefaultParams
 * PMJ  05/02/01   Inserted a NAWriteDevBoardParams() of the default parameters
 *                 in function NAReadDevBoardParams() on a read checksum failure.
 * PMJ  05/23/01   Changed computeChecksum() to remove the presently stored checksum 
 *                 value from the computation.
 * PMJ  03/23/02   Changed NAReadDevBoardParams() to allow expansion, plus included  
 *                 relevant security parameters.
 * PMJ  03/29/02   Included NVRAM capabilities for SNTP Servers. 
 * PMJ  04/09/02   Included Kerberos Realm name in defaultParams.  Removed trailing 
 *                 zeros in defaultParams since they are included in function 
 *                 UseDefaultParams().
 * PMJ  04/10/02   Prevent writes to NVRAM in NAWriteDevBoardParams() if 
 *                 checkAppUseNvram() does not return true.  Note checkAppUseNvram()
 *                 returns true only when APP_USE_NVRAM (in appconf.h) is true.
 * DXL  04/16/02   Cleaned up variable declared but never reference; warnings generated by new compiler
 * LZ   10/21/02   Changed checkAppUseNvram() to NAGetAppUseNvram().
 * CHG  11/14/02   Ran into a problem where invalid configuration records would sometimes be used.
 *                 Apparently the checksum test passes if all fields are zero.  Changed
 *                 NAReadDevBoardParams() to reset the config to default values if the baud rate
 *                 field is zero.  It should never be zero and hangs the board if it is.
 * HOANG(intern) 04/15/03  Added comments to the functions. This is the new API and new comments, need someone to look
 *             over to see if anything thing need to be change in the comments.
 * MLC  08/08/03   Defined time zone in NVRAM and added default values for time zone.
 */



#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include <bsp_sys.h>
#include <bsp_net.h>
#if BSP_WANT_WIRELESS
#include <wln_api.h>
#endif
#include <boardParams.h>
#include <narmnvrm.h>
#include <appconf_api.h>
#include <Npttypes.h>
#include <bootldr.h>
#include <serParam.h>
#include <narmapi.h>
#include <NAsntp.h>
#include "dhcpOptions.h"
#include "bele.h"


#define DEFAULT_STANDARD_TIMEZONE   NASNTP_GMT_MINUS_5  /* Eastern standard time USA */
#define DEFAULT_DAYLIGHT_TIMEZONE   NASNTP_GMT_MINUS_4  /* Eastern Daylight saving time */
#define DEFAULT_START_DAYLIGHT_RULE "3.2.0/02:00:00"    /* March,2nd week,sunday/2am */
#define DEFAULT_END_DAYLIGHT_RULE   "11.1.0/02:00:00"   /* November,1st week,sunday/2am */
#define DEFAULT_SNTP_SYNC_TIME      18000 /* in seconds = 5 hours */

#define DEFAULT_SERIAL_NUMBER       "N99999999"
#define OLD_SERIAL_NUMBER_LENGTH    6
#define OLD_SERIAL_NUMBER_START     (BP_SERIAL_NUMBER_LENGTH - OLD_SERIAL_NUMBER_LENGTH)

#define ETHERNET_ADDRESS_LENGTH     6
#define SHORT_FORMAT_LENGTH         6
#define LONG_FORMAT_LENGTH          17

#define BAD_HEX_DIGIT               0xff


#define DEFAULT_WLN_BAND            (0)
/* signature used to restore default wireless paramater if the restore to 
   default is issued when wireless interface was disabled */
#define PARAM_RESTORED_SIGNATURE    0x44664C74   /* DfLt */

static BYTE const digiMacPrefix[] = {0x00, 0x40, 0x9d};
static int nvramChecksumError = FALSE;

static unsigned long computeChecksum (devBoardParamsType *params);
static BYTE convertHexDigit(char hexDigit);


/*ad*
 * The board parameters API is used to read and write configuration
 * settings for the development board that are stored in NVRAM.  
 * 
 * These settings are stored in a devBoardParamsType structure in 
 * persistent storage on the development board.  Generally, you 
 * will need to make significant changes to this API and to the
 * format of NVRAM storage in order to support your specific
 * application.  This API is only meant to support NET+OS development
 * boards and to serve as an example.
 *
 *
 * @category Board_Params
 * @since 6.0
 * @overview Development Board Parameters
 * @library bsp
 * @include <boardParams.h>
 * @platform all
 * @external
*ad*/
 


/*
 * The structure below contains hardcoded default settings for a Digi International's 
 * development board's startup parameters.   
 * These constant values will be overwritten with the ones which are defined 
 * in appconf.h when customizeUseDefaultParams() is called. 
 * 
 *  Notes:
 *
 *      THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  The implementation
 *      below is for NET+OS development boards only.
 *
 */

devBoardParamsType defaultParams;

static boardParamsFreeFnType freeFn = NULL;
static boardParamsMallocFnType mallocFn = NULL;

#if BSP_WANT_WIRELESS


static BYTE *wepParsePsk(char *pskString)
{
    static BYTE psk[WLN_PSK_SIZE];
    unsigned i;
    
    memset(psk, 0, sizeof(psk));
    
    if (pskString != NULL)
    {
        if (strlen(pskString) != 2*WLN_PSK_SIZE)
        {
            goto done;
        }
        
        for (i = 0; i < WLN_PSK_SIZE; i++)
        {
            psk[i] = (convertHexDigit(pskString[2*i]) << 4);
            psk[i] |= convertHexDigit(pskString[(2*i) + 1]);
        }
    }
done:
    return psk;
}

static BYTE *wepParseKey(char *keyString)
{
    static BYTE key[WLN_WEP104_SIZE];
    unsigned i;
    unsigned keyLength;
    
    memset(key, 0, sizeof(key));
    
    if (keyString != NULL)
    {
        keyLength = strlen(keyString) / 2;
        if ((keyLength != WLN_WEP40_SIZE) && (keyLength != WLN_WEP104_SIZE))
        {
            goto done;          /* reject illegal length keys */
        }
        
        
        for (i = 0; i < keyLength; i++)
        {
            key[i] = (convertHexDigit(keyString[2*i]) << 4);
            key[i] |= convertHexDigit(keyString[(2*i) + 1]);
        }
    }
    else
    {
        memset(key, 0, sizeof(key));
    }
done:
    return key;
}

static unsigned wepKeyLength(char *keyString)
{
    unsigned keyLength = 0;
    
    if (keyString != NULL)
    {
        keyLength = strlen(keyString) / 2;
        if ((keyLength != WLN_WEP40_SIZE) && (keyLength != WLN_WEP104_SIZE))
        {
            keyLength = 0;          /* reject illegal length keys */
        }
    }
    return keyLength;
}


    
// note, ghs doesn't like initializers like .wln_bss=WLN_BSS_ESS
static wln_params *getDefaultWlnParams(void)
{
    static BOOLEAN firstTime = TRUE;
    static wln_params defaultWlnParams =
    {
        WLN_BSS_ESS, /* .bss_type =  */
        "", /* .ssid =  */
        0, /* .ssid_len = */
        0, /* .channel =  */
        {0}, /* sta_addr */
        WLN_AUTH_OPEN, /* authen */
        WLN_ENCR_OPEN, /* encrypt */
        0, /* wep_key_id */
        0, /* wep_key_len */
        {{ 0 }},/*.wep_key */
        { 0 }, /*.wpa_psk */
        WLN_EAP_ANY, /* eap_methods */
        "", /* identity */
        "", /* password */
        0, /* options */
        WLN_CHANMASK_ALL, /* chan_mask */
#ifdef BSP_ARM9        
        540, /* 54 mbps tx_rate */
#else
        110, /* 11 mbps tx_rate */
#endif
        0, /* rts_thresh */
        0, /* frag_thresh */
        WLN_PWR_MAX, /* power_mode */
    	DEFAULT_WLN_BAND, /* band, not used */
#if (PLATFORM == connectcorewi9c_a)
	10                 /* default tx_power is 10 on wi9c with UBEC chip */
#else
        WLN_TXPOWER_DEFAULT /* tx_power */
#endif
    };

    if (firstTime)
    {
        defaultWlnParams.bss_type = NAGetAppWlnBssType();
        if (NAGetAppWlnSsid() != NULL)
        {
            defaultWlnParams.ssid_len = strlen(NAGetAppWlnSsid());
            memcpy (defaultWlnParams.ssid, NAGetAppWlnSsid(), sizeof(defaultWlnParams.ssid));
        }
        defaultWlnParams.channel = NAGetAppWlnChannel();
        defaultWlnParams.authen = NAGetAppWlnAuthenticationType();
        defaultWlnParams.encrypt = NAGetAppWlnEncryptionType();
        defaultWlnParams.wep_key_id = NAGetAppWlnKeyId();
        defaultWlnParams.wep_key_len = wepKeyLength(NAGetAppWlnKey(0));
        memcpy (defaultWlnParams.wep_key[0], wepParseKey(NAGetAppWlnKey(0)), sizeof(defaultWlnParams.wep_key[0]));
        memcpy (defaultWlnParams.wep_key[1], wepParseKey(NAGetAppWlnKey(1)), sizeof(defaultWlnParams.wep_key[1]));
        memcpy (defaultWlnParams.wep_key[2], wepParseKey(NAGetAppWlnKey(2)), sizeof(defaultWlnParams.wep_key[2]));
        memcpy (defaultWlnParams.wep_key[3], wepParseKey(NAGetAppWlnKey(3)), sizeof(defaultWlnParams.wep_key[3]));
        defaultWlnParams.eap_methods = NAGetAppWlnEapMethods();
        memcpy (defaultWlnParams.identity, NAGetAppWlnIdentity(), sizeof(defaultWlnParams.identity));
        defaultWlnParams.identity[sizeof(defaultWlnParams.identity) - 1] = 0;
        memcpy (defaultWlnParams.password, NAGetAppWlnPassword(), sizeof(defaultWlnParams.password));
        defaultWlnParams.password[sizeof(defaultWlnParams.password) - 1] = 0;
        memcpy (defaultWlnParams.wpa_psk, wepParsePsk(NAGetAppWlnPsk()), WLN_PSK_SIZE);
        firstTime = FALSE;
    }
    
    return &defaultWlnParams;
}



/*ad*
 * Set the default PSK.
 *
 * This function sets the default PSK to be used by 802.11.  This value is only used
 * if the configuration values in NVRAM are corrupted, or if NVRAM has been disabled.
 *
 * @category Board_Params  
 * @since 7.0
 * @external
 *
 * @param   psk     pointer to new wireless PSK
*ad*/
void customizeSetDefaultWlnPsk(unsigned char * psk)
{
    wln_params *defaultWlnParams = getDefaultWlnParams();
    
    memcpy(defaultWlnParams->wpa_psk, psk, sizeof(defaultWlnParams->wpa_psk));
}


#endif

/*ad*
 * Sets the malloc routine used by the board parameters API
 *
 * Use this function to set the malloc() function that will be used
 * by the board Parameters API to allocate memory.  This should almost
 * always be set to the standard C malloc() function.  The bootloader
 * uses a different version of this function to reduce its memory
 * footprint.
 *
 * @category Board_Params  
 * @since 6.0
 * @external
 *
 * @param bpMallocFn    pointer to malloc() function
 * @param bpFreeFn      pointer to free() function
*ad*/
void NABoardParamsSetMalloc(boardParamsMallocFnType bpMallocFn, boardParamsFreeFnType bpFreeFn)
{
    mallocFn = bpMallocFn;
    freeFn = bpFreeFn;
}


/*ad*
 * Used internally to allocate memory buffers
 *
 * Use the malloc function registered by NABoardParamsSetMalloc()
 * to allocate a buffer.  Return NULL if NABoardParamsSetMalloc()
 * has not been called.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @param size          number of bytes to allocate
 *
 * @return  NULL        out of memory or mallocFn not setup
 * @return pointer      pointer to buffer
*ad*/
static void * bpMalloc(size_t size)
{
    void *result = NULL;
    
    if (mallocFn != NULL)
    {
        result = mallocFn(size);
    }
    
    return result;
}


/*ad*
 * Used internally to free memory buffers
 *
 * Use the free function registered by NABoardParamsSetMalloc()
 * to allocate a buffer.  Return NULL if NABoardParamsSetMalloc()
 * has not been called.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @param buffer        pointer to memory to free
*ad*/
static void bpFree(void * buffer)
{
    if (freeFn)
    {
        freeFn(buffer);
    }
} 

#if BSP_WANT_WIRELESS
/*
 * customizeGetWirelessParameters
 *
 *  Description:
 *
 *      This function retrieves the wireless network parameters 
 *      from NVRAM and returns it in the buffer passed to us.  
 *      If we are unable to read NVRAM, then a default value is used.
 * 
 *  Notes:
 *
 *      THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  The implementation
 *      below is for NET+OS development boards only.
 *
 *  Parameters:
 *
 *      wln_params  Pointer to destination of wireless parameters.
 *
 */

int
customizeGetWirelessParameters (wln_params *wlnParams)
{
    devBoardParamsType *params;
    int result;

    NA_ASSERT(wlnParams != NULL);

	params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
	if (params == NULL)
	{
		return -1;
	}
    result = customizeReadDevBoardParams (params);             /* read params in NVRAM*/
    
    memcpy (wlnParams, &params->wlnParams, sizeof params->wlnParams);
    customizeGetInterfaceMACAddress(BP_WLN_INTERFACE, wlnParams->sta_addr);

	bpFree(params);

    return result;
}
#endif //  BSP_WANT_WIRELESS  
    

/*ad*
 * Calculate a checksum using a 32-bit CRC algorithm.  This algorithm
 * replaces the original checksum method that did a simple summation.
 * The checksum calculation is done in two stages because the checksum
 * result is stored in the middle of the record and we don't want to
 * include it in the calculation.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @param params    pointer to buffer with NVRAM parameters
 *
 * @return 32-bit CRC checksum
*ad*/
static unsigned long computeChecksum(devBoardParamsType * params)
{
    WORD32 accumulator = blCrc32(0, params, offsetof(devBoardParamsType, checksum));
    
    return (blCrc32(accumulator, ((unsigned char *)&(params->checksum)) + sizeof(params->checksum),
        sizeof(devBoardParamsType) - offsetof(devBoardParamsType, checksum) - sizeof(params->checksum)));
}
    
static unsigned long compute63Checksum(devBoardParams63Type * params)
{
    WORD32 accumulator = blCrc32(0, params, offsetof(devBoardParams63Type, checksum));
    
    return (blCrc32(accumulator, ((unsigned char *)&(params->checksum)) + sizeof(params->checksum),
        sizeof(devBoardParams63Type) - offsetof(devBoardParams63Type, checksum) - sizeof(params->checksum)));
}

/*
 * This function will be called if the size of the previously ran version's board
 * parameter is greater than the current structure.  
 */
static unsigned long computeChecksumFromSize(devBoardParamsType * params)
{
    int ccode;
    WORD32 accumulator = blCrc32(0, params, offsetof(devBoardParamsType, checksum));
    
    accumulator = blCrc32(accumulator, ((unsigned char *)&(params->checksum)) + sizeof(params->checksum),
        sizeof(devBoardParamsType) - offsetof(devBoardParamsType, checksum) - sizeof(params->checksum));

    if (params->sizeOfRecord > sizeof(devBoardParamsType))
    {
        unsigned long len = params->sizeOfRecord - sizeof(devBoardParamsType); 
        unsigned char *buffer;

        if (len < sizeof(devBoardParamsType))
        {
            buffer = (unsigned char *) bpMalloc(len);
            if (buffer == NULL)
                return accumulator;

            ccode = NANVRead (BSP_START_OF_DEV_BOARD_PARAMETERS + sizeof(devBoardParamsType), (char *) buffer, len);
            if (ccode == 0)
            {    
                accumulator = blCrc32(accumulator, buffer, len);
            }
            bpFree(buffer); 
        }
    }

    return accumulator;
}
    
/*
 * Deprecated version of computeChecksum.  This version performs
 * a mathematical sum of all the words in the structure.  It is
 * used when reading data stored in NET+OS 5.0 format.
 */
static unsigned long compute500Checksum(devBoardParams500Type * params)
{
    int idx, size;
    unsigned long sum = 0;
    unsigned long *longParams = (unsigned long *) params;

    size = sizeof (devBoardParams500Type) / sizeof (unsigned long);

    /*  subtract off the checksum -- so when we add it later it cancels */
    sum = -params->checksum;

    for (idx = 0; idx < size; idx++)
    {
        sum += *longParams;
        longParams++;
    }

    return (0xffffffff - sum);
}



/*ad*
 * Deprecated version of function that calculates the MAC address from the
 * serial number.
 *
 * @category Board_Params 
 * @since 6.0
 * @param mac_addrp Pointer to destination of ethernet MAC address. This pointer must point to
 *          storage containing at least 6 bytes.
 * @param serialNumber  Ponter to buffer containing serial number.
 *
*ad*/

static void convertSerialNumberToMacAddress(BYTE * mac_addrp, char * serialNumber)
{
    unsigned long serial_num;

    /* The first half of the ethernet mac address contains the
       number assigned to Digi International by IEEE. The second half is computed
       from the serial number. */ 

    mac_addrp[0] = 0x00; /* IEEE supplied address for Digi International */
    mac_addrp[1] = 0x40;
    mac_addrp[2] = 0x9D;

/*
 * Note that we only use the last 6 digits of the serial number.
 */
    serial_num = (serialNumber[OLD_SERIAL_NUMBER_START]-'0') * 10 + (serialNumber[OLD_SERIAL_NUMBER_START+1]-'0');
    serial_num = serial_num * 0x2710; 
    serial_num = serial_num + (serialNumber[OLD_SERIAL_NUMBER_START+2]-'0')*1000 + (serialNumber[OLD_SERIAL_NUMBER_START+3]-'0')*100 
        + (serialNumber[OLD_SERIAL_NUMBER_START+4]-'0') * 10 + (serialNumber[OLD_SERIAL_NUMBER_START+5]-'0'); 

    mac_addrp[3] = serial_num >> 13;
    mac_addrp[4] = (serial_num >> 5) & 0x000000FF;
    mac_addrp[5] = (serial_num & 0x0000001F) << 3;
}



/**
 * This function has been deprecated in NET+OS 7.0 and should be 
 * replaced with @link customizeGetInterfaceMACAddress. 
 *
 * @external
 * @category Board_Params
 * @since 6.0
 * @deprecated 7.0
 *
 * @param mac_addrp Pointer to destination of ethernet MAC address. This pointer must point to
 *          storage containing at least 6 bytes.
 *
 * @return 0        Success
 * @return -1       Unable to read NVRAM
**/

int customizeGetMACAddress(BYTE * mac_addrp)
{
    devBoardParamsType *params;
    int result;

    NA_ASSERT(mac_addrp != NULL);

    params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
    if (params == NULL)
    {
        return -1;
    }
    result = customizeReadDevBoardParams (params);             /* read params in NVRAM*/

    memcpy (mac_addrp, params->ethernetMac, sizeof params->ethernetMac);

    bpFree(params);
    
    return result;
}


/*ad*
 * Returns the MAC address stored in NVRAM for the interface identified
 * by ifname. When this function returns BP_FAILURE, a default mac address
 * was used because the NVRAM could not be read. BP_NO_RESOURCES is 
 * returned when memory could not be allocated to read the NVRAM. In this 
 * case, the buffer pointed to by mac_addrp has not been filled with
 * a default mac address.     
 *
 * @external
 * @category Board_Params
 * @since 7.0
 *
 * @param ifname    nul-terminated interface name string in the "eth0"/"wln0" format.
 * @param mac_addrp	Pointer to the MAC address buffer, filled in by this function,
 *                  at least 6 bytes in length. 
 *
 * @return BP_SUCCESS           Success
 * @return BP_FAILURE           Unable to read NVRAM; a default value was used instead.
 * @return BP_NO_RESOURCES      Unable to allocate memory; a default value was not used.
 * @return BP_INVALID_ARGUMENT  Invalid argument(s)
*ad*/
int customizeGetInterfaceMACAddress(const char * ifname, BYTE * mac_addrp)
{
    devBoardParamsType *params;
    int result = BP_INVALID_ARGUMENT; /* Assume invalid ifname.*/

    NA_ASSERT((mac_addrp != NULL) && (ifname != NULL));

    if ((mac_addrp == NULL) || (ifname == NULL))
    {
        goto exit;
    }

	params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
	if (params == NULL)
	{
        result = BP_NO_RESOURCES;
		goto exit;
	}

    /* Read params in NVRAM*/
    result = customizeReadDevBoardParams (params);

    if ((strcmp(ifname, BP_ETH_INTERFACE) == 0) ||
        (strcmp(ifname, BP_ETH_0INTERFACE) == 0))
    {
        memcpy (mac_addrp, params->ethernetMac, sizeof params->ethernetMac);
    }

    if ((strcmp(ifname, BP_WLN_INTERFACE) == 0) ||
        (strcmp(ifname, BP_WLN_0INTERFACE) == 0))
    {
        memcpy (mac_addrp, params->wlnParams.sta_addr,
                                         sizeof params->wlnParams.sta_addr);
    }

	bpFree(params);
    
exit:
    return result;
}

/*ad*
 * retrieves the serial number stored in a NET+ARM development board's NVRAM. 
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param srln      Destination for stored serial number. This array must be a minimum of 10 bytes.
*ad*/

void customizeGetSerialNumber(char * srln)
{
    devBoardParamsType *params;

    NA_ASSERT(srln != NULL);
    
    params = (devBoardParamsType *)bpMalloc(sizeof (devBoardParamsType));
    if (params == NULL)
        return;

    customizeReadDevBoardParams (params);             /* read params in NVRAM*/

/*
 * First two bytes of serial number don't count.  Yet...
 */
    memcpy (srln, params->serialNumber, sizeof params->serialNumber);
    bpFree (params);
}


/*ad*
 * re-writes the serial number of NET+ARM development board.
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param srln      Character pointer to the new serial number. The serial number must be composed
 *          of 9 alpha-numeric characters.
*ad*/
void customizeSaveSerialNumber(char * srln)
{
    devBoardParamsType *params;

    NA_ASSERT(srln != NULL);
    NA_ASSERT(strlen(srln) == BP_SERIAL_NUMBER_LENGTH);

    params = (devBoardParamsType *)bpMalloc(sizeof (devBoardParamsType));
    if (params == NULL)
        return;
    
    customizeReadDevBoardParams (params);             /* read params in NVRAM*/
    strcpy (params->serialNumber, srln);
    customizeWriteDevBoardParams (params);
    bpFree(params);
}



/*ad*
 * Set the Ethernet MAC address in NVRAM.
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param mac_addrp Pointer to destination of ethernet MAC address. This pointer must point to
 *          storage containing at least 6 bytes.
 *
 * @return 0        Success
 * @return -1       Unable to read NVRAM
*ad*/

int customizeSetMACAddress(BYTE * mac_addrp)
{
    devBoardParamsType *params;                  
    int result;

    NA_ASSERT(mac_addrp != NULL);

    params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
    if (params == NULL)
        return -1;

    result = customizeReadDevBoardParams (params);             /* read params in NVRAM*/

    if (result == BP_SUCCESS)
    {
        memcpy (params->ethernetMac, mac_addrp, sizeof params->ethernetMac);
        result = customizeWriteDevBoardParams (params);
    }
    
    bpFree(params);
    return result;
}



/*ad*
 * Convert hex digit into a byte.
 *
 * @category Board_Params 
 * @since 6.0
 *
 * @param hexDigit  pointer to 2 chars with hex value
 *
 * @return digit    binary value of hex string
*ad*/
static BYTE convertHexDigit(char hexDigit)
{
    BYTE returnValue = BAD_HEX_DIGIT;
    static char const table[]="0123456789ABCDEF";
    unsigned int idx;
    
    for (idx = 0; idx < strlen(table); idx++)
    {
        if (table[idx] == toupper(hexDigit))
        {
            returnValue = idx;
            break;
        }
    }
    
    return returnValue;
}


/*ad*
 * This routine converts an Ethernet MAC address string into
 * the equivalent binary value.  The address string can be
 * in one of two forms.  It can be the traditional set of
 * 6 2-hexdigit values seperated by colons, or
 * it can be a 6 hexdigit value which is the last 3 bytes of
 * the MAC address (the first 3 are the Digi MAC ID).
 *
 * @param dest      pointer to destination buffer to store 
 *                  MAC address to
 * @param source    pointer to source buffer with character
 *                  string MAC address.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @return BP_SUCCESS       converted string to MAC address
 * @return BP_FAILURE       string is not a valid MAC address
*ad*/
int NAConvertMacAddressString(BYTE * dest, char * source)
{
    int idx;
    BYTE hi, low;
    int result = BP_FAILURE;
    
    if (strlen(source) == SHORT_FORMAT_LENGTH)
    {
        /*
         * If length is 6 chars, then decode as short format.
         */
        memcpy(dest, digiMacPrefix, sizeof digiMacPrefix);
        for (idx = sizeof digiMacPrefix; idx < ETHERNET_ADDRESS_LENGTH; idx++)
        {
            hi = convertHexDigit(*source++);
            low = convertHexDigit(*source++);
            if ((hi == BAD_HEX_DIGIT) || (low == BAD_HEX_DIGIT))
            {
                goto done;
            }
            dest[idx] = (hi << 4) | low;
        }
        result = BP_SUCCESS;
    }
    else if (strlen(source) == LONG_FORMAT_LENGTH)
    {
        /*
         * If length is 17 chars, then decode as long format.
         */
        for (idx = 0; idx < ETHERNET_ADDRESS_LENGTH; idx++)
        {
            hi = convertHexDigit(*source++);
            low = convertHexDigit(*source++);
            if ((hi == BAD_HEX_DIGIT) || (low == BAD_HEX_DIGIT))
            {
                goto done;
            }
            dest[idx] = (hi << 4) | low;
            if ((idx < (ETHERNET_ADDRESS_LENGTH - 1)) && (*source != ':'))
            {
                goto done;
            }
            source++;
         }
         result = BP_SUCCESS;
    }

    done:
    return result;
}


/*ad*
 * This routine returns the default Ethernet MAC address.  If APP_USE_NVRAM is
 * set to APP_DO_NOT_USE_NVRAM, or if there is a checksum error reading NVRAM,
 * the value of APP_BSP_MAC_ADDRESS in appconf.h is used.  If
 * APP_BSP_MAC_ADDRESS is not set, then a default value of the DIGI Ethernet
 * MAC prefix and all zeros is used.  
 *
 * If APP_USE_NVRAM is not set to APP_DO_NOT_USE_NVRAM and there is not a 
 * checksum error reading NVRAM, then this routine returns the MAC address
 * stored in NVRAM.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @return Ethernet MAC address
*ad*/
static BYTE * getDefaultMacAddress(void)
{
    static BYTE returnValue[ETHERNET_ADDRESS_LENGTH];
    
    char *value= NAGetAppBspMacAddress();
        
    if (nvramChecksumError == FALSE)
    {
        if (NAGetAppUseNvram() != APP_DO_NOT_USE_NVRAM)
        {
            int ccode;
            WORD32 offset = BSP_START_OF_DEV_BOARD_PARAMETERS;
        
            offset += OFFSETOF(devBoardParamsType, ethernetMac);
            ccode = NANVRead (offset, (char *) returnValue, sizeof (returnValue));
            if (ccode == 0)
            {
                goto done;
            }
        }
    }
    
    memset (returnValue, 0, ETHERNET_ADDRESS_LENGTH);
    memcpy (returnValue, digiMacPrefix, sizeof digiMacPrefix);
    if (value != NULL)
    {
        NAConvertMacAddressString(returnValue, value);
    }
done:
    return returnValue;
}

/*ad*
 * This routine returns the default wireless MAC address.  If APP_USE_NVRAM is set to
 * APP_DO_NOT_USE_NVRAM, or there is a checksum error reading NVRAM then;
 *
 * <list type="unordered">
 *  <item>If this unit has both an Ethernet and a wireless interface, then the value
 *        of APP_2ND_INTERFACE_MAC_ADDRESS set in appconf.h is returned.</item>
 *  <item>If this unit does not have an Ethernet interface, just one wireless interface,
 *        Then the value of APP_BSP_MAC_ADDRESS set in appconf.h is used.</item>
 * </list>
 *
 * If APP_2ND_INTERFACE_MAC_ADDRESS or APP_BSP_MAC_ADDRESS is undefined, then a default
 * value of the DIGI Ethernet MAC prefix and all zeros is used.  
 *
 * If APP_USE_NVRAM is not set to APP_DO_NOT_USE_NVRAM and there is not a 
 * checksum error reading NVRAM, then this routine returns the MAC address
 * stored in NVRAM.
 *
 * @category Board_Params  
 * @since 6.0
 *
 * @return Wireless MAC address
*ad*/
static BYTE * getDefaultWlnMacAddress(void)
{
    static BYTE returnValue[ETHERNET_ADDRESS_LENGTH];
    
#if	BSP_WANT_ETHERNET
    char *value= NAGetApp2ndInterfaceMacAddress();
#else
    char *value= NAGetAppBspMacAddress();
#endif

    if (nvramChecksumError == FALSE)
    {
        if (NAGetAppUseNvram() != APP_DO_NOT_USE_NVRAM)
        {
            int ccode;
            WORD32 offset = BSP_START_OF_DEV_BOARD_PARAMETERS;
        
            offset += OFFSETOF(devBoardParamsType, wlnParams);
            offset += OFFSETOF(wln_params, sta_addr);
            ccode = NANVRead (offset, (char *) returnValue, sizeof (returnValue));
            if (ccode == 0)
            {
                goto done;
            }
        }
    }
    
    memset (returnValue, 0, ETHERNET_ADDRESS_LENGTH);
    memcpy (returnValue, digiMacPrefix, sizeof digiMacPrefix);
    if (value != NULL)
    {
        NAConvertMacAddressString(returnValue, value);
    }
done:
    return returnValue;
}

#define MAC_ADDRESS_SIZE        (6)

/*ad*
 * Changes the params with the setting in the appconf.h
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param params    Pointer to structure with development board parameters
 *
 * @return 0        Successfully changed to default setting
 * @return -1       Unable to read parameters
 *
 * @see @link devBoardParamsType
 *
 * @note    This code must be customized for your board should you decide not to use the
 *      setting in appconf.h. You may use the settings in structure defaultParams, or
 *      any other ways.
*ad*/

int customizeUseDefaultParams(devBoardParamsType * params)
{
    unsigned long app_ip_address_val=0;
    char    *valueStr;

    NA_ASSERT(params != NULL);
    if (params == NULL)
    {
        return -1;
    }
    
    /*  default the structure to zeros  */
    memset (params, 0, sizeof(devBoardParamsType));
    params->sizeOfRecord = sizeof *params;

    /* Get default network configuration*/
    customizeIamGetDefaultConfig(&params->iamParamsInfo);

#if BSP_WANT_WIRELESS
    /* Get default wireless network params*/
	memcpy (&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
    params->wlnCountryCode = NAGetAppWlnCountryCode();
#else
    /* Warning!! we need this signature to restore the wireless paramater when
       the interface is enabled */
    params->wlnCountryCode = PARAM_RESTORED_SIGNATURE;
#endif

    params->waitTime = NAGetAppBspDelay ();
    params->baudrate = NAGetAppBspBaudRate();
    params->defaultDuplexLevel = NAGetDefaultEthernetDuplex();
    
    /*
     * Serial number in appconf.h may be wrong length, or nonexistent.  Write default
     * serial number, then copy in the serial number from appconf.h.  Since the length
     * may be wrong, right justify it.
     */
    strcpy(params->serialNumber, DEFAULT_SERIAL_NUMBER);
    valueStr = NAGetAppBspSerialNum();
    if (valueStr)
    {
        if (strlen(valueStr) < BP_SERIAL_NUMBER_LENGTH)
        {
            strcpy(&params->serialNumber[BP_SERIAL_NUMBER_LENGTH - strlen(valueStr)], valueStr);
        }
    }

    memcpy(params->ethernetMac, getDefaultMacAddress(), sizeof(params->ethernetMac));
    memcpy(params->wlnParams.sta_addr, getDefaultWlnMacAddress(), 
           sizeof(params->wlnParams.sta_addr));        

    if (NAGetAppEnablePPP1 ())
    {
        /*  set the default ppp ip address  */
        valueStr = NAGetAppPPP1Address ();
        app_ip_address_val      = NAInet_addr (valueStr);
        params->ipAddrPpp1      = app_ip_address_val;

        /*  set the default ppp peer ip address  */
        valueStr = NAGetAppPPP1PeerAddress ();
        app_ip_address_val      = NAInet_addr (valueStr);
        params->ipAddrPpp1peer  = app_ip_address_val;
    }
    else
    {
        params->ipAddrPpp1      = app_ip_address_val;
        params->ipAddrPpp1peer  = 0;
    }

    if (NAGetAppEnablePPP2 ())
    {
        /*  set the default ppp ip address  */
        valueStr = NAGetAppPPP2Address ();
        app_ip_address_val      = NAInet_addr(valueStr);
        params->ipAddrPpp2      = app_ip_address_val;

        /*  set the default ppp peer ip address  */
        valueStr = NAGetAppPPP2PeerAddress ();
        app_ip_address_val      = NAInet_addr(valueStr);
        params->ipAddrPpp2peer  = app_ip_address_val;
    }
    else
    {
        params->ipAddrPpp2      = 0;
        params->ipAddrPpp2peer  = 0;
    }

    if (NAGetAppUseNetworkTimeProtocol ())
    {
        if ((valueStr = NAGetAppSntpPrimary ()) != NULL)
        {
            params->ipAddrSntp1 = (unsigned long)NAInet_addr (valueStr);
        }

        if ((valueStr = NAGetAppSntpSecondary ()) != NULL)
        {
            params->ipAddrSntp2 = (unsigned long)NAInet_addr (valueStr);
        }   
    }

    if ((valueStr = NAGetAppRootPassword ()) != NULL)
    {
        memcpy(params->rootPassword, valueStr, NASYSACC_STRLEN_PASSWORD);
            params->rootPassword[NASYSACC_STRLEN_PASSWORD - 1] = 0;
    }

    if ((valueStr = NAGetAppAdministratorsAccount ()) != NULL)
    {
        memcpy(params->adminPassword, valueStr, NASYSACC_STRLEN_PASSWORD);
            params->adminPassword[NASYSACC_STRLEN_PASSWORD - 1] = 0;
    }

    /* USA - Standard Eastern Time Zone */
    params->timezone.sync_time          = DEFAULT_SNTP_SYNC_TIME;
    params->timezone.std_zone_offset    = DEFAULT_STANDARD_TIMEZONE;
    params->timezone.dst_zone_offset    = DEFAULT_DAYLIGHT_TIMEZONE;
    strcpy(params->timezone.dst_start_rule, DEFAULT_START_DAYLIGHT_RULE);
    strcpy(params->timezone.dst_end_rule, DEFAULT_END_DAYLIGHT_RULE);
    return (0);
}


/*ad*
 * Determine if the parameter buffer passed to us looks like a valid set
 * of old style parameters.  Check the checksum, serial number, and
 * baud rate.
 *
 * @category Board_Params 
 * @since 6.0
 *
 * @param params    pointer to buffer with data that may be in 5.00 format.
 *
 * @return TRUE     record appears to be valid NET+OS 5.00 parameters
 * @return FALSE    record is invalid
*ad*/
static BOOLEAN isValidOldStyleParams(devBoardParams500Type * const params)
{
    BOOLEAN isValid = FALSE;
    unsigned int idx;
    
    if (compute500Checksum(params) == params->checksum) 
    {
        switch (params->baudrate)
        {
            case SIO_2400_BAUD:   
            case SIO_4800_BAUD:   
            case SIO_7200_BAUD:   
            case SIO_9600_BAUD:   
            case SIO_14400_BAUD:  
            case SIO_19200_BAUD:  
            case SIO_28800_BAUD:  
            case SIO_38400_BAUD:  
            case SIO_57600_BAUD:  
            case SIO_115200_BAUD: 
            case SIO_230400_BAUD: 
                isValid = TRUE;
                for (idx = 0; idx < sizeof(params->serialNumber); idx++)
                {
                    if (isdigit(params->serialNumber[idx]) == FALSE)
                    {
                        isValid = FALSE;
                        break;
                    }
                }
                break;
            default:
                break;
        }
        
    }
    
    return isValid;
}
    
#if BSP_WANT_WIRELESS
/*
 * Wireless paramater structure is changed after 6.3 release. This function
 * targets the migration from 6.3 release and pre 6.3 versions.
 */
static void convertWlnDataFrom60(wln_params *wlnParam)
{
    wln_params_60 *wln_60; 
    
    wln_60 = (wln_params_60 *)bpMalloc(sizeof(wln_params_60));
    if (wln_60 != NULL)
    {
        memcpy(wln_60, wlnParam, sizeof(wln_params_60));

        /* copy security to authen */
        if ((wln_60->security != WLN_AUTH_ANY) && (wln_60->security != WLN_AUTH_OPEN))
            wlnParam->authen = wln_60->security << 1;
        
        /* copy wpa_encrypt to encrypt */
        if (wln_60->wpa_encrypt != WLN_ENCR_ANY)
            wlnParam->encrypt = wln_60->wpa_encrypt << 1;

        /* copy auth_methods to eap_methods */
        if (wln_60->auth_methods != WLN_EAP_ANY)
            wlnParam->eap_methods = WLN_EAP_MSCHAPV2;

        /* copy other unmapped fields */
        wlnParam->wep_key_id  = wln_60->wep_key_id;
        wlnParam->wep_key_len = wln_60->wep_key_len;
        memcpy(wlnParam->wep_key, wln_60->wep_key, sizeof wlnParam->wep_key);
        if (wln_60->chan_mask > 0)
            wlnParam->chan_mask = WLN_CHANMASK_ALL;
                            
        bpFree(wln_60);
    }    
}
#endif /* BSP_WANT_WIRELESS */

/* converting from 6.3? */
static int convertFrom63Params(devBoardParamsType * params)
{
    int ret = BP_FAILURE;
    devBoardParams63Type *params63 = (devBoardParams63Type *)params;
    unsigned long recSize = params63->sizeOfRecord;
    devBoardParamsType *new_params;
    char *ptr, *optionsBuffer;
    unsigned long addr, lease;
    int i, j = 0, len;
    char options_count;


    if((recSize == sizeof *params63) || (compute63Checksum(params63) == params63->checksum))
    {
        new_params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));

        if (new_params == NULL)
        {
            return BP_FAILURE;
        }

        /* Frist move the non-ACE members. */
        strcpy(new_params->serialNumber, params63->serialNumber);

        /* The last sizeof(int) accounts for wln_params having been
         * expanded by a new member, tx_power, of type int. */ 
        len = offsetof(devBoardParamsType, iamParamsInfo) - offsetof(devBoardParamsType, waitTime) - sizeof(int);
        memcpy(&new_params->waitTime, &params63->waitTime, len);

        new_params->iamParamsInfo.version = NA_IAM_CONFIG_VERSION;

        /* ACE -> IAM. */
        for (i = 0; i < NA_IAM_INTERFACE_MAX; i++)
        {
            strcpy(new_params->iamParamsInfo.iamParams[i].ifname, 
                   params63->aceConfig.ace_interface_info[i].ifname);

            new_params->iamParamsInfo.iamParams[i].isEnabled = 
            params63->aceConfig.ace_interface_info[i].isEnabled;

            new_params->iamParamsInfo.iamParams[i].isConfigValid = 
            params63->aceConfig.ace_interface_info[i].isConfigValid;

            /* STATIC */
            new_params->iamParamsInfo.iamParams[i].staticParams.isEnabled = 
            params63->aceConfig.ace_interface_info[i].static_config.isEnabled;
            new_params->iamParamsInfo.iamParams[i].staticParams.IPV4_ADDR(ipAddress) = 
            params63->aceConfig.ace_interface_info[i].static_config.ip_address;
            new_params->iamParamsInfo.iamParams[i].staticParams.subnetMask =
            params63->aceConfig.ace_interface_info[i].static_config.subnet_mask;
            new_params->iamParamsInfo.iamParams[i].staticParams.IPV4_ADDR(gateway) =
            params63->aceConfig.ace_interface_info[i].static_config.gateway;
            new_params->iamParamsInfo.iamParams[i].staticParams.IPV4_ADDR(primaryDns) = 
            params63->aceConfig.ace_interface_info[i].static_config.name_server_address[0];
            new_params->iamParamsInfo.iamParams[i].staticParams.IPV4_ADDR(secondaryDns) =
            params63->aceConfig.ace_interface_info[i].static_config.name_server_address[1];
 
            /* DHCP */
            new_params->iamParamsInfo.iamParams[i].dhcpParams.isEnabled = 
            params63->aceConfig.ace_interface_info[i].dhcp_config.isEnabled; 

            ptr = optionsBuffer = new_params->iamParamsInfo.iamParams[i].dhcpParams.optionsBuffer;
            memset(ptr, 0, NA_IAM_DHCP_OPTIONS_BUFFER_LEN);

            /* We have to create a DHCP options buffer from scratch in IAM. */
            if ((addr = params63->aceConfig.ace_interface_info[i].dhcp_config.suggested_ip_address) != 0)
            {
                *ptr++ = DHCP_REQUESTED_IP_ADDR;
                *ptr++ = sizeof addr; 
                for (j = 0; j < (int)sizeof addr; j++)
                {
                    *ptr++ = ((char *)&addr)[j];
                } 
            }

            if ((lease = params63->aceConfig.ace_interface_info[i].dhcp_config.suggested_lease_time) != 0)
            {
                *ptr++ = DHCP_IP_ADDR_LEASE_TIME;
                *ptr++ = sizeof lease;
                for (j = 0; j < (int)sizeof lease; j++)
                {
                    *ptr++ = ((char *)&lease)[j];
                } 
            }

            *ptr++ = DHCP_PARAM_REQUEST;
            /* Make sure that we get the number of options correct. */
            if ((params63->aceConfig.ace_interface_info[i].dhcp_config.num_desired_params) >
                (NA_IAM_DHCP_OPTIONS_BUFFER_LEN - (int)(ptr - optionsBuffer) + 1))
            {
                options_count = NA_IAM_DHCP_OPTIONS_BUFFER_LEN - (int)(ptr - optionsBuffer) + 1;
            }
            else
            {
                options_count = params63->aceConfig.ace_interface_info[i].dhcp_config.num_desired_params;
            }

            *ptr++ = options_count;

            /* Copy the old options list. */ 
            memcpy(ptr, 
                   params63->aceConfig.ace_interface_info[i].dhcp_config.desired_params,
                   options_count); 

            ptr += options_count;

            /* Save the length of the buffer. */
            new_params->iamParamsInfo.iamParams[i].dhcpParams.optionsLength = (int)(ptr - optionsBuffer);                

            /* AUTOIP */
            new_params->iamParamsInfo.iamParams[i].autoipParams.isEnabled = 
            params63->aceConfig.ace_interface_info[i].autoip_config.isEnabled;   
        }

#if BSP_WANT_WIRELESS
        /* we had only one physical interface in all pre 7.0 dev boards */
        memcpy(new_params->wlnParams.sta_addr, params63->ethernetMac, sizeof(mac_addr));
        new_params->wlnParams.tx_power = WLN_TXPOWER_DEFAULT;
        /* handle data structure change condition b/w 7.0 and 6.3 release */
        {
            wln_params_60 *wln_60 = (wln_params_60 *)&new_params->wlnParams;

            if ((wln_60->wpa_encrypt == WLN_ENCR_ANY) || 
                (wln_60->wpa_encrypt == WLN_ENCR_OPEN)||
                (wln_60->wpa_encrypt == WLN_ENCR_WEP) || 
                (wln_60->wpa_encrypt == WLN_ENCR_TKIP))
            {
                /* most probably (of probability 1-(1/(2^30))) it original 6.3 style structure */
                convertWlnDataFrom60(&new_params->wlnParams);
            }
        }
#endif
        memcpy(params, new_params, sizeof *params);

        bpFree(new_params);
        ret = BP_SUCCESS; 
    }

    return ret;
}

#ifdef FOR_DIGI_MANUFACTURING
typedef struct
{
    unsigned char id[4];
    unsigned int version;
    unsigned int length;
    unsigned int checksum;
    unsigned char mac_address[6];
    unsigned char pad[2];
} devMfgBoardParamsType;

/**
 * Try to convert data stored at manufacturing time to boardparams.
 *
 * @category Board_Params
 * @since 6.0
 *
 * @param params    pointer to buffer with data that may be from manufacturing
 *
 * @return BP_FAILURE   Buffer pointed to by params is not in the manufacturing format.
 * @return BP_SUCCESS   Buffer has been converted.
 */
static int convertFromMfgParams(devBoardParamsType * params)
{
    devMfgBoardParamsType *mfg_params = NULL;
    unsigned int checksum, params_len;
    int errval = BP_FAILURE;
    char params_array[4];

    mfg_params = (devMfgBoardParamsType *)
                  bpMalloc(sizeof(devMfgBoardParamsType));

    if (mfg_params == NULL)
    {
        goto EXIT;
    }

    memcpy(mfg_params, params, sizeof(devMfgBoardParamsType));

    BE16cpy(params_array, mfg_params->id, 4);

    /* Verify ID */
    if ((params_array[0] != 'N') ||
        (params_array[1] != 'M') ||
        (params_array[2] != 'F') ||
        (params_array[3] != 'G'))
    {
        goto EXIT;
    }

    /* Verify length */
    params_len = FROM_BE32(mfg_params->length);

    if (params_len != sizeof(devMfgBoardParamsType))
    {
        goto EXIT;
    }
    /* Verify checksum */
#ifndef DOTNETMF /* Checksum doesn't work for .NET */
    checksum = blCrc32(0, mfg_params, offsetof(devMfgBoardParamsType, checksum));
    checksum = blCrc32(checksum, 
                      ((unsigned char *)&(mfg_params->checksum)) + 
                       sizeof(mfg_params->checksum), 
                       sizeof(devMfgBoardParamsType) - 
                       offsetof(devMfgBoardParamsType, checksum) - 
                       sizeof(mfg_params->checksum));

    if (checksum != mfg_params->checksum)
    {
        goto EXIT;
    }
#endif

    /* Set to defaults */
    customizeUseDefaultParams(params);

    /* Copy in mfg parameters */

    /* If we are little endian we need to swap the MAC address */
    BE16cpy(params->ethernetMac, mfg_params->mac_address, 6);

#if (BSP_WANT_WIRELESS && BSP_WANT_ETHERNET)
    BE16cpy(params->ethernetMac, mfg_params->mac_address, 6);
    mfg_params->mac_address[5] += 1;
    BE16cpy(params->wlnParams.sta_addr, mfg_params->mac_address, 6);
#elif BSP_WANT_WIRELESS
    BE16cpy(params->wlnParams.sta_addr, mfg_params->mac_address, 6);
#else
    BE16cpy(params->ethernetMac, mfg_params->mac_address, 6);
#endif

    /* Calculate params checksum */
    params->checksum = computeChecksum (params);

    errval = BP_SUCCESS;

EXIT:

    if (mfg_params != NULL)
    {
        bpFree(mfg_params);
    }

    return errval;
}
#endif /* FOR_DIGI_MANUFACTURING */


static int convertFrom500Params(devBoardParamsType * paramsNew)
{
    devBoardParams500Type *oldStyle;
    devBoardParams63Type *params = (devBoardParams63Type *)paramsNew;
    int returnValue = BP_FAILURE;
    
    oldStyle = (devBoardParams500Type *)bpMalloc(sizeof(devBoardParams500Type));
    if (oldStyle == NULL)
        return BP_FAILURE;

    memcpy (oldStyle, params, sizeof(devBoardParams500Type));
    
    if (isValidOldStyleParams(oldStyle))
    {
        params->serialNumber[0] = BP_OLDSTYLE_PREFIX;
        memcpy (&params->serialNumber[1], oldStyle->serialNumber, sizeof oldStyle->serialNumber);
        params->serialNumber[BP_SERIAL_NUMBER_LENGTH] = 0;
        params->aceConfig.ace_interface_info[0].static_config.isEnabled = !oldStyle->useDhcp;
        params->aceConfig.ace_interface_info[0].static_config.isConfigValid = TRUE;
        params->aceConfig.ace_interface_info[0].static_config.ip_address = oldStyle->ipAddress;
        params->aceConfig.ace_interface_info[0].static_config.subnet_mask = oldStyle->subnetMask;
        params->aceConfig.ace_interface_info[0].static_config.gateway = oldStyle->gateway;
        params->aceConfig.ace_interface_info[0].static_config.auto_assign = !oldStyle->useDhcp;
        params->aceConfig.ace_interface_info[0].dhcp_config.isEnabled = oldStyle->useDhcp;
        params->waitTime = oldStyle->waitTime;                            
        params->baudrate = oldStyle->baudrate;                            
        params->telnetMagic = oldStyle->telnetMagic;                        
        params->ipAddrPpp1 = oldStyle->ipAddrPpp1;                           
        params->ipAddrPpp2 = oldStyle->ipAddrPpp2;                           
        params->ipAddrPpp1peer = oldStyle->ipAddrPpp1peer;                       
        params->ipAddrPpp2peer = oldStyle->ipAddrPpp2peer;                       
        memcpy(params->rootPassword, oldStyle->rootPassword, sizeof params->rootPassword);        
        memcpy(params->adminPassword, oldStyle->adminPassword, sizeof params->adminPassword);       
        memcpy(params->FixedKey, oldStyle->FixedKey, sizeof params->FixedKey);                                   
        memcpy (params->resvfieldone, oldStyle->resvfieldone, sizeof params->resvfieldone);
        memcpy (params->resvfieldtwo, oldStyle->resvfieldtwo, sizeof params->resvfieldtwo);
        params->resvfieldthree = oldStyle->resvfieldthree;
        memcpy (params->resvfieldfour, oldStyle->resvfieldfour, sizeof params->resvfieldfour);
        params->ipAddrSntp1 = oldStyle->ipAddrSntp1;                         
        params->ipAddrSntp2 = oldStyle->ipAddrSntp2;
        convertSerialNumberToMacAddress(params->ethernetMac, params->serialNumber);
        params->defaultDuplexLevel = NAGetDefaultEthernetDuplex();
        
#if BSP_WANT_WIRELESS
        memcpy(&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
#endif
        params->snmpEngineBoots = defaultParams.snmpEngineBoots;
        memset((void *)&params->aceConfig.ace_interface_info[1], 0, sizeof(aceConfigInterfaceInfo));
        memset((void *)&params->aceConfig.ace_interface_info[2], 0, sizeof(aceConfigInterfaceInfo));
        memset((void *)&params->aceConfig.ace_interface_info[3], 0, sizeof(aceConfigInterfaceInfo));
        params->checksum = compute63Checksum(params);
        convertFrom63Params(paramsNew);
        returnValue = BP_SUCCESS;
    }
    
    bpFree(oldStyle);
    return returnValue;
}

/* calculates the CRC for the specified size of board param data
   assuming initial fields upto ipAddrPpp1 are same as in new data */
static unsigned long isValidOlderVersionParams(devBoardParamsType * params, unsigned long size)
{
    WORD32 accumulator = blCrc32(0, params, offsetof(devBoardParamsType, checksum));
    
    return (blCrc32(accumulator, ((unsigned char *)&(params->checksum)) + sizeof(params->checksum),
        size - offsetof(devBoardParamsType, checksum) - sizeof(params->checksum)));
}

/* converting from 6.0? */
static int convertFrom60Params(devBoardParamsType * paramsNew)
{
    int ret = BP_FAILURE;
    devBoardParams63Type *params = (devBoardParams63Type *)paramsNew;
    devBoardParams60Type *params60 = (devBoardParams60Type *)paramsNew;
    WORD32 accumulator;
    unsigned int len;
    unsigned long chksum;

    /* checksum ok? */
    len = (sizeof *params60) - offsetof(devBoardParams60Type, checksum) - sizeof(params60->checksum);
    accumulator = blCrc32(0, params60, offsetof(devBoardParams60Type, checksum));
    chksum = blCrc32(accumulator, ((unsigned char *)&(params60->checksum)) + sizeof(params60->checksum), len);

    if (params60->checksum == chksum)
    {
        len = offsetof(devBoardParams60Type, wlnParams) - offsetof(devBoardParams60Type, waitTime);
        if (len < sizeof *params60) /* field position changed? */
        {
            memmove(&params->waitTime, &params60->waitTime, len);  
            memmove(&params->wlnParams, &params60->wlnParams, sizeof params->wlnParams);
            params->snmpEngineBoots = defaultParams.snmpEngineBoots;
            memset((void *)&params->aceConfig.ace_interface_info[2], 0, sizeof(aceConfigInterfaceInfo));
            memset((void *)&params->aceConfig.ace_interface_info[3], 0, sizeof(aceConfigInterfaceInfo));
            params->checksum = compute63Checksum(params);
            convertFrom63Params(paramsNew);
            ret = BP_SUCCESS;
        }
    }

    return ret;    
}

/* converting from 6.1? */
static int convertFrom61Params(devBoardParamsType * paramsNew)
{
    int ret = BP_FAILURE;
    devBoardParams63Type *params = (devBoardParams63Type *)paramsNew;
    devBoardParams61Type *params61 = (devBoardParams61Type *)paramsNew;
    WORD32 accumulator;
    unsigned int len;
    unsigned long chksum;
    
    /* checksum ok? */
    len = (sizeof *params61) - offsetof(devBoardParams61Type, checksum) - sizeof(params61->checksum);
    accumulator = blCrc32(0, params61, offsetof(devBoardParams61Type, checksum));
    chksum = blCrc32(accumulator, ((unsigned char *)&(params61->checksum)) + sizeof(params61->checksum), len);

    if (params61->checksum == chksum)
    {
        len = (sizeof *params61) - offsetof(devBoardParams61Type, waitTime);
        if (len < sizeof *params61) /* field position changed? */
        {
            memmove(&params->waitTime, &params61->waitTime, len);  
#if BSP_WANT_WIRELESS
            memcpy(&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
#endif
            params->snmpEngineBoots = defaultParams.snmpEngineBoots;
            memset((void *)&params->aceConfig.ace_interface_info[2], 0, sizeof(aceConfigInterfaceInfo));
            memset((void *)&params->aceConfig.ace_interface_info[3], 0, sizeof(aceConfigInterfaceInfo));
            params->checksum = compute63Checksum(params);
            convertFrom63Params(paramsNew);
            ret = BP_SUCCESS;
        }
    }

    return ret;    
}

/* converting from 6.2? */
static int convertFrom62Params(devBoardParamsType * paramsNew)
{
    int ret = BP_FAILURE;
    devBoardParams63Type *params = (devBoardParams63Type *)paramsNew;
    devBoardParams62Type *params62 = (devBoardParams62Type *)paramsNew;
    unsigned long recSize = params62->sizeOfRecord;
    WORD32 accumulator;
    unsigned int len;
    unsigned long chksum;
    
    /* checksum ok? */
    if ((recSize <= sizeof *params62) && (recSize > offsetof(devBoardParams62Type, snmpEngineBoots)))
    {
        len = recSize - offsetof(devBoardParams62Type, checksum) - sizeof(params62->checksum);
        accumulator = blCrc32(0, params62, offsetof(devBoardParams62Type, checksum));
        chksum = blCrc32(accumulator, ((unsigned char *)&(params62->checksum)) + sizeof(params62->checksum), len);

        if (params62->checksum == chksum)
        {
            len = recSize - offsetof(devBoardParams62Type, waitTime);
            if (len < recSize) /* field position changed? */
            {
                memmove(&params->waitTime, &params62->waitTime, len);
#if BSP_WANT_WIRELESS
                params->wlnParams.band = DEFAULT_WLN_BAND;
#endif
                memset((void *)&params->aceConfig.ace_interface_info[2], 0, sizeof(aceConfigInterfaceInfo));
                memset((void *)&params->aceConfig.ace_interface_info[3], 0, sizeof(aceConfigInterfaceInfo));
                params->checksum = compute63Checksum(params);
                convertFrom63Params(paramsNew);
                ret = BP_SUCCESS;
            }
        }
    }
    else /* initail version of 6.2? */
    {
        len = offsetof(devBoardParams62Type, wlnParams)  - offsetof(devBoardParams62Type, checksum) - sizeof(params62->checksum);
        accumulator = blCrc32(0, params62, offsetof(devBoardParams62Type, checksum));
        chksum = blCrc32(accumulator, ((unsigned char *)&(params62->checksum)) + sizeof(params62->checksum), len);

        if (params62->checksum == chksum)
        {
            len = offsetof(devBoardParams62Type, wlnParams) - offsetof(devBoardParams62Type, waitTime);
            if (len < sizeof *params62) /* field position changed? */
            {
                memmove(&params->waitTime, &params62->waitTime, len);  
#if BSP_WANT_WIRELESS
                memcpy(&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
#endif
                memset((void *)&params->aceConfig.ace_interface_info[2], 0, sizeof(aceConfigInterfaceInfo));
                memset((void *)&params->aceConfig.ace_interface_info[3], 0, sizeof(aceConfigInterfaceInfo));
                params->checksum = compute63Checksum(params);
                convertFrom63Params(paramsNew);
                ret = BP_SUCCESS;
            }
        }
    }

    return ret;    
}

/* function first tries to use the record size to calculate the checksum, if
   it fails then it tries to use old record size to calulate the checksum. 
   This is required because in older versions we didn't update the record
   size correctly */
int convertFromOlderVersionParams(devBoardParamsType * params)
{
    int retVal = BP_FAILURE;
    unsigned long recSize = params->sizeOfRecord;
 
    if ((recSize <= sizeof *params) && (recSize >= offsetof(devBoardParamsType, snmpEngineBoots)))
    {
        if (params->checksum == isValidOlderVersionParams(params, recSize))
        {
            retVal = BP_SUCCESS;
            if (recSize < sizeof defaultParams)
            {
                memcpy ((BYTE *)params+recSize, (BYTE *)(&defaultParams)+recSize, sizeof defaultParams - recSize);
            }
            goto done_old_params;
        }
    }

    /* Check if it is from NET+OS 6.3 */
    if ((retVal = convertFrom63Params(params)) == BP_SUCCESS)
        goto done_old_params;
  
    /* Check if it is from NET+OS 6.2 */
    if ((retVal = convertFrom62Params(params)) == BP_SUCCESS)
        goto done_old_params; 

    /* Check if it is from NET+OS 6.1 */
    if ((retVal = convertFrom61Params(params)) == BP_SUCCESS)
        goto done_old_params;

    /* Check if it is from NET+OS 6.0 */
    if ((retVal = convertFrom60Params(params)) == BP_SUCCESS)
        goto done_old_params;

    /* finally check if it is 5.0 */    
    if ((retVal = convertFrom500Params(params)) == BP_SUCCESS)
        goto done_old_params;

#ifdef FOR_DIGI_MANUFACTURING
    if ((retVal = convertFromMfgParams(params)) == BP_SUCCESS)
        goto done_old_params;
#endif

    /* couldn't recover from older version */

    customizeUseDefaultParams(params);

done_old_params:
     
    return retVal;
}

/*
 * Function returns 0 if MAC address is not reset to zero otherwise it 
 * returns 1 after updating the MAC address with default value.
 *
 * Function also checks whether unit is factory defaulted when wireless
 * interface was disabled. We can identify this state by checking the
 * country code value for the special signature. 
 *
 * Note: value of more than 64k is invalid value for country code. So
 * we can safely use this field to identify above special scenario.
 */
static int checkForInvalidData(devBoardParamsType * params)
{
    int ret = 0;
#if	(BSP_WANT_ETHERNET || BSP_WANT_WIRELESS)
    unsigned char zero_mac_addr[MAC_ADDRESS_SIZE] = {0,0,0,0,0,0};
#endif

#if	BSP_WANT_ETHERNET
    if (!memcmp(params->ethernetMac, zero_mac_addr, MAC_ADDRESS_SIZE))
    {
        nvramChecksumError = TRUE;
        memcpy(params->ethernetMac, getDefaultMacAddress(), 
                sizeof(params->ethernetMac));

        ret = 1;
    }
#endif

#if BSP_WANT_WIRELESS
    if (!memcmp(params->wlnParams.sta_addr, zero_mac_addr, MAC_ADDRESS_SIZE)
        || (params->wlnCountryCode == PARAM_RESTORED_SIGNATURE))
    {
        if (!memcmp(params->wlnParams.sta_addr, zero_mac_addr, MAC_ADDRESS_SIZE))
            nvramChecksumError = TRUE;
        else
            nvramChecksumError = FALSE;

        memcpy(&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
        memcpy(params->wlnParams.sta_addr, getDefaultWlnMacAddress(), 
                 sizeof(params->wlnParams.sta_addr));
        params->wlnCountryCode = NAGetAppWlnCountryCode();

        ret = 1;
    }
#endif
#if (BSP_WANT_WIRELESS == FALSE) && (BSP_WANT_ETHERNET == FALSE)
    NA_UNUSED_PARAM(params);
#endif

    return ret;
}

/*ad*
 * Reads the contents of the section of NVRAM that contains the development board's startup parameters.
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param params    Pointer to structure with development board parameters
 *
 * @return 0        Successfully read.
 * @return -1       Unable to read parameters
 *
 * @see @link devBoardParamsType
*ad*/
int customizeReadDevBoardParams(devBoardParamsType * params)
{
    int result = BP_FAILURE;
    int ccode;
#if (PLATFORM == connectcore7u_a)
    int i = 0x2000;
    unsigned char *buffer, FSFORTH_mac_addr[MAC_ADDRESS_SIZE];
#endif

    NA_ASSERT(params != NULL);
    
    if (params == NULL)
    {
        goto done;
    }

    if (NAGetAppUseNvram() == APP_FOR_ALL_PARAMETERS) 
    {
        ccode = NANVRead (BSP_START_OF_DEV_BOARD_PARAMETERS, (char *) params, sizeof (devBoardParamsType));
    
        if (ccode == 0)
        {    
            if (computeChecksum(params) != params->checksum)
            {
                if (params->sizeOfRecord > sizeof *params)
                {
                    if (computeChecksumFromSize(params) == params->checksum)
                    {
                        customizeWriteDevBoardParams (params);
                        result = BP_SUCCESS;
                        goto done;
                    }
                }

                if (convertFromOlderVersionParams(params) == BP_SUCCESS)
                {
                    customizeWriteDevBoardParams (params);
                    result = BP_SUCCESS;
                    goto done;
                }
                nvramChecksumError = TRUE;
#if (PLATFORM == connectcore7u_a)
                /*  search for the NVRAM for the old FSFORTH MAC address    */
                buffer = (unsigned char *)bpMalloc(0x2000);
                if (buffer == NULL)
                    goto use_default;
    
                memset (buffer, 0, 0x2000);
                NANVRead (0, (char *)buffer, 0x2000);
                    
                for (i = 2; i <(0x2000 - 3); i++)
                {           
                    if((buffer[i] == 0x9d && buffer[i-1] == 0x40 && buffer[i-2] == 0x00) ||
                    (buffer[i] == 0xf3 && buffer[i-1] == 0x04 && buffer[i-2] == 0x00))
                    {
                        memcpy(FSFORTH_mac_addr, &buffer[i-2], MAC_ADDRESS_SIZE);
                        
                        bpFree(buffer);
                        goto use_default;
                    }
                }
                
                bpFree(buffer);
#endif       
            }
            else if (checkForInvalidData(params))
            {
                nvramChecksumError = FALSE;
                customizeWriteDevBoardParams (params);
                result = BP_SUCCESS;
                goto done;
            }
            else
            {
                result = BP_SUCCESS;
                goto done;
            }
        }
        else /* use default configuration if error reading NVRAM */
        {
            /*
             * We could just fall through to the code, but the compiler generates an error
             * if the label isn't used, and I want the label to provide a clue about that 
             * code is for.
             */
            goto use_default; 
        }
    }
    else
    {
        /*
         * This handles both APP_DO_NOT_USE_NVRAM and APP_FOR_MAC_ADDRESS_ONLY since
         * customizeUseDefaultParams() will use the MAC address from NVRAM if 
         * APP_FOR_MAC_ADDRESS_ONLY is specified.
         */
        result = BP_SUCCESS;
        /*
         * We could just fall through to the code, but the compiler generates an error
         * if the label isn't used, and I want the label to provide a clue about that 
         * code is for.
         */
        goto use_default; 
    }
    
    use_default:    
    customizeUseDefaultParams(&defaultParams);
#if (PLATFORM == connectcore7u_a)
    if (i < (0x2000 - 3))
    {
        /*  We're here because we found the old FSFORTH MAC address -- bring it into the NETOS world */
        memcpy(&defaultParams.ethernetMac, FSFORTH_mac_addr, sizeof params->ethernetMac);
    }
#endif
    memcpy (params, &defaultParams, sizeof (defaultParams));
    customizeWriteDevBoardParams (params);
    nvramChecksumError = FALSE;

    done:
    return result;
}




/*ad*
 * Writes development board parameters to NVRAM.
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param params    Pointer to structure with development board parameters
 *
 * @return 0        The development board paremters were successfully written.
 * @return -1       Unable to write to NVRAM
 *
 * @see @link devBoardParamsType
*ad*/
int customizeWriteDevBoardParams(devBoardParamsType * params)
{
    NA_ASSERT(params != NULL);
    
    if (params != NULL)
    {
        params->sizeOfRecord = sizeof *params;
        params->checksum = computeChecksum(params);

        if (NAGetAppUseNvram() != APP_DO_NOT_USE_NVRAM)  /* return the APP_USE_NVRAM value */
        {
            return NANVWrite (BSP_START_OF_DEV_BOARD_PARAMETERS, (char *) params, sizeof (devBoardParamsType));
        }
        else
            return 0;
    }

    return -1;
}


/*ad*
 * Retrieves the IP address values (address, subnet maske and
 * default gateway) from NVRAM. The caller is then able to make a determination
 * if a valid IP address has been retrieved and stored in NVRAM.
 *
 *
 * Zero values indicate that the addresses have not been initialized.
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param ipptr     Pointer to destination of the retrieved IP address.
 * @param subptr    Pointer to destination of the retrieved subnet mask.
 * @param defgwptr  Pointer to the destination of the retrieved default gateway.
*ad*/
void customizeGetIPParameters(unsigned long * ipptr, unsigned long * subptr, unsigned long * defgwptr)
{
    NaIamStaticParams_t config;

    NA_ASSERT(ipptr != NULL);
    NA_ASSERT(subptr != NULL);
    NA_ASSERT(defgwptr != NULL);
    memset( (void*) &config, 0, sizeof(config)); 
    
#if	BSP_WANT_ETHERNET
    customizeIamGetStaticConfig(BP_ETH_INTERFACE, &config);
#endif
#if BSP_WANT_WIRELESS
	memset( (void*) &config, 0, sizeof(config));
    customizeIamGetStaticConfig(BP_WLN_INTERFACE, &config);   
#endif   

    *ipptr = config.IPV4_ADDR(ipAddress);
    *subptr = config.subnetMask;
    *defgwptr = config.IPV4_ADDR(gateway);
}


/*ad*
 * Saves IP address parameters to NVRAM. 
 *
 * @external
 * @category Board_Params
 * @since 6.0
 *
 * @param ipaddr    IP address to save
 * @param submask   Subnet mask to save
 * @param defgw     Default gateway to save
*ad*/
void customizeSaveIPParameters(unsigned long ipaddr, unsigned long submask, unsigned long defgw)
{
    NaIamStaticParams_t config;

    NA_ASSERT(ipaddr > 0);
    NA_ASSERT(submask > 0);
    NA_ASSERT(defgw > 0);
    memset( (void*) &config, 0, sizeof(config)); 
    
#if BSP_WANT_ETHERNET
    customizeIamGetStaticConfig(BP_ETH_INTERFACE, &config);
#endif
#if BSP_WANT_WIRELESS
	memset( (void*) &config, 0, sizeof(config));
    customizeIamGetStaticConfig(BP_WLN_INTERFACE, &config);   
#endif
  

    config.IPV4_ADDR(ipAddress) = ipaddr;
    config.subnetMask = submask;
    config.IPV4_ADDR(gateway) = defgw;
    config.isEnabled = TRUE;

	/* write updated params*/
#if	BSP_WANT_ETHERNET
    customizeIamSetStaticConfig(BP_ETH_INTERFACE, &config);            /* write updated params*/
#endif
#if BSP_WANT_WIRELESS
    customizeIamSetStaticConfig(BP_WLN_INTERFACE, &config);   
#endif

}


void customizeSaveEnable(BOOLEAN mode)
{
   NaIamStaticParams_t static_config;
   NaIamDhcpParams_t   dhcp_config;

   customizeIamGetStaticConfig(BP_ETH_INTERFACE, &static_config);
   customizeIamGetDhcpConfig(BP_ETH_INTERFACE, &dhcp_config);

   static_config.isEnabled = !mode;
   dhcp_config.isEnabled = mode;

   customizeIamSetStaticConfig(BP_ETH_INTERFACE, &static_config);
   customizeIamSetDhcpConfig(BP_ETH_INTERFACE, &dhcp_config);
}

bpDuplexLevelType customizeGetEthernetDuplexMode(void)
{
    devBoardParamsType *params;
    bpDuplexLevelType  duplex =  NAGetDefaultEthernetDuplex();

    params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
    if (params)
    {
        customizeReadDevBoardParams (params);             /* read params in NVRAM*/
        duplex = params->defaultDuplexLevel;
        bpFree(params);
    }
  
    return duplex;
}

int customizeSetEthernetDuplexMode(bpDuplexLevelType duplex)
{
    devBoardParamsType *params;
 
    params = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));
    if (params == NULL)
        return -1;

    customizeReadDevBoardParams (params);             /* read params in NVRAM*/
    params->defaultDuplexLevel = duplex;
    customizeWriteDevBoardParams (params);
    bpFree(params);
  
    return duplex;
}

/* exported access to the computeChecksum function */

unsigned long computeBPChecksum(devBoardParamsType * params)
{
	return computeChecksum(params);
}

