/*****************************************************************************
* Copyright (c) 2005 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
*
*****************************************************************************/
#include "boardParams.h"
#include "ace_params.h"
#include "naifconfig.h"
#include "iam.hh"
#include "iam_params.h"
#include "bsp.h"
#include "appconf_api.h"
#include "dhcpOptions.h"
#include "starttcp.h"
#include "narmapi.h"
#include "vpn.h"

#define DEFAULT_NUMBER_OF_INTERFACES    2

#define PRIMARY_INTERFACE_INDEX      0
#define SECONDARY_INTERFACE_INDEX    1

/*ad*
 * This is the shared parameter buffer protected with semaphores.
 *
 * @category Networking:IAM:iam_params
 * @since 7.0
*ad*/
static devBoardParamsType boardParamsBuffer;

/* For GNU 4.0.3, we have to do this to remove initialization warning. */
static NaIamParams_t defaultUnusedInterfaceConfig;

#ifdef IAM_CAN_USE_MUTEX
static TX_MUTEX iam_mutex;
static unsigned mutex_initialized = 0;
#define IAM_LOCK()     { tx_mutex_get(&iam_mutex, TX_WAIT_FOREVER); }
#define IAM_UNLOCK()   { tx_mutex_put(&iam_mutex); }
#else
#define IAM_LOCK()
#define IAM_UNLOCK()
#endif

/*ad*
 * This structure stores the default Ethernet configuration settings
 * for IAM.  You should edit these settings to suit your
 * application.
 *
 * The initial values that NET+OS ships with cause IAM to use
 * DHCP to configuration settings.
 *
 * The IAM configuration can be overridden by settings in the
 * application's appconf.h file:
 * <list type="unordered">
 *  <item>APP_ENABLE_AUTO_IP:  IAM will enable Auto-IP on the
 *        eth0:0 or wln0:0 interface if this option is set.  Auto-IP is
 *        not suitable for all applications.  IP addresses
 *        acquired using it are not routable and may cause
 *        errors. </item>
 *  <item>APP_USE_STATIC_IP:  If this option is set, then IAM
 *        will use the values set by APP_IP_ADDRESS,
 *        APP_IP_SUBNET_MASK, and APP_IP_GATEWAY in appconf.h.
 *        </item>
 * </list>
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
*ad*/
static NaIamParams_t NADefaultEthInterfaceConfig[] =
{
    {
        TRUE, /* Interface enabled */
        TRUE,
        BP_ETH_INTERFACE,                   /* config for Ethernet interface*/
        {   /* static config record*/
            FALSE,                          /* disable by default */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* don't know IPv4 address */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* don't know IPv6 address */
            NA_IAM_UNKNOWN_SUBNET_MASK,     /* unknown subnet mask */
            NA_IAM_DEFAULT_PREFIX_LEN,      /* 64 */
			0,								/* both staticV6 and DHCPv6 disabled */
             NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown gateway */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown primary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown secondary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS       /* unknown gateway tunnel */
        },
        {   /* config for DHCP*/
            TRUE,                           /* enabled by default */
            {0},                            /* no options by default */
            0                               /* buffer length */
        },
        {   /* Auto IP is off by default*/
            FALSE                           /* disabled by default */
        },
    }
/*
 * This second Ethernet or 802.11 configuration structure exists to support Auto-IP.
 * Auto-IP has to be implemented on a secondary interface (in this case eth0:0 or wln0:0)
 * since its addresses are not routable.  The default setup below has Auto-IP
 * disabled.  However, the structure will be updated to enable Auto-IP if
 * APP_ENABLE_AUTO_IP is set to TRUE.
 */
#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
    ,{
        TRUE,
        TRUE,
        BP_ETH_0INTERFACE,                   /* config for Ethernet interface*/
        {   /* static config record*/
            TRUE,                            /* enable by default */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* don't know IPv4 address */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* don't know IPv6 address */
            NA_IAM_UNKNOWN_SUBNET_MASK,      /* unknown subnet mask */
            NA_IAM_DEFAULT_PREFIX_LEN,   	 /* 64 */
			0,								 /* both staticV6 and DHCPv6 disabled */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown gateway */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown primary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown secondary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS        /* inknown gateway tunnel */
        },
        {   /* config for DHCP*/
            FALSE,                           /* disable by default */
            {0},                             /* no options by default */
            0                                /* buffer length */
        },
        {   /* Auto IP is off by default*/
            FALSE                            /* disable by default */
        },
    }
#endif
};
/*ad*
 * This structure stores the default wireless configuration settings
 * for IAM.  You should edit these settings to suit your
 * application.
 *
 * The initial values that NET+OS ships with cause IAM to use
 * DHCP to configuration settings.
 *
 * The IAM configuration can be overridden by settings in the
 * application's appconf.h file:
 * <list type="unordered">
 *  <item>APP_ENABLE_AUTO_IP:  IAM will enable Auto-IP on the
 *        eth0:0 or wln0:0 interface if this option is set.  Auto-IP is
 *        not suitable for all applications.  IP addresses
 *        acquired using it are not routable and may cause
 *        errors. </item>
 *  <item>APP_USE_STATIC_IP:  If this option is set, then IAM
 *        will use the values set by APP_IP_ADDRESS,
 *        APP_IP_SUBNET_MASK, and APP_IP_GATEWAY in appconf.h.
 *        </item>
 * </list>
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
*ad*/
static NaIamParams_t NADefaultWlnInterfaceConfig[] =
{
    {
        TRUE, /* Interface enabled */
        TRUE,
        BP_ETH_INTERFACE,                   /* config for Ethernet interface*/
        {   /* static config record*/
            FALSE,                          /* disable by default */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* don't know IPv4 address */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* don't know IPv6 address */
            NA_IAM_UNKNOWN_SUBNET_MASK,     /* unknown subnet mask */
            NA_IAM_DEFAULT_PREFIX_LEN,      /* 64 */
			0,								/* both staticV6 and DHCPv6 disabled */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown gateway */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown primary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS,      /* unknown secondary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS       /* unknown gateway tunnel */
        },
        {   /* config for DHCP*/
            TRUE,                           /* enabled by default */
            {0},                            /* no options by default */
            0                               /* buffer length */
        },
        {   /* Auto IP is off by default*/
            FALSE                           /* disabled by default */
        },
    }
/*
 * This second Ethernet or 802.11 configuration structure exists to support Auto-IP.
 * Auto-IP has to be implemented on a secondary interface (in this case eth0:0 or wln0:0)
 * since its addresses are not routable.  The default setup below has Auto-IP
 * disabled.  However, the structure will be updated to enable Auto-IP if
 * APP_ENABLE_AUTO_IP is set to TRUE.
 */
#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
    ,{
        FALSE, /* IF disabled */
        TRUE,
        BP_ETH_0INTERFACE,                   /* config for Ethernet interface*/
        {   /* static config record*/
            FALSE,                           /* disable by default */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* don't know IPv4 address */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* don't know IPv6 address */
            NA_IAM_UNKNOWN_SUBNET_MASK,      /* unknown subnet mask */
            NA_IAM_DEFAULT_PREFIX_LEN,       /* 64 */
			0,								 /* both staticV6 and DHCPv6 disabled */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown gateway */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown primary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS,       /* unknown secondary DNS */
            NA_IAM_UNKNOWN_IP_ADDRESS        /* inknown gateway tunnel */
        },
        {   /* config for DHCP*/
            FALSE,                            /* enabled by default */
            {0},                             /* no options by default */
            0                                /* buffer length */
        },
        {   /* Auto IP is off by default*/
            FALSE                            /* disabled by default */
        },
    }
#endif
};


/*ad*
 * This is the default list of DHCP options that the DHCP client requests from
 * the server.  Update this list to include any additional DHCP
 * options that are required by your application.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
*ad*/
static WORD8 const iamDhcpOptions[] =
{
	SUBNET_MASK, ROUTERS_ON_SUBNET, DNS,
	HOST_NAME, DOMAIN_NAME, BROADCAST_ADDR,
	NTP_SERVERS, NIS_DOMAIN_NAME,TCP_KEEP_ALIVE_INTERVAL,
    DEFAULT_IP_TTL, TCP_DEFAULT_TTL,
	TCP_KEEP_ALIVE_GARBAGE, IP_FORWARDING,IF_MTU
};

/*ad*
 * This function finds the IAM configuration record for the indicated
 * interface in the IAM configuration structure passed in to this function.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string name of the interface for which to
 *                  retrieve settings. For example, "eth0" or
 *                  "eth0:0". The string is case sensitive.
 * @param   config  Pointer to buffer with IAM configuration.
 *
 * @return NULL             No configuration for interface was found.
 * @return pointer          Pointer to interface configuration.
*ad*/
NaIamParams_t * customizeIamFindInterfaceConfig(char const * ifname, NaIamParamsInfo_t * config)
{
    int idx;
    NaIamParams_t *result = NULL;

    if (config->version == NA_IAM_CONFIG_VERSION)
    {
        for (idx = 0; idx < NA_IAM_INTERFACE_MAX; idx++)
        {
            if (config->iamParams[idx].isConfigValid)
            {
                if (strcmp(config->iamParams[idx].ifname, ifname) == 0)
                {
                    result = &config->iamParams[idx];
                    break;
                }
            }
        }
    }
    return result;
}

/*ad*
 * This function gets the default configuration for the Ethernet or wireless interface.
 * The default configuration is to get IP parameters by any means.
 *
 * @param   config  Pointer to buffer to be loaded with default configuration
 *                  values for the network interface.
 * @param   idx     Indicates which entry in NADefaultEthInterfaceConfig should be used.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @return BP_SUCCESS       Success
*ad*/
int customizeIamGetDefaultEthernetConfig(NaIamParams_t * config, unsigned idx)
{
    static int haveInitialized = FALSE;
    unsigned long app_ip_address_val, app_ip_subnet_mask_val, app_ip_gateway_val;
    char	*valueStr;

    NA_ASSERT(config != NULL);
    NA_ASSERT(idx < DEFAULT_NUMBER_OF_INTERFACES);

    /* calculate app_ip_address_val value */
    valueStr = NAGetAppIpAddress ();
    app_ip_address_val = NAInet_addr(valueStr);

    /* calculate app_ip_subnet_mask_val value */
    valueStr = NAGetAppIpSubnetMask ();
    app_ip_subnet_mask_val = NAInet_addr(valueStr);

    /* calculate app_ip_subnet_mask_val value */
    valueStr = NAGetAppIpGateway ();
    app_ip_gateway_val = NAInet_addr(valueStr);

    if (!haveInitialized)
    {
        /* optionsBuffer has to be in the actual DHCP packet options format. We subtract 2 from size
         * calculations in order to account for the two bytes needed to specify the options field.*/
        unsigned dhcp_options_count = asizeof(iamDhcpOptions) < (NA_IAM_DHCP_OPTIONS_BUFFER_LEN - 2) ?
                                             asizeof(iamDhcpOptions) : (NA_IAM_DHCP_OPTIONS_BUFFER_LEN - 2);

        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[0] = DHCP_PARAM_REQUEST;
        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[1] = dhcp_options_count;

        memcpy(&NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[3],
               iamDhcpOptions, dhcp_options_count);

        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsLength = dhcp_options_count;

        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.isEnabled   = ((NAGetAppUseStaticIP() & APP_ON_ETHERNET_INTERFACE) != 0);
        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.isEnabled =
         1 - NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.isEnabled;

        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(ipAddress)  = app_ip_address_val;
        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.subnetMask = app_ip_subnet_mask_val;
        NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(gateway)     = app_ip_gateway_val;

#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
        /* Set IP address for VPN tunnel */
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].isEnabled = TRUE;
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].dhcpParams.isEnabled = FALSE;
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].autoipParams.isEnabled = FALSE;

        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.isEnabled = TRUE;
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(ipAddress)  = NAInet_addr(OUR_ADDRESS_ON_LOCAL_SUBNET);
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.subnetMask = NAInet_addr(LOCAL_IP_SUBNET_MASK);
        NADefaultEthInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(gateway) = 0;
#endif

		NaIpv6SetStaticEnabled(&NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);
		NaIpv6SetDhcpEnabled(&NADefaultEthInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);

        haveInitialized = TRUE;
#ifdef IAM_CAN_USE_MUTEX
        if (!mutex_initialized)
        {
            if(tx_mutex_create(&iam_mutex, "iam board param mutex", TX_INHERIT) != TX_SUCCESS)
            {
                assert(0);
            }
            mutex_initialized = 1;
        }
#endif
    }

    *config = NADefaultEthInterfaceConfig[idx];

    return BP_SUCCESS;
}

/*ad*
 * This function gets the default configuration for the wireless interface. The default configuration
 * is to get IP parameters by any means.
 *
 * @param   config  Pointer to buffer that to be loaded with default configuration
 *                  values for the Ethernet interface
 * @param   idx     Indicates which entry in NADefaultEthInterfaceConfig should be used
 *
 * @external
 * @category Networking:IAM
 * @since 7.0
 *
 * @return BP_SUCCESS       Success
*ad*/
int customizeIamGetDefaultWirelessConfig(NaIamParams_t * config, unsigned idx)
{
    static int haveInitializedWireless = FALSE;
    unsigned long app_ip_address_val = 0, app_ip_subnet_mask_val = 0, app_ip_gateway_val = 0;
    char	*valueStr;

    NA_ASSERT(config != NULL);
    NA_ASSERT(idx < DEFAULT_NUMBER_OF_INTERFACES);

    /* calculate app_ip_address_val value */
    valueStr = (char	*)NAGetApp2ndInterfaceIpAddress ();
    if (valueStr)
        app_ip_address_val = NAInet_addr (valueStr);

    /* calculate app_ip_subnet_mask_val value */
    valueStr = (char	*)NAGetApp2ndInterfaceIpSubnetMask ();
    if (valueStr)
        app_ip_subnet_mask_val = NAInet_addr(valueStr);

    /* calculate app_ip_subnet_mask_val value */
    valueStr = (char	*)NAGetApp2ndInterfaceIpGateway ();
    if (valueStr)
        app_ip_gateway_val = NAInet_addr (valueStr);

    if (!haveInitializedWireless)
    {
        /* optionsBuffer has to be in the actual DHCP packet options format. We subtract 2 from size
         * calculations in order to account for the two bytes needed to specify the options field.*/
        unsigned dhcp_options_count = asizeof(iamDhcpOptions) < (NA_IAM_DHCP_OPTIONS_BUFFER_LEN - 2) ?
                                             asizeof(iamDhcpOptions) : (NA_IAM_DHCP_OPTIONS_BUFFER_LEN - 2);

        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[0] = DHCP_PARAM_REQUEST;
        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[1] = dhcp_options_count;

        memcpy(&NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsBuffer[3],
               iamDhcpOptions, dhcp_options_count);

        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.optionsLength = dhcp_options_count;

        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.isEnabled   = ((NAGetAppUseStaticIP() & APP_ON_WIRELESS_INTERFACE) != 0);
        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].dhcpParams.isEnabled =
         1 - NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.isEnabled;

        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(ipAddress)  = app_ip_address_val;
        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.subnetMask = app_ip_subnet_mask_val;
        NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(gateway)    = app_ip_gateway_val;

		NaIpv6SetStaticEnabled(&NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);
		NaIpv6SetDhcpEnabled(&NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);

        haveInitializedWireless = TRUE;

#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
#if !defined(BSP_WANT_ETHERNET) || (BSP_WANT_ETHERNET == FALSE)
        /* Set IP address for VPN tunnel */
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].isEnabled = TRUE;
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].dhcpParams.isEnabled = FALSE;
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].autoipParams.isEnabled = FALSE;

        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.isEnabled = TRUE;
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(ipAddress)  = NAInet_addr(OUR_ADDRESS_ON_LOCAL_SUBNET);
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.subnetMask = NAInet_addr(LOCAL_IP_SUBNET_MASK);
        NADefaultWlnInterfaceConfig[SECONDARY_INTERFACE_INDEX].staticParams.IPV4_ADDR(gateway) = 0;
#endif
#endif
		NaIpv6SetStaticEnabled(&NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);
		NaIpv6SetDhcpEnabled(&NADefaultWlnInterfaceConfig[PRIMARY_INTERFACE_INDEX], FALSE);

#ifdef IAM_CAN_USE_MUTEX
        if (!mutex_initialized)
        {
            if(tx_mutex_create(&iam_mutex, "iam board param mutex", TX_INHERIT) != TX_SUCCESS)
            {
                assert(0);
            }
            mutex_initialized = 1;
        }
#endif
    }

    *config = NADefaultWlnInterfaceConfig[idx];

    return BP_SUCCESS;
}


/*ad*
 * This function gets a configuration record that contains default values for the
 * indicated interface. This routine does NOT check to see if a configuration
 * for the interface already exists.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example, "eth0" or
 *                  "eth0:0". The string is case sensitive.
 * @param   config  Pointer to buffer to write configuration values into.
 *
 * @return BP_SUCCESS       Success
*ad*/
int customizeIamGetDefaultInterfaceConfig(char const * ifname, NaIamParams_t * config)
{
    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);

#if !defined(BSP_WANT_ETHERNET) || BSP_WANT_ETHERNET
    if (strcmp(ifname, BP_ETH_INTERFACE) == 0)
    {
        customizeIamGetDefaultEthernetConfig(config, PRIMARY_INTERFACE_INDEX);
    }
    else
    if (strcmp(ifname, BP_ETH_0INTERFACE) == 0)
    {
        customizeIamGetDefaultEthernetConfig(config, SECONDARY_INTERFACE_INDEX);
    }
    else
#endif
#if BSP_WANT_WIRELESS
    if (strcmp(ifname, BP_WLN_INTERFACE) == 0)
    {
        customizeIamGetDefaultWirelessConfig(config, PRIMARY_INTERFACE_INDEX);
        /* Update the interface name. */
        strcpy(config->ifname, BP_WLN_INTERFACE);
    }
    else
    if (strcmp(ifname, BP_WLN_0INTERFACE) == 0)
    {
        customizeIamGetDefaultWirelessConfig(config, SECONDARY_INTERFACE_INDEX);
        /* Update the interface name. */
        strcpy(config->ifname, BP_WLN_0INTERFACE);
    }
    else
#endif
    {
        *config = defaultUnusedInterfaceConfig;
    }

    return BP_SUCCESS;
}

/*ad*
 * This function gets default configuration values for IAM.  The default
 * configuration is to use all protocols to get an IP address for the
 * eth0/wln0 interface.
 *
 * @param   config  Pointer to buffer that is to be loaded with default configuration
 *                  values for IAM.
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @return BP_SUCCESS       Success
*ad*/
int customizeIamGetDefaultConfig(NaIamParamsInfo_t * config)
{
    unsigned int idx;
    int first_unused = 0;

    NA_ASSERT(config != NULL);

    config->version = NA_IAM_CONFIG_VERSION;

#if !defined(BSP_WANT_ETHERNET) || BSP_WANT_ETHERNET
    customizeIamGetDefaultEthernetConfig(&config->iamParams[0], PRIMARY_INTERFACE_INDEX);
    first_unused++;

#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
    customizeIamGetDefaultEthernetConfig(&config->iamParams[1], SECONDARY_INTERFACE_INDEX);
    first_unused++;
#endif

#endif

#if BSP_WANT_WIRELESS

    customizeIamGetDefaultInterfaceConfig(BP_WLN_INTERFACE, &config->iamParams[first_unused]);
    first_unused++;

#if (DEFAULT_NUMBER_OF_INTERFACES > 1)
    customizeIamGetDefaultInterfaceConfig(BP_WLN_0INTERFACE, &config->iamParams[first_unused]);
    first_unused++;
#endif
#endif /* BSP_WANT_WIRELESS */

    for (idx = first_unused; idx < asizeof(config->iamParams); idx++)
    {
        config->iamParams[idx] = defaultUnusedInterfaceConfig;
    }

    return BP_SUCCESS;
}


/*ad*
 * This function finds an unused configuration record in the IAM settings
 * information structure. If the forceIt parameter is set, and if no records
 * are available, the first record will be zeroed and returned.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   config      Pointer to buffer with IAM configuration information
 * @param   forceIt     Grab record zero if nothing else is available
 *
 * @return NULL             No unused record was found
 * @return pointer          Pointer to unused interface configuration
*ad*/
NaIamParams_t * customizeIamFindUnusedInterfaceConfig(NaIamParamsInfo_t * config, BOOLEAN forceIt)
{
    int idx;
    NaIamParams_t *result = NULL;
    static NaIamParams_t zero;

    /* added this to remove GNU initialization warning. */
    memset((void*) &zero, 0, sizeof(zero));

    if (config->version == NA_IAM_CONFIG_VERSION)
    {
        for (idx = 0; idx < NA_IAM_INTERFACE_MAX; idx++)
        {
            if (config->iamParams[idx].isConfigValid)
            {
                config->iamParams[idx] = zero;
                result = &config->iamParams[idx];
                break;
            }
        }
    }
    else
    {
        config->version = NA_IAM_CONFIG_VERSION;
        for (idx = 0; idx < NA_IAM_INTERFACE_MAX; idx++)
        {
            config->iamParams[idx] = zero;
        }
        result = &config->iamParams[idx];
    }

    if ((result == NULL) && (forceIt))
    {
        config->iamParams[0] = zero;
        result = &config->iamParams[0];
    }

    return result;
}


/*ad*
 * This function reads the development board configuration setings from NVRAM
 * and stores it into a shared buffer.  This function assumes that the semaphore
 * that protects the shared configuration buffer from reentrant
 * access has already been acquired.  The values are read into the shared
 * buffer. This is a private helper function and should not be called by the
 * application
 *
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @return BP_SUCCESS           Success
 * @return BP_FAILURE           Unable to read NVRAM
 * @return BP_WRONG_VERSION     Configuration version field is incorrect
*ad*/
static int readConfig(void)
{
    int result = BP_SUCCESS;

    customizeReadDevBoardParams (&boardParamsBuffer);

    if (boardParamsBuffer.iamParamsInfo.version != NA_IAM_CONFIG_VERSION)
    {
        result = BP_WRONG_VERSION;
    }

    return result;
}

/*ad*
 * This function reads the entire IAM configuration structure from NVRAM and copies it into
 * the buffer passed into this routine.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   config  Pointer to buffer to hold IAM configuration record read from
 *                  NVRAM.
 *
 * @return BP_SUCCESS           Success
 * @return BP_FAILURE           Unable to read NVRAM
 * @return BP_WRONG_VERSION     Configuration version field is incorrect
*ad*/
int customizeIamGetConfig(NaIamParamsInfo_t * config)
{
    int result = BP_SUCCESS;

    IAM_LOCK();

    NA_ASSERT(config != NULL);

    result = readConfig ();

    if ((result == BP_SUCCESS) || (result == BP_WRONG_VERSION))
    {
        memcpy(config, &boardParamsBuffer.iamParamsInfo, sizeof *config);
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function reads the IAM board parameters into the shared buffer and then finds the
 * interface record for the indicated interface.  This function assumes
 * that the semaphore has already been gotten. This is a private helper function and
 * should not be called by the application.
 *
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example, "eth0" or
 *                  "eth0:0". The string is case sensitive.
 *
 * @return NULL     No configuration for indicated interface
 * @return otherwise Pointer to record in shared buffer with interface configuration
*ad*/
static NaIamParams_t * getInterfaceConfig(char const * ifname)
{
    NaIamParams_t *result = NULL;
    int idx;

    if (readConfig() == BP_SUCCESS)
    {
        for (idx = 0; idx < NA_IAM_INTERFACE_MAX; idx++)
        {
            if (boardParamsBuffer.iamParamsInfo.iamParams[idx].isConfigValid)
            {
                if (strcmp(boardParamsBuffer.iamParamsInfo.iamParams[idx].ifname, ifname) == 0)
                {
                    result = &boardParamsBuffer.iamParamsInfo.iamParams[idx];
                    break;
                }
            }
        }
    }

    return result;
}

/*ad*
 * This function is called before writing to an interface's
 * configuration record. This function reads the IAM board parameters into the
 * shared buffer and finds the record for the indicated interface.  If the
 * function can't find the record, then it finds an unused record and zeroes
 * it in preparation to write new values to all or part of it. This is a private
 * helper function and should not be called by the application.
 *
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 *
 * @return NULL     No room for configuration
 * @return otherwise Pointer to record in shared buffer with interface configuration
*ad*/
static NaIamParams_t * getInterfaceConfigToWrite(char const * ifname)
{
    NaIamParams_t *result = NULL;
    int idx;

    if (readConfig() == BP_SUCCESS)
    {
        result = getInterfaceConfig(ifname);
        if (result == NULL)
        {
            /*
             * If we couldn't find an existing record, then look for an empty one.
             */
            for (idx = 0; idx < NA_IAM_INTERFACE_MAX; idx++)
            {
                if (!boardParamsBuffer.iamParamsInfo.iamParams[idx].isConfigValid)
                {
                    result = &boardParamsBuffer.iamParamsInfo.iamParams[idx];
                    *result = defaultUnusedInterfaceConfig;
                    result->isEnabled = TRUE;
                    result->isConfigValid = TRUE;
                }
            }
        }
    }

    return result;
}

/*ad*
 * This function writes the IAM configuration values for a single interface into NVRAM.
 * The configuration data is supplied in a buffer that is provided by the caller.
 * If the indicated interface already has a configuration, then the old
 * configuration record is overwritten. Otherwise, a new interface configuration
 * record is added to the NVRAM structure if space is available.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to write the configuration record for. For example, "eth0" or
 *                  "eth0:0". The string is case sensitive.
 * @param   config  Pointer to buffer to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to write NVRAM
 * @return BP_FULL          There is no record for a new configuration record
*ad*/
int customizeIamSetInterfaceConfig(char const * ifname, NaIamParams_t const * config)
{
    int result = BP_FULL;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfigToWrite(ifname);

    if (interfaceConfig)
    {
        memcpy (interfaceConfig, config, sizeof *interfaceConfig);
        result = customizeWriteDevBoardParams(&boardParamsBuffer);
    }

    IAM_UNLOCK();

    return result;
}

/*ad*
 * This function reads the static IP configuration values for a single interface into a buffer
 * that is supplied by the caller.  The interface is identified by the ifname parameter.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to buffer to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to read NVRAM
 * @return BP_NO_RECORD     There is no record for the indicated interface
 * @return BP_WRONG_VERSION Configuration version field is incorrect
*ad*/
int customizeIamGetStaticConfig(char const * ifname, NaIamStaticParams_t * config)
{
    int result = BP_NO_RECORD;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfig(ifname);

    if (interfaceConfig)
    {
        memcpy (config, &interfaceConfig->staticParams, sizeof *config);
        result = BP_SUCCESS;
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function writes the static IP configuration values for a single interface into NVRAM.
 * The configuration data is supplied in a buffer that is provided by the caller.
 * If the indicated interface already has a configuration, then the old
 * configuration record is overwritten.  Otherwise, a new interface configuration
 * record is added to the NVRAM structure if space is available.
 *
 * The routine fails if no configuration for the interface exists.  In
 * this case, you can use @link customizeIamGetDefaultInterfaceConfig and
 * @link customizeIamSetInterfaceConfig to create a configuration record for the
 * interface, and then call this routine again to update it.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to write the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to buffer to read configuration values into
 *
 * @return BP_SUCCESS        Success
 * @return BP_FAILURE        Unable to write NVRAM
 * @return BP_FULL           There is no record for a new configuration record
 * @return BP_WRONG_VERSION  Version field in current record is incorrect
*ad*/
int customizeIamSetStaticConfig(char const * ifname, NaIamStaticParams_t const * config)
{
    int result = BP_FULL;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfigToWrite(ifname);

    if (interfaceConfig)
    {
        memcpy (&interfaceConfig->staticParams, config, sizeof interfaceConfig->staticParams);
        result = customizeWriteDevBoardParams(&boardParamsBuffer);
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function reads the DHCP configuration values for a single interface into a buffer
 * that is supplied by the caller.  The interface is identified by name.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to buffer that to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to read NVRAM
 * @return BP_NO_RECORD     There is no record for the indicated interface
 * @return BP_WRONG_VERSION     Version field in current record is incorrect
*ad*/
int customizeIamGetDhcpConfig(char const * ifname, NaIamDhcpParams_t * config)
{
    int result = BP_NO_RECORD;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfig(ifname);

    if (interfaceConfig)
    {
        memcpy (config, &interfaceConfig->dhcpParams, sizeof *config);
        result = BP_SUCCESS;
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function writes the DHCP configuration values for a single interface into NVRAM.
 * The configuration data is supplied in a buffer that is provided by the caller.
 * If the indicated interface already has a configuration, then the old
 * configuration record is overwritten.  Otherwise, a new interface configuration
 * record is added to the NVRAM structure if space is available.
 *
 * The routine fails if no configuration for the interface exists.  In
 * this case, you can use @link customizeIamGetDefaultInterfaceConfig and
 * @link customizeIamSetInterfaceConfig to create a configuration record for the
 * interface, and then call this routine again to update it.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A null terminated string that contains the name of the interface
 *                  to write the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to buffer to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to write NVRAM
 * @return BP_FULL          There is no record for a new configuration record
 * @return BP_WRONG_VERSION     Version field in current record is incorrect
*ad*/
int customizeIamSetDhcpConfig(char const * ifname, NaIamDhcpParams_t const * config)
{
    int result = BP_FULL;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfigToWrite(ifname);

    if (interfaceConfig)
    {
        memcpy (&interfaceConfig->dhcpParams, config, sizeof interfaceConfig->dhcpParams);
        result = customizeWriteDevBoardParams(&boardParamsBuffer);
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function reads the Auto IP configuration values for a single interface into a buffer
 * that is supplied by the caller.  The interface is identified by name.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to read the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to the buffer to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to read NVRAM
 * @return BP_NO_RECORD     There is no record for the indicated interface
 * @return BP_WRONG_VERSION     Version field in current record is incorrect
*ad*/
int customizeIamGetAutoipConfig(char const * ifname, NaIamAutoipParams_t * config)
{
    int result = BP_NO_RECORD;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfig(ifname);

    if (interfaceConfig)
    {
        memcpy (config, &interfaceConfig->autoipParams, sizeof *config);
        result = BP_SUCCESS;
    }

    IAM_UNLOCK();

    return result;
}


/*ad*
 * This function writes the Auto IP configuration values for a single interface into NVRAM.
 * The configuration data is supplied in a buffer that is provided by the caller.
 * If the indicated interface already has a configuration, then the old
 * configuration record is overwritten.  Otherwise, a new interface configuration
 * record is added to the NVRAM structure if space is available.
 *
 * The routine fails if no configuration for the interface exists.  In
 * this case, you can use @link customizeIamGetDefaultInterfaceConfig and
 * @link customizeIamSetInterfaceConfig to create a configuration record for the
 * interface, and then call this routine again to update it.
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 *
 * @param   ifname  A nul-terminated string that contains the name of the interface
 *                  to write the configuration record for.  For example, "eth0" or
 *                  "eth0:0".  The string is case sensitive.
 * @param   config  Pointer to buffer to read configuration values into
 *
 * @return BP_SUCCESS       Success
 * @return BP_FAILURE       Unable to write NVRAM
 * @return BP_FULL          There is no record for a new configuration record
 * @return BP_WRONG_VERSION     Version field in current record is incorrect
*ad*/
int customizeIamSetAutoipConfig(char const * ifname, NaIamAutoipParams_t const * config)
{
    int result = BP_FULL;
    NaIamParams_t *interfaceConfig = NULL;

    IAM_LOCK();

    NA_ASSERT(config != NULL);
    NA_ASSERT(ifname != NULL);
    NA_ASSERT(strlen(ifname));

    interfaceConfig = getInterfaceConfigToWrite(ifname);

    if (interfaceConfig)
    {
        memcpy (&interfaceConfig->autoipParams, config, sizeof interfaceConfig->autoipParams);
        result = customizeWriteDevBoardParams(&boardParamsBuffer);
    }

    IAM_UNLOCK();

    return result;
}

