/*
 *  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 "bsp_drivers.h"
#include "migration.h"

#define NAMI_SUPPORTED	(PLATFORM != connectcore9p9360_a && PLATFORM != connectcore7u_a)

#if NAMI_SUPPORTED
#include "nami.h"
#endif

#ifdef DOTNETMF
#define FOR_DIGI_MANUFACTURING
#include "bele.h"
char ethernetMac[6];
#endif


#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


#ifdef BSP_ARM9
#ifdef REDPINE
#define DEFAULT_WLN_BAND            (WLN_BAND_BGN)
#else
#define DEFAULT_WLN_BAND            (WLN_BAND_BG)
#endif
#else
#define DEFAULT_WLN_BAND            (WLN_BAND_B)
#endif

/* 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);
static int revertOlderVersionParams(devBoardParamsType * params);

static int update_idigi_params_crc(devBoardParamsType * nvParamsPtr);

#if NAMI_SUPPORTED
static int saveModuleInfo(devBoardParamsType * params);
#endif

/*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 @link 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 BSP:Board_Params
 * @since 6.0
 * @overview Development Board Parameters
 * @library bsp
 * @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 NaWlnParams_t *getDefaultWlnParams(void)
{
    static BOOLEAN firstTime = TRUE;
    unsigned long mask[2];
    static NaWlnParams_t 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 */
#if (PLATFORM == connectcorewi9c_a)
	10                 /* default tx_power is 10 on wi9c with UBEC chip */
#else
        WLN_TXPOWER_DEFAULT /* tx_power */
#endif
    };

    if (firstTime)
    {
        extern BOOLEAN isRF_AIROHA_7230(void);
                
        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);
        // update channel mask
        {            
            if (wln_get_channel_mask(NAGetAppWlnCountryCode(), mask) != 0)
            {
                /*
                * Default to US if country code was invalid.
                */
                if (wln_get_channel_mask(COUNTRY_UNITED_STATES, mask) != 0)
                {
                    //if US is not even supported
                    mask[0]=0;
                    mask[1]=0;
                }
            }
            
            defaultWlnParams.chan_mask = mask[0];
        }
        if (NAGetWln80211Band() == APP_WLN_80211_BAND_DEFAULT)
        {
            defaultWlnParams.band = DEFAULT_WLN_BAND;
#if (AIROHA_TRANSCEIVER == TRUE) 
            if (isRF_AIROHA_7230() == TRUE)
            {
                /*
                 * Include A bands for A capable radio.  Note that
                 * APP_WLN_80211_BAND_DEFAULT == APP_WLN_80211_BAND_ALL
                 */
                defaultWlnParams.band = APP_WLN_80211_BAND_ALL;
            }
#endif
        }
        else
        {
            defaultWlnParams.band = NAGetWln80211Band();
#if (AIROHA_TRANSCEIVER != TRUE) 
            if (defaultWlnParams.band == WLN_BAND_A)
            {
                /*
                 * 802.11a is only supported on platforms with the AIROHA_TRANSCEIVER.
                 * If this platform doesn't allow it and user has set 802.11a, then
                 * switch it to the default band.
                 */
                defaultWlnParams.band = DEFAULT_WLN_BAND;
            }
#else /* if an airoha transceiver*/
            {
                if ((isRF_AIROHA_7230() == FALSE) && (defaultWlnParams.band == WLN_BAND_A))
                {
                    /*
                     * Only the 7230 supports 802.11a.  If this is not it and band A
                     * is selected, then switch to the default band setting.
                     */
                    defaultWlnParams.band = DEFAULT_WLN_BAND;
                }
            }
#endif
#if !defined(BSP_ARM9) 
            /*
             * If this is an ARM7 platform, then it only supports 802.11b.
             */
            defaultWlnParams.band = WLN_BAND_B;
#endif
        }
        defaultWlnParams.channel = NAGetAppWlnChannel();
        if (defaultWlnParams.channel >= WLN_CHANNEL_A_INDEX_OFFSET)
        {
            /*
             * If an 802.11a channel.
             */
#if (AIROHA_TRANSCEIVER != TRUE) 
            /* 
             * and this hardware does not support 802.11a, then reset the channel to SCAN.
             */
            defaultWlnParams.channel = SCAN;
#endif
            if ((defaultWlnParams.band == WLN_BAND_B) || (defaultWlnParams.band == APP_WLN_80211_BAND_BG))
            {
                /*
                 * If an 802.11a channel, but the 802.11a band is not selected, then reset
                 * to SCAN.
                 */
                defaultWlnParams.channel = SCAN;
            }
        }
        else /* if not an 802.11a channel */
        {
            if (defaultWlnParams.band == WLN_BAND_A) 
            {
                /*
                 * but the 802.11a band was selected, then channel is invalid so reset it to SCAN.
                 */
                defaultWlnParams.channel = SCAN;
            }
        }
        if (defaultWlnParams.channel != SCAN)
        {
            /*
             * Now make sure the channel is valid in this country.
             */
            int channelNumber = naWlnGetChannelInfo(defaultWlnParams.channel, NULL);
            
            if (naWlnGetChannelIndex((uint32 *)mask/*&defaultWlnParams.chan_mask*/, channelNumber, (defaultWlnParams.channel >= WLN_CHANNEL_A_INDEX_OFFSET)) == -1)
            {
                /*
                 * If channel is not supported in this country.
                 */
                defaultWlnParams.channel = SCAN;
            }
        }
        if (NAGetWln80211Options() == APP_WLN_80211_OPTION_MULTI_DOMAIN)
        {
            defaultWlnParams.options = WLN_OPT_MULTI_DOMAIN;
        }
        else if (NAGetWln80211Options() == APP_WLN_80211_OPTION_SPECTRUM_MANAGEMENT)
        {
            defaultWlnParams.options = WLN_OPT_MULTI_DOMAIN | WLN_OPT_SPECTRUM_MGMT;
        }

        /* wireless power save mode */
        if (NAGetAppWlnPsMode() != WLN_PS_MODE_DISABLED)
        {
            defaultWlnParams.options |= WLN_OPT_PS_ENABLE;
            if (NAGetAppWlnPsMode() == WLN_PS_MODE_VERY_LOW_POWER)
                defaultWlnParams.options |= WLN_OPT_VERY_LOW_PWR;
        }
        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 BSP:Board_Params  
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @since 7.0
 * @external
 *
 * @param   psk     pointer to new wireless PSK
*ad*/
void customizeSetDefaultWlnPsk(unsigned char * psk)
{
    NaWlnParams_t *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 BSP:Board_Params  
 * @include <boardParams.h>
 * @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 @link NABoardParamsSetMalloc
 * to allocate a buffer.  Return NULL if @link NABoardParamsSetMalloc
 * has not been called.
 *
 * @category BSP:Board_Params  
 * @location src/bsp/customize/boardParams.c
 * @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 @link NABoardParamsSetMalloc
 * to allocate a buffer.  Return NULL if @link NABoardParamsSetMalloc
 * has not been called.
 *
 * @category BSP:Board_Params  
 * @location src/bsp/customize/boardParams.c
 * @since 6.0
 *
 * @param buffer        pointer to memory to free
*ad*/
static void bpFree(void * buffer)
{
    if (freeFn)
    {
        freeFn(buffer);
    }
} 


/*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 BSP:Board_Params  
 * @location src/bsp/customize/boardParams.c
 * @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)));
}

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

    
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;
}



/**
 * This function has been deprecated in NET+OS 7.0 and should be 
 * replaced with @link customizeGetInterfaceMACAddress. 
 *
 * @external
 * @category BSP:Board_Params
 * @location src/bsp/customize/boardParams.c
 * @include <boardParams.h>
 * @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 BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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 BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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 BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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 BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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 BSP:Board_Params 
 * @location src/bsp/customize/boardParams.c
 * @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 BSP:Board_Params  
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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 @link APP_USE_NVRAM is
 * set to APP_DO_NOT_USE_NVRAM, or if there is a checksum error reading NVRAM,
 * the value of @link APP_BSP_MAC_ADDRESS in appconf.h is used.  If
 * @link APP_BSP_MAC_ADDRESS is not set, then a default value of the DIGI Ethernet
 * MAC prefix and all zeros is used.  
 *
 * If @link 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 BSP:Board_Params  
 * @location src/bsp/customize/boardParams.c
 * @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 @link 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 @link 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 @link APP_BSP_MAC_ADDRESS set in appconf.h is used.</item>
 * </list>
 *
 * If @link APP_2ND_INTERFACE_MAC_ADDRESS or @link APP_BSP_MAC_ADDRESS is undefined, then a default
 * value of the DIGI Ethernet MAC prefix and all zeros is used.  
 *
 * If @link 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 BSP:Board_Params  
 * @location src/bsp/customize/boardParams.c
 * @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 WLN_POWER_CALIBRATION_LENGTH (64)
static unsigned long * getDefaultwlnPowerCalibration(void)
{
    static unsigned long returnValue[WLN_POWER_CALIBRATION_LENGTH]; 

    if (nvramChecksumError == FALSE)
    {
        if (NAGetAppUseNvram() != APP_DO_NOT_USE_NVRAM)
        {
            int ccode;
            WORD32 offset = BSP_START_OF_DEV_BOARD_PARAMETERS;
        
            offset += OFFSETOF(devBoardParamsType, wlnExtParams.wlnPowerCalibration);
            ccode = NANVRead (offset, (char *) returnValue, sizeof (returnValue));
            if (ccode == 0)
            {
                goto done;
            }
        }
    }
    
    memset (returnValue, 0, sizeof (returnValue));
done:
    return returnValue;
}

#define MAC_ADDRESS_SIZE        (6)

#define ETH_EX_PARAMS_IDX   0
#define WLN_EX_PARAMS_IDX   1

static int useDefaultIpv6Gateways(devBoardParamsType * nvParamsPtr)
{
    int result = BP_SUCCESS;

    if (nvParamsPtr == NULL)
    {
        result = BP_INVALID_ARGUMENT;
        goto done;
    }

    memset(&nvParamsPtr->iamExParams, 0, sizeof nvParamsPtr->iamExParams);

#if BSP_WANT_ETHERNET
    strcpy((char *) &nvParamsPtr->iamExParams.ifname[ETH_EX_PARAMS_IDX], BP_ETH_INTERFACE);
    nvParamsPtr->iamExParams.ipv6gateway[ETH_EX_PARAMS_IDX] = customizeIamGetDefaultIpv6GatewayConfig(BP_ETH_INTERFACE);
#endif

#if BSP_WANT_WIRELESS
    strcpy((char *) &nvParamsPtr->iamExParams.ifname[WLN_EX_PARAMS_IDX], BP_WLN_INTERFACE);
    nvParamsPtr->iamExParams.ipv6gateway[WLN_EX_PARAMS_IDX] = customizeIamGetDefaultIpv6GatewayConfig(BP_WLN_INTERFACE);
#endif

done:
    return result;
}

/*ad*
 * Changes the params with the setting in the appconf.h
 *
 * @external
 * @category BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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);
    useDefaultIpv6Gateways(params);

#if BSP_WANT_WIRELESS
    /* Get default wireless network params*/
	memcpy (&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
    params->wlnExtParams.wlnCountryCode = NAGetAppWlnCountryCode();
    // update channel mask based on the selected band and country
    {
        unsigned long chan_mask[2];
        
        if (wln_get_channel_mask(params->wlnExtParams.wlnCountryCode, chan_mask) < 0)
        {
            chan_mask[0] = WLN_CHANMASK_ALL;
            chan_mask[1] = WLN_CHANMASK_ALL_HIGH;
        }

        if ((params->wlnParams.band == WLN_BAND_B) || 
            (params->wlnParams.band == WLN_BAND_BG) || 
            (params->wlnParams.band == WLN_BAND_BGN))
        {
            chan_mask[0] &= 0x00003FFF;
            chan_mask[1] = 0;    
        }

        if (params->wlnParams.band == WLN_BAND_A)
        {
            chan_mask[0] &= 0xFFFFC000;
        }
        
        params->wlnParams.chan_mask = chan_mask[0];
        params->wlnExtParams.ext_chan_mask = chan_mask[1];
    }    
#else
    /* Warning!! we need this signature to restore the wireless paramater when
       the interface is enabled */
    params->wlnExtParams.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));        
    memcpy(params->wlnExtParams.wlnPowerCalibration, getDefaultwlnPowerCalibration(), sizeof(params->wlnExtParams.wlnPowerCalibration));
    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;
    }

    /* 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);
}


    
#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(NaWlnParams_t *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 BSP:Board_Params
 * @location src/bsp/customize/boardParams.c
 * @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;
    int errval = BP_FAILURE;
    
#ifdef DOTNETMF
    BYTE mac_addrp[6];
    unsigned long IPAddress;
    int    i;
    char   a, b, c, d;
    char   *ptr;
#endif

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

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

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

#ifdef TEST_MAC    
    mfg_params->id[0] = 'M';
    mfg_params->id[1] = 'N';
    mfg_params->id[2] = 'G';
    mfg_params->id[3] = 'F';
#endif

#ifdef DOTNETMF
    /* Verify ID */
    if ((mfg_params->id[0] != 'M') ||
        (mfg_params->id[1] != 'N') ||
        (mfg_params->id[2] != 'G') ||
        (mfg_params->id[3] != 'F'))
    {
        goto EXIT;
    }
#else
    /* Verify ID */
    if ((mfg_params->id[0] != 'N') ||
        (mfg_params->id[1] != 'M') ||
        (mfg_params->id[2] != 'F') ||
        (mfg_params->id[3] != 'G'))
    {
        goto EXIT;
    }
#endif

#ifdef DOTNETMF
    /* SWAP16 length */
    ptr = (char *)&mfg_params->length;
    a = ptr[0];
    b = ptr[1];
    c = ptr[2];
    d = ptr[3];
    ptr[0] = c;
    ptr[1] = d;
    ptr[2] = a;
    ptr[3] = b;
#endif

#ifndef TEST_MAC
    /* Verify length */
    if (mfg_params->length != sizeof(devMfgBoardParamsType))
    {
        goto EXIT;
    }
#endif

#ifndef DOTNETMF
    /* Verify checksum */
    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;
    }
#else
#if (PLATFORM == connectme9210)
    NAconfigureGPIOpin(12, NA_GPIO_OUTPUT_STATE, 0); /* MFGO = 0 = Loopback state of JIG is off */
#endif
#endif

    /* Set to defaults */        
    customizeUseDefaultParams(&defaultParams);
    memcpy (params, &defaultParams, sizeof (defaultParams));

    /* Copy in mfg parameters */
#if BSP_WANT_WIRELESS
    #ifdef DOTNETMF
    /* We need to byte swap since we are now Little Endian */
    for (i = 0; i < 6; i += 2)
    {
        params->wlnParams.sta_addr[i] = mfg_params->mac_address[i + 1];        
        params->wlnParams.sta_addr[i + 1] = mfg_params->mac_address[i];
    }
    #else
    memcpy(params->wlnParams.sta_addr, mfg_params->mac_address, 6);
    #endif
#else
    #ifdef DOTNETMF
    /* We need to byte swap since we are now Little Endian */
    for (i = 0; i < 6; i += 2)
    {
        params->ethernetMac[i] = mfg_params->mac_address[i + 1];        
        params->ethernetMac[i + 1] = mfg_params->mac_address[i];
    }
    
    #ifdef TEST_MAC
    params->ethernetMac[0] = 0x00;
    params->ethernetMac[1] = 0x40;
    params->ethernetMac[2] = 0x9d;
    params->ethernetMac[3] = 0x11;
    params->ethernetMac[4] = 0x22;
    params->ethernetMac[5] = 0x66;
    #endif
    
    memcpy (ethernetMac, params->ethernetMac, sizeof params->ethernetMac);
    
    params->iamParamsInfo.iamParams[0].staticParams.isEnabled      = 1;
    params->iamParamsInfo.iamParams[0].dhcpParams.isEnabled        = 0;

    /* Create a 192.168.0.x IP address based on the last 6 bits of the last octet in the interface MAC Address */
#ifdef DOTNETMF
    IPAddress = TO_BE32(0xc0a80000 + (ethernetMac[5] & 0x3f)+1);
#else
    IPAddress = 0xc0a80000 + (ethernetMac[5] & 0x3f)+1;
#endif
    params->iamParamsInfo.iamParams[0].staticParams.IPV4_ADDR(ipAddress) = IPAddress;   
    #else
    memcpy(params->ethernetMac, mfg_params->mac_address, 6);
    #endif
#endif

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

    errval = BP_SUCCESS;

EXIT:

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

    return errval;
}
#endif /* FOR_DIGI_MANUFACTURING */


/* 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);  
            len = (sizeof(params->wlnParams) > sizeof(params60->wlnParams))? sizeof (params60->wlnParams): sizeof (params->wlnParams);
            memmove(&params->wlnParams, &params60->wlnParams, len);
            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;
            }
        }
        else /* intermediate version, used in some manufacturing images */
        {
            len = sizeof(devBoardParams62Type) - offsetof(devBoardParams62Type, checksum) - sizeof(params62->checksum) - 4;
            accumulator = blCrc32(0, params62, offsetof(devBoardParams62Type, checksum));
            chksum = blCrc32(accumulator, ((unsigned char *)&(params62->checksum)) + sizeof(params62->checksum), len);

            if (params62->checksum == chksum)
            {
                len = sizeof(devBoardParams62Type) - offsetof(devBoardParams62Type, waitTime) - 4;
                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;
            }
        }
    }

    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 */
static int revertOlderVersionParams(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;

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

done_old_params:
     
    return retVal;
}

int convertFromOlderVersionParams(devBoardParamsType * params)
{
    int retVal = BP_FAILURE;

    retVal = revertOlderVersionParams(params);
    if (retVal != BP_SUCCESS)
    {
        /* couldn't recover from older version */
        customizeUseDefaultParams(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.
 */
int naBoardParamsCheckForInvalidData(devBoardParamsType * params, unsigned shouldFixBadParams, int * shouldSetChecksumError)
{
    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
#define MULTICAST_BIT   1

#if	BSP_WANT_ETHERNET
    if (   (!memcmp(params->ethernetMac, zero_mac_addr, MAC_ADDRESS_SIZE))
        || (params->ethernetMac[0] & MULTICAST_BIT))
    {
        *shouldSetChecksumError = TRUE;
        if (shouldFixBadParams)
        {
            memcpy(params->ethernetMac, getDefaultMacAddress(), 
                    sizeof(params->ethernetMac));
        }
        ret = 1;
    }
    if (strcmp((char *) &params->iamExParams.ifname[0], BP_ETH_INTERFACE) != 0)
    {
        *shouldSetChecksumError = TRUE;
        if (shouldFixBadParams)
        {
            strcpy((char *) &params->iamExParams.ifname[0], BP_ETH_INTERFACE);
        }
        ret = 1;
    }
#endif

#if BSP_WANT_WIRELESS
    if (strcmp((char *) &params->iamExParams.ifname[1], BP_WLN_INTERFACE) != 0)
    {
        *shouldSetChecksumError = TRUE;
        if (shouldFixBadParams)
        {
            strcpy((char *) &params->iamExParams.ifname[1], BP_WLN_INTERFACE);
        }
        ret = 1;
    }
    if (!memcmp(params->wlnParams.sta_addr, zero_mac_addr, MAC_ADDRESS_SIZE)
        || (params->wlnParams.sta_addr[0] & MULTICAST_BIT)
        || (params->wlnExtParams.wlnCountryCode == PARAM_RESTORED_SIGNATURE))
    {
        if (   (!memcmp(params->wlnParams.sta_addr, zero_mac_addr, MAC_ADDRESS_SIZE))
            || (params->wlnParams.sta_addr[0] & MULTICAST_BIT))
            *shouldSetChecksumError = TRUE;
        else
            *shouldSetChecksumError = FALSE;

        if (shouldFixBadParams)
        {
            memcpy(&params->wlnParams, getDefaultWlnParams(), sizeof params->wlnParams);
            memcpy(params->wlnParams.sta_addr, getDefaultWlnMacAddress(), 
                     sizeof(params->wlnParams.sta_addr));
            params->wlnExtParams.wlnCountryCode = NAGetAppWlnCountryCode();
            memcpy(params->wlnExtParams.wlnPowerCalibration, getDefaultwlnPowerCalibration(), sizeof(params->wlnExtParams.wlnPowerCalibration));
        }
        ret = 1;
    }
#endif
#if (BSP_WANT_WIRELESS == FALSE) && (BSP_WANT_ETHERNET == FALSE)
    NA_UNUSED_PARAM(params);
    NA_UNUSED_PARAM(shouldFixBadParams);
    NA_UNUSED_PARAM(shouldSetChecksumError);
#endif

    return ret;
}

/*
 * This is the for internal use version of naBoardParamsCheckForInvalidData.
 * This version sets nvramChecksumError.  Originally, checkForInvalidData
 * did everything and there was no naBoardParamsCheckForInvalidData.  I gutted
 * checkForInvalidData and created naBoardParamsCheckForInvalidData so I
 * could use it externally.
 */
static int checkForInvalidData(devBoardParamsType * params)
{
    return naBoardParamsCheckForInvalidData(params, TRUE, &nvramChecksumError);
}


#if (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)

/*
 * Read the backup copy of NVRAM parameters into the parameter buffer.
 * Verify that it looks okay.  If it does not, then reread the 
 * primary copy into the buffer.
 */
int readAndVerifyBackupNVRAM(devBoardParamsType * params)
{
    int notUsed = 0, ccode, result = BP_FAILURE;
    /*
     * Read the backup copy of NVRAM into the buffer and see if it
     * looks valid.
     */
    ccode = NANVBackupRead (BSP_START_OF_DEV_BOARD_PARAMETERS, (char *) params, sizeof (devBoardParamsType));

    if (   (ccode == 0) 
        && (computeChecksum(params) == params->checksum)
        && (naBoardParamsCheckForInvalidData(params, FALSE, &notUsed) == FALSE))
    {
        /*
         * Backup data looks good.  
         */
        result = BP_SUCCESS;
    }
    else
    {
        /*
         * If branch here, then the
         * backup copy was not good.  Reread the primary copy into our
         * buffer.
         */
        if (NANVRead (BSP_START_OF_DEV_BOARD_PARAMETERS, (char *) params, sizeof (devBoardParamsType)) != 0)
            result = BP_FAILURE;
    }
    

    return result;
}
#endif


/*ad*
 * Reads the contents of the section of NVRAM that contains the development board's startup parameters.
 *
 * @external
 * @category BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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_DO_NOT_USE_NVRAM)
//    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 (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)
                /*
                 * Primary copy doesn't look good.  See if the backup copy
                 * of NVRAM is intact.
                 */
                if (readAndVerifyBackupNVRAM(params) == BP_SUCCESS)
                {
                    /*
                     * It is.  Use it to restore the primary copy. 
                     * readAndVerifyBackupNVRAM left it in the buffer for us.
                     */
                    nvramChecksumError = FALSE;
                    customizeWriteDevBoardParams (params);
                    result = BP_SUCCESS;
                    /* if we only want mac address from nvram, goto use_default
                     * to get default values.
                     * Otherwise, done with all parameters read from nvram.
                     */
                    if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                        goto use_default;
                    goto done;
                }
                /*
                 * If the backup copy was bad, then readAndVerifyBackupNVRAM 
                 * has already reloaded the primary copy of NVRAM into the
                 * buffer for us.  The code below tries to convert an old
                 * version of NVRAM into the current one, if that is the problem...
                 */
#endif
                if (params->sizeOfRecord > sizeof *params)
                {
                    if (computeChecksumFromSize(params) == params->checksum)
                    {
                        customizeWriteDevBoardParams (params);
                        result = BP_SUCCESS;
                        /* if we only want mac address from nvram, goto use_default
                         * to get default values.
                         * Otherwise, done with all parameters read from nvram.
                         */
                        if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                            goto use_default;
                        goto done;
                    }
                }

                if (convertFromOlderVersionParams(params) == BP_SUCCESS)
                {
                    customizeWriteDevBoardParams (params);
                    result = BP_SUCCESS;
                    /* if we only want mac address from nvram, goto use_default
                     * to get default values.
                     * Otherwise, done with all parameters read from nvram.
                     */
                    if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                        goto use_default;

                    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))
            {
#if (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)
                /*
                 * Primary copy looks bad.  See if the backup copy
                 * is any better.
                 */
                if (readAndVerifyBackupNVRAM(params) == BP_SUCCESS)
                {
                    /*
                     * Backup copy looks good.  readAndVerifyBackupNVRAM has
                     * already read it into the buffer.  Now write it into
                     * the primary NVRAM area.
                     */
                    nvramChecksumError = FALSE;
                    customizeWriteDevBoardParams (params);
                    result = BP_SUCCESS;
                    /* if we only want mac address from nvram, goto use_default
                     * to get default values.
                     * Otherwise, done with all parameters read from nvram.
                     */
                    if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                        goto use_default;
                    goto done;
                }
                else
                {
                    /*
                     * The backup copy isn't usable.  readAndVerifyBackupNVRAM already
                     * reread the primary copy into the buffer.  We need to call
                     * checkForInvalidData again because it has side effects (I hate
                     * functions that have side effects).
                     */
                    checkForInvalidData(params);
                }
#endif
                nvramChecksumError = FALSE;
                customizeWriteDevBoardParams (params);
                result = BP_SUCCESS;
                /* if we only want mac address from nvram, goto use_default
                 * to get default values.
                 * Otherwise, done with all parameters read from nvram.
                 */
                if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                    goto use_default;
                goto done;
            }
            else
            {
#if (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)
                static BOOLEAN first_time = TRUE;
                
                /* Once at startup, make sure backup paramaters are valid */
                if (first_time)
                {
                    devBoardParamsType *backup = (devBoardParamsType *)bpMalloc(sizeof(devBoardParamsType));                    
                    if (backup != NULL)
                    {
                        ccode = NANVBackupRead(BSP_START_OF_DEV_BOARD_PARAMETERS, 
                                               (char *) backup, sizeof(devBoardParamsType));
                        if ((ccode == 0) && memcmp(backup, params, sizeof(devBoardParamsType)))
                        {
                            /* they are not identical, overwrite with primary data */
                            NANVBackupWrite(BSP_START_OF_DEV_BOARD_PARAMETERS, 
                                            (char *) params, sizeof(devBoardParamsType));
                        }
                        bpFree(backup);
                    }                    
                    first_time = FALSE;
                }
#endif
                result = BP_SUCCESS;
                /* if we only want mac address from nvram, goto use_default
                 * to get default values.
                 * Otherwise, done with all parameters read from nvram.
                 */
                if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                    goto use_default;
                goto done;
            }
        }
        else /* use default configuration if error reading NVRAM */
        {
#if (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)
            /*
             * This is probably a waste of code since we come here
             * only if we can't read NVRAM, but let's go through the
             * motions anyway...
             *
             * Try to read and verify the backup copy of NVRAM.
             */
            if (readAndVerifyBackupNVRAM(params) == BP_SUCCESS)
            {
                /*
                 * Hey!  Somehow we were able to read it, even though we
                 * couldn't read the primary copy.  This probably means the
                 * primary NVRAM flash sector is dead.  That's not a good
                 * thing.  However, go ahead and try to write the good 
                 * values into it.  There isn't much else we can do...
                 */
                nvramChecksumError = FALSE;
                customizeWriteDevBoardParams (params);
                result = BP_SUCCESS;
                /* if we only want mac address from nvram, goto use_default
                 * to get default values.
                 * Otherwise, done with all parameters read from nvram.
                 */
                if (NAGetAppUseNvram() == APP_FOR_MAC_ADDRESS_ONLY) 
                    goto use_default;
                goto done;
            }
            /*
             * Looks like we weren't able to read the backup copy of NVRAM
             * either.  This is not a surprise since we only come here if
             * there was an error reading flash when we tried to read the
             * primary copy.
             */
#endif
            /*
             * 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 BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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)
    {
        update_idigi_params_crc(params);

        params->sizeOfRecord = sizeof *params;
        params->checksum = computeChecksum(params);

        if (NAGetAppUseNvram() != APP_DO_NOT_USE_NVRAM)  /* return the APP_USE_NVRAM value */
        {
            if( NANVWrite (BSP_START_OF_DEV_BOARD_PARAMETERS, (char *) params, sizeof (devBoardParamsType)) == 0)
            {
#if NAMI_SUPPORTED
            	//save another copy of MAC addresses in a tagged area
				if (saveModuleInfo(params) == 0)
#endif
                	return 0;
            }
        }
        else
            return 0;
    }

    return -1;
}

#if NAMI_SUPPORTED

/* return -1: failed*/
static int saveModuleInfo(devBoardParamsType * params)
{
#if !BSP_WANT_WIRELESS && !BSP_WANT_ETHERNET
	(void)params;
	return 0;
#else
	uint16 *temp=NULL, *newTags=NULL;
	int len, newLen=0;
	
	temp = bpMalloc(sizeof(devBoardParamsType));
	if (temp != NULL)
    {    
    	newTags = bpMalloc(sizeof(devBoardParamsType));
    	if (newTags != NULL)
    	{
#if	BSP_WANT_ETHERNET 
            len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_ETH_MAC_TAG, 0, temp);
        	if ((len <= 0) || (len != NAMI_ETH_MAC_LENGTH) || (memcmp(params->ethernetMac, temp, len*2)!=0) )
            { 
                newTags[newLen] = NAMI_ETH_MAC_TAG;
                newTags[newLen+1] =   NAMI_ETH_MAC_LENGTH;
                memcpy(&newTags[newLen+2],  params->ethernetMac, NAMI_ETH_MAC_LENGTH*2);
                newLen += 1/*tag name*/ + 1/*tag length*/ + NAMI_ETH_MAC_LENGTH;
            }
#endif
#if	BSP_WANT_WIRELESS  
            len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_MAC_TAG, 0, temp);
            if ((len <= 0) || (len != NAMI_WIFI_MAC_LENGTH) || (memcmp(params->wlnParams.sta_addr, temp, len*2)!=0) )
            { 
                newTags[newLen] = NAMI_WIFI_MAC_TAG;
                newTags[newLen+1] =   NAMI_WIFI_MAC_LENGTH;
                memcpy(&newTags[newLen+2],  params->wlnParams.sta_addr, NAMI_WIFI_MAC_LENGTH*2);
                newLen += 1/*tag name*/ + 1/*tag length*/ + NAMI_ETH_MAC_LENGTH;
            }
#if (platform == connectwiem9210) || (platform == connectcorewi9p9215_a) 
            len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_CALIB_TAG, 0, temp);
            if ((len <= 0) || (len != NAMI_WIFI_CALIB_LENGTH) || (memcmp(params->wlnExtParams.wlnPowerCalibration, temp, len*2)!=0))
            {    
                newTags[newLen] = NAMI_WIFI_CALIB_TAG;
                newTags[newLen+1] =   NAMI_WIFI_CALIB_LENGTH;
                memcpy(&newTags[newLen+2],  params->wlnExtParams.wlnPowerCalibration, NAMI_WIFI_CALIB_LENGTH*2);
                newLen += 1/*tag name*/ + 1/*tag length*/ + NAMI_WIFI_CALIB_LENGTH;  
            }    
#endif  //(platform == connectwiem9210) || (platform == connectcorewi9p9215_a) 

           if(newLen >0)
            {
                if(namiUpdateTag(NAMI_LOCATION_IN_FLASH, newTags, newLen)!= 0)
                {
                    bpFree(newTags);
                    bpFree(temp);	
                    return -1;
                }
            }
#endif  //BSP_WANT_WIRELESS	

        	bpFree(temp);
        	bpFree(newTags);	
        	return 0;
	    }
	    else
	    {
	        bpFree(temp);
	        return -1;
	    }
	}
#endif	
	return -1;
}

#if 0
/* return -1: failed*/
static int saveModuleInfo(devBoardParamsType * params)
{
#if !BSP_WANT_WIRELESS && !BSP_WANT_ETHERNET
	(void)params;
#else
	uint16 *temp;
	int len;
	
	temp = bpMalloc(sizeof(devBoardParamsType));
	if (temp != NULL)
	{
#if	BSP_WANT_ETHERNET    
		len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_ETH_MAC_TAG, 0, temp);
		if ((len <= 0) || (len != NAMI_ETH_MAC_LENGTH) || (memcmp(params->ethernetMac, temp, len*2)!=0) )
		{       			
	            	// Delete all obsolete eth mac tags.
	    		while (0 == namiDeleteTag(NAMI_LOCATION_IN_FLASH, NAMI_ETH_MAC_TAG, 0))
	                        ;
	    		if (namiAppendTag(NAMI_LOCATION_IN_FLASH, NAMI_ETH_MAC_TAG, (uint16 *)params->ethernetMac, NAMI_ETH_MAC_LENGTH) != 0)
	    		{
	    			bpFree(temp);
	            		return -1;        // Failed to save eth mac.
	            	}
	        }
#endif
#if	BSP_WANT_WIRELESS  
		len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_MAC_TAG, 0, temp);
		if ((len <= 0) || (len != NAMI_WIFI_MAC_LENGTH) || (memcmp(params->wlnParams.sta_addr, temp, len*2)!=0) )
		{                 		
	            	// Delete all obsolete wifi mac tags.
	    		while (0 == namiDeleteTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_MAC_TAG, 0))
	                        ;
	    		if (namiAppendTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_MAC_TAG, (uint16 *)params->wlnParams.sta_addr, NAMI_WIFI_MAC_LENGTH) != 0)
	            	{
	    			bpFree(temp);
	            		return -1;        // Failed to save wifi mac.
	            	}
	       }
#if (platform == connectwiem9210) || (platform == connectcorewi9p9215_a)   
		len = namiFindTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_CALIB_TAG, 0, temp);
		if ((len <= 0) || (len != NAMI_WIFI_CALIB_LENGTH) || (memcmp(params->wlnExtParams.wlnPowerCalibration, temp, len*2)!=0))
		{           		
	            	// Delete all obsolete wifi calibration data tags.
	    		while (0 == namiDeleteTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_CALIB_TAG, 0))
	                        ;
	    		if (namiAppendTag(NAMI_LOCATION_IN_FLASH, NAMI_WIFI_CALIB_TAG, (uint16 *)params->wlnExtParams.wlnPowerCalibration, NAMI_WIFI_CALIB_LENGTH) != 0)
	    		{
	    			bpFree(temp);
	            		return -1;        // Failed to save wifi calibration data.
	            	}
	        }        
#endif  //(platform == connectwiem9210) || (platform == connectcorewi9p9215_a) 
#endif  //BSP_WANT_WIRELESS	

	bpFree(temp);	
	return 0;
	}
#endif	
	return -1;
}
#endif
#endif


/*ad*
 * Retrieves the static IPv4 address values (address, subnet mask and
 * default gateway) from NVRAM. Ihe caller is then able to make a determination
 * if a valid IP address has been retrieved and stored in NVRAM.
 *
 * If your platform supports Ethernet, IP parameters for eth0 are retrieved, 
 * otherwise if your platform supports wireless, IP parameters for wln0
 * are retrieved.
 *
 * Zero values indicate that the addresses have not been initialized.
 *
 * @external
 * @category BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @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.
 *
 * @see @link customizeSaveIPParameters
*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);
#elif BSP_WANT_WIRELESS
    customizeIamGetStaticConfig(BP_WLN_INTERFACE, &config);   
#endif   

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


/*ad*
 * Saves static IPv4 address parameters to NVRAM and enables static IP address
 * in NVRAM.
 *
 * If your platform supports Ethernet, IP parameters for eth0 are saved, 
 * otherwise if your platform supports wireless, IP parameters for wln0
 * are saved.
 *
 * @external
 * @category BSP:Board_Params
 * @include <boardParams.h>
 * @location src/bsp/customize/boardParams.c
 * @since 6.0
 *
 * @param ipaddr    IP address to save
 * @param submask   Subnet mask to save
 * @param defgw     Default gateway to save
 *
 * @see @link customizeGetIPParameters
*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);
#elif BSP_WANT_WIRELESS
    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*/
#elif BSP_WANT_WIRELESS
    customizeIamSetStaticConfig(BP_WLN_INTERFACE, &config);   
#endif

}

/* 
 * Retrieves the static IPv4 address parameters from NVRAM 
 * for the network interface with the name ifname.
 */
BOOLEAN customizeGetInterfaceIPParameters(const char * ifname, unsigned long * ipaddr, unsigned long * submask, unsigned long * defgw)
{
	NaIamStaticParams_t config;

	if (ifname == NULL || ipaddr == NULL || submask == NULL || defgw == NULL)
		return FALSE;

	if (customizeIamGetStaticConfig(ifname, &config) == BP_SUCCESS)
	{
		*ipaddr  = config.IPV4_ADDR(ipAddress);
		*submask = config.subnetMask;
		*defgw   = config.IPV4_ADDR(gateway);

		return TRUE;
	}
	return FALSE;
}

/* 
 * Saves static IPv4 address parameters to NVRAM and enables static IP address
 * in NVRAM for the network interface with the name ifname.
 */
BOOLEAN customizeSaveInterfaceIPParameters(const char * ifname, unsigned long ipaddr, unsigned long submask, unsigned long defgw)
{
	NaIamStaticParams_t config;

	if (customizeIamGetStaticConfig(ifname, &config) == BP_SUCCESS)
	{
		config.IPV4_ADDR(ipAddress) = ipaddr;
		config.subnetMask = submask;
		config.IPV4_ADDR(gateway) = defgw;
		config.isEnabled = TRUE;

		customizeIamSetStaticConfig(ifname, &config); 
		return TRUE;
	}
	return FALSE;
}

/* 
 * If mode == TRUE, enables DHCP and disables static IPv4 address in NVRAM,
 * if mode == FALSE, enables static and disables DHCP IPv4 address in NVRAM
 * for the network interface with the name ifname.
 * 
 */
BOOLEAN customizeSaveInterfaceEnable(const char * ifname, BOOLEAN mode)
{
   NaIamStaticParams_t static_config;
   NaIamDhcpParams_t   dhcp_config;

   if (customizeIamGetStaticConfig(ifname, &static_config) == BP_SUCCESS && 
	   customizeIamGetDhcpConfig(ifname, &dhcp_config)     == BP_SUCCESS)
   {
		static_config.isEnabled = !mode;
		dhcp_config.isEnabled = mode;

		customizeIamSetStaticConfig(ifname, &static_config);
		customizeIamSetDhcpConfig(ifname, &dhcp_config);

		return TRUE;
   }
   return FALSE;
}

/* 
 * If mode == TRUE, enables DHCP and disables static IPv4 address in NVRAM,
 * if mode == FALSE, enables static and disables DHCP IPv4 address in NVRAM
 * for the eth0 if the platform runs Ethernet, otherwise for wln0, 
 * the platform runs wireless.
 */
void customizeSaveEnable(BOOLEAN mode)
{
   NaIamStaticParams_t static_config;
   NaIamDhcpParams_t   dhcp_config;

#if BSP_WANT_ETHERNET
   customizeIamGetStaticConfig(BP_ETH_INTERFACE, &static_config);
   customizeIamGetDhcpConfig(BP_ETH_INTERFACE, &dhcp_config);

#elif BSP_WANT_WIRELESS
   customizeIamGetStaticConfig(BP_WLN_INTERFACE, &static_config);
   customizeIamGetDhcpConfig(BP_WLN_INTERFACE, &dhcp_config);
#endif

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

#if BSP_WANT_ETHERNET
   customizeIamSetStaticConfig(BP_ETH_INTERFACE, &static_config);
   customizeIamSetDhcpConfig(BP_ETH_INTERFACE, &dhcp_config);

#elif BSP_WANT_WIRELESS
   customizeIamSetStaticConfig(BP_WLN_INTERFACE, &static_config);
   customizeIamSetDhcpConfig(BP_WLN_INTERFACE, &dhcp_config);
#endif
}

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);
}

static int update_idigi_params_crc(devBoardParamsType * nvParamsPtr)
{
    int       rc = 0;
    unsigned long checksum;
    NaiDigiParams_t     * idigiPtr;
    char                * ptr;
    unsigned            size;
    unsigned            offset;

    if (nvParamsPtr == NULL) 
    {
        rc = -1;
        goto _ret;
    }

    idigiPtr = &nvParamsPtr->idigiParams;

    nvParamsPtr->idigiParams.sizeOfRecord = sizeof(NaiDigiParams_t);

    offset = sizeof(idigiPtr->signature) + sizeof(idigiPtr->checksum) + sizeof(idigiPtr->sizeOfRecord);

    ptr = (char *)idigiPtr + offset;

    size = sizeof(NaiDigiParams_t) - offset;

    checksum = blCrc32(0, ptr, size);
    nvParamsPtr->idigiParams.checksum = checksum;

_ret:
    return rc;
}

