#ifndef IAM_NETOS_HH
#define IAM_NETOS_HH

#include "eth_api.h"

/*ad*
 * The Internet Address Manager (IAM) controls the process of acquiring and configuring
 * IPv4 and stateless auto-configured IPv6 addresses. By default, IAM provides support for static,
 * DHCPv4, and Auto IP IP address acquisition methods and
 * allows a user defined IPv4 method to be incorporated into the IAM framework where it can coexist with 
 * the supported methods or function alone. For IPv6, IAM supports only stateless auto-configured 
 * addresses, the acquisition of which begins automatically when running in dual-stack mode.
 *
 * IAM gives the user control over the acquisition methods used on network interfaces.
 * Settings for individual methods are stored in NVRAM and 
 * read every time a method is started or restarted. Individual settings include, but are not limited to, 
 * Address Conflict Detection (ACD) and whether an acquisition method is enabled for an interface.
 * When more than one method is used on a single, non-multihomed interface, IAM allows
 * assigning of priorities to each method. Alternatively, different methods can run on an interface
 * through the use of multihoming. IAM supports up to four multihomes on a single network interface. 
 * 
 * An application can be notified of various IAM events through the use of IAM's callback
 * mechanism. IAM notifications include such events as the acquisition and loss of an IP address or
 * DHCP server configuration offers. If an application callback function is not provided by the application,
 * IAM uses defaults rules to handle specific events. These rules are described later in this section.
 *
 * For NET+OS version 6.3 and earlier users, IAM is the replacement for the ACE API, which has been
 * obsoleted in version 7.0.
 *
 * <section> Starting IAM </section>
 *
 * This section describes IAM's default start-up procedure, which can be customized
 * by the user as needed. Once started, NET+OS processes all IAM events through a supplied callback
 * function, @link customizeIamEventCallback, defined in file iamCallbacks.c. This function is
 * described here in detail and may be modified per system requirements. NET+OS starts IAM in function,
 * @link customizeIamStart, also defined in iamParams.c and called from the ROOT task. This function is 
 * described first in order to demonstrate IAM's initialization procedure.
 *
 * <example>
 * int customizeIamStart(void) 
 * {
 *     NaIamParamsInfo_t * iam_info;
 *     int result = 0, j = 0;
 *     NaIfInterfaceConfigureParams_t cfg_params;
 *
 *     iam_info = (NaIamParamsInfo_t *)malloc(sizeof *iam_info);
 *     if (iam_info == NULL)
 *     {
 *         printf("customizeIamStart: malloc() failed!\n");
 *         result = -1;
 *         goto exit;
 *     }
 * 
 *     // Read the whole IAM NVRAM structure
 *     if (customizeIamGetConfig(iam_info) == BP_FAILURE)
 *     {
 *         printf("customizeIamStart: customizeIamGetConfig() failed!\n");
 *         result = -1;
 *         goto exit;
 *     }
 * 
 *     for (j = 0; j < NA_IAM_INTERFACE_MAX; j++)
 *     {
 *         // Only start IAM on an interface that has been enabled for IAM.  
 *         if (iam_info->iamParams[j].isEnabled)
 *         {
 *             // Retrieve interface specific parameters. 
 *             if (naIfConfigGetInterfaceParams(iam_info->iamParams[j].ifname,
 *                                              &cfg_params) != NA_SUCCESS)
 *             {
 *                 printf("customizeIamStart: naIfConfigGetInterfaceParams failed!\n");
 *                 result = -1;
 *                 goto exit;
 *             }        
 * 
 *             if (naIamStart(iam_info->iamParams[j].ifname,
 *                            method_list,
 *                            cfg_params.if_config_flags,
 *                            cfg_params.buffers_per_frame,  
 *                            NULL,
 *                            customizeIamEventCallback) != NA_IAM_STATUS_SUCCESS)
 *             {
 *                 printf("customizeIamStart: naIamStart() failed for interface %s\n",
 *                                                      iam_info->iamParams[j].ifname);
 *                 result = -1;
 *                 goto exit;
 *             }
 *         }
 *     }
 * 
 * exit:
 *     if (iam_info)
 *     {
 *         free(iam_info);
 *     }
 *     return result;
 * }
 * </example>
 *
 * 1. The first task @link customizeIamStart performs is the retrieval of IAM NVRAM settings for all network
 * interfaces by calling @link customizeIamGetConfig. An interface enabled for IAM must have the 
 * "isEnabled" variable set to TRUE and have
 * a valid interface name stored in the ifname member array. Interface names must be in the
 * "(eth\wln)x:x" format, where "eth0" represents the first Ethernet interface and "wln0" the first
 * wireless interface. "eth0:0" stands for the second multihome of the first ethernet interface,
 * "eth0:1" for the third, and so on, up to a maximum of four multihomes per interface.
 * 
 * 2. The second task performed in @link customizeIamStart is the retrieval of interface specific
 * parameters, previously registered during the driver installation process, by calling 
 * @link naIfConfigGetInterfaceParams. The two parameters of 
 * interest to IAM are TCP/IP stack interface configuration flags and the number of scatter buffers
 * supported by the the underlying device. Because these parameters are platform dependent, they should
 * never be modified by the application.
 *
 * 3. IAM is started next for each enabled interface with a call to @link naIamStart. The first argument
 * to this function is the interface name retrieved from NVRAM in step one. The second argument
 * is a list of IAM IPv4 acquistion methods defined at the top of file iamCallbacks.c and reproduced below:
 *
 * <example>
 * static const NaIamMethodInfo_t method_list[] = \
 *                          {{NA_IAM_DEFAULT_STATIC_METHOD_CB, NULL, NA_IAM_METHOD_STATIC},
 *                           {NA_IAM_DEFAULT_DHCP_METHOD_CB,   NULL, NA_IAM_METHOD_DHCP},
 *                           {NA_IAM_DEFAULT_AUTOIP_METHOD_CB, NULL, NA_IAM_METHOD_AUTOIP},
 *                           {NA_IAM_NULL_METHOD_CB,           NULL, NA_IAM_METHOD_NONE}};
 * </example>
 *
 * This list comprises IPv4 acquisition methods IAM attempts to use to acquire an IPv4
 * address; however, the methods actually used depend on NVRAM settings as described later
 * in this section.
 * 
 * The order of the list determines the priority assigned to the methods with the above definition 
 * making static the highest priority, followed by DHCPv4 and Auto IP. Priority determines how IAM treats
 * acquired addresses. For example, the above priority scheme ensures that static addresses
 * will always be configured even when a previously acquired DHCPv4 or Auto IP address has been
 * configured on an interface. In this case, the lower priority address is removed from
 * the interface and replaced with the newly acquired static address. Consequently, when a 
 * static address is configured first on an interface and a lower priority address is obtained
 * after the fact, the lower priority address is ignored.
 *
 * The first member of the @link NaIamMethodInfo_t structure is the method callback called by the 
 * @link naIamStart function with
 * one of three commands: NA_IAM_COMMAND_INITIALIZE, NA_IAM_COMMAND_ACQUIRE,
 * and NA_IAM_COMMAND_RELEASE. The second member is the context data passed in as an argument 
 * to the method callback. The third member is the the method identifier. The default method
 * callbacks do not use any context arguments. A user defined method callback can be included in this 
 * list in the desired priority slot along with the NA_IAM_METHOD_USER identifier. The last
 * element of the list has to be set to NA_IAM_NULL_METHOD_CB to mark its end.   
 * 
 * Function @link naIamStart calls each callback with the NA_IAM_COMMAND_INITIALIZE command.
 * In response to this command, each callback reads IAM
 * NVRAM settings for the specific acquisition method by calling @link customizeIamGetSettingsCallback
 * and then calls @link naIamEnable when the acquisition method is enabled in NVRAM or @link naIamDisable
 * when disabled. @link naIamEnable in turn calls each method callback with the NA_IAM_COMMAND_ACQUIRE
 * command. Here, again, each callback reads NVRAM settings and, if enabled, begins the 
 * address acquisition process with configuration parameters retrieved from NVRAM and file bsp.h. 
 * IAM configuration parameters defined in bsp.h are described below in section "IAM Configuration".
 * Once a method acquires its address,
 * function @link naIamAcquire is called to attempt to configure the interface with the obtained address.
 * Whether the configuration offered by @link naIamAcquire is actually used depends on the 
 * configured address and the priority of the method that was used to acquire it. In the
 * case where an address has not been configured on an interface, the first acquisition method 
 * that acquires an address is allowed to configure it.
 *
 * The third and fourth arguments to @link naIamStart are the platform dependent parameters 
 * retrieved in step two above. The fifth argument is the context data passed into the callback function @link
 * customizeIamEventCallback. This callback function is registered in the sixth argument. No context data is
 * used by the default method callbacks; however, one use for this parameter might be a pointer to a
 * list of callback functions, registered by applications when opening network connections. 
 * This list can be traversed and each callback can be called in order to direct the registered applications
 * to end open sessions gracefully when an event such as the loss of an ip address occurs.       
 *                 
 * <section> Acquisition of Stateless Auto-configured IPv6 Addresses </section>
 *
 * @link naIamStart attempts to configure a stateless link-local auto-configured IPv6 address for the interface
 * specified by the first argument. When IAM is started for several virtual interfaces
 * such as "eth0" and "eth0:0", auto-configuration is performed only once for the physical
 * interface.
 *
 * Because of how IPv6 stateless address auto-configuration works, IPv6 needs access to the interface 
 * ID. The interface ID is always 64 bits long ([RFC2373].R2.4:20), and is used as the low-order 64
 * bits of a stateless auto-configured IPv6 address. When the interface link-layer type is Ethernet,
 * interface ID is automatically derived from the IEEE 48-bit MAC address assigned to the device.
 *
 * IAM uses Duplicate Address Detection (DAD) to test all auto-configured addresses for
 * initial address conflicts before configuring them on an interface. If the initial MAC address derived
 * link-local address is in conflict before being configured, IAM derives a random interface ID to 
 * form a new link-local address and performs DAD on this address before configuring it on an interface.
 * This auto-recovery mechanism is repeated until a valid link-local address is found. Each time 
 * DAD fails for the link-local address, IAM calls the application callback passed into @link naIamStart
 * in the "app_cb" parameter with the NA_IAM_ADDR_INITIAL_CONFLICT event. IAM begins auto-recovery
 * immediately after this callback returns. For all other stateless auto-configured addresses, IAM
 * simply discards them when they fail DAD and calls the application callback with the aforementioned
 * event.
 *
 * <section> IAM Configuration </section>
 *
 * Most configuration parameters needed by IAM are retrieved by function @link customizeIamGetSettingsCallback,
 * defined in file iamCallbacks.c. The default implementation of this function, reproduced below, retrieves 
 * the configuration from NVRAM for the specified interface/multihome pair and acquisition method.
 *
 * <example>
 * NaIamStatus_t customizeIamGetSettingsCallback(const char * ifname, int method, NaIamCfg_t * cfg)
 * { 
 *     NaIamStatus_t status = NA_IAM_STATUS_SUCCESS;
 * 
 *     NA_ASSERT((ifname != NULL) && (cfg != NULL)); 
 *    
 *     if ((ifname == NULL) || (cfg == NULL))
 *     {
 *         status = NA_IAM_STATUS_ERROR;
 *         goto done;
 *     }     
 *     
 *     // Retrieve IAM NVRAM settings for IAM.
 *     switch(method)
 *     {
 *         case NA_IAM_METHOD_STATIC:
 *         {
 *             NaIamStaticParams_t staticParams;
 * 
 *             if (customizeIamGetStaticConfig(ifname, &staticParams) != BP_SUCCESS)
 *             {
 *                 status = NA_IAM_STATUS_ERROR; 
 *                 goto done;
 *             }
 * 
 *             cfg->cfg.staticCfg.isEnabled    = staticParams.isEnabled;
 *             cfg->cfg.staticCfg.ipAddress    = staticParams.ipAddress;
 *             cfg->cfg.staticCfg.subnetMask   = staticParams.subnetMask;
 *             cfg->cfg.staticCfg.gateway      = staticParams.gateway;
 *             cfg->cfg.staticCfg.primaryDns   = staticParams.primaryDns;
 *             cfg->cfg.staticCfg.secondaryDns = staticParams.secondaryDns;
 *             cfg->cfg.staticCfg.initialAcd   = BSP_ENABLE_ADDR_CONFLICT_DETECTION;
 *             cfg->cfg.staticCfg.ongoingAcd   = BSP_ENABLE_ONGOING_ADDR_CONFLICT_DETECTION;          
 *         }
 *         break;
 * 
 *         case NA_IAM_METHOD_DHCP:
 *         {
 *             NaIamDhcpParams_t dhcpParams;
 * 
 *             if (customizeIamGetDhcpConfig(ifname, &dhcpParams) != BP_SUCCESS)
 *             {
 *                 status = NA_IAM_STATUS_ERROR; 
 *                 goto done;
 *             }
 * 
 *             cfg->cfg.dhcpCfg.isEnabled = dhcpParams.isEnabled;
 *             memcpy(cfg->cfg.dhcpCfg.optionsBuffer,
 *                    dhcpParams.optionsBuffer,
 *                    dhcpParams.optionsLength);
 *             cfg->cfg.dhcpCfg.optionsLength = dhcpParams.optionsLength;
 *             cfg->cfg.dhcpCfg.ongoingAcd = 
 *                            BSP_ENABLE_ONGOING_ADDR_CONFLICT_DETECTION;
 * 
 *                     
 *         }
 *         break;
 * 
 *         case NA_IAM_METHOD_AUTOIP:
 *         {
 *             NaIamAutoipParams_t autoipParams;
 * 
 *             if (customizeIamGetAutoipConfig(ifname, &autoipParams) != BP_SUCCESS)
 *             {
 *                 status = NA_IAM_STATUS_ERROR; 
 *                 goto done;
 *             }
 *             
 *             cfg->cfg.autoipCfg.isEnabled = autoipParams.isEnabled; 
 *              
 *         }
 *         break; 
 * 
 *         default:
 *             NA_ASSERT(0);
 *             status =  NA_IAM_STATUS_ERROR;
 *             goto done;        
 *     }
 * 
 *     //These are common to all acquisition methods. 
 *     cfg->probeInterval         = BSP_DEFAULT_ETH_PROBE_INTERVAL_MS;
 *     cfg->numProbes             = BSP_DEFAULT_ETH_NUM_ADDR_PROBES;
 *     cfg->numAnnouncements      = BSP_DEFAULT_ETH_NUM_ADDR_ANNOUNCEMENTS;  
 *     cfg->announcementsInterval = BSP_DEFAULT_ETH_ANNOUNCE_INTERVAL_MS; 
 * 
 * done:
 *     return status;
 * }
 * </example>
 *
 * The static configuration parameters consist of whether or not the static method is enabled for the interface,
 * the IPv4 address, subnet mask, default gateway, primary and secondary dns servers, and two boolean
 * variables that determine if IAM should perform initial and ongoing address conflict detection. These 
 * two variables are set to macros BSP_ENABLE_ADDR_CONFLICT_DETECTION and 
 * BSP_ENABLE_ONGOING_ADDR_CONFLICT_DETECTION respectively, both defined in file bsp.h. Additional
 * configuration parameters, common to all acquisition methods, are assigned at the bottom of this function.
 * They include the number of ARP probes to send during initial address conflict detection and the time
 * interval between these probes, the number of ARP announcements to send after an IPv4 address is configured
 * and the time interval between them. Here, again, these parameters are assigned the following macros defined in 
 * file bsp.h: BSP_DEFAULT_ETH_PROBE_INTERVAL_MS, BSP_DEFAULT_ETH_NUM_ADDR_PROBES, 
 * BSP_DEFAULT_ETH_NUM_ADDR_ANNOUNCEMENTS, and BSP_DEFAULT_ETH_ANNOUNCE_INTERVAL_MS. IAM always 
 * sends one ARP announcement after an IPv4 address has been configured. Setting the number of announcements
 * to one, for example, will force IAM to send two ARP announcements. If initial address conflict detection
 * is enabled and the number of ARP probes and the probe interval time are both set to zero, IAM sends four
 * ARP probes at 200ms intervals by default.  
 *
 * DHCPv4 configuration parameters consist of whether or not the DHCPv4 method is enabled for the interface,
 * if ongoing address conflict detection should be performed, and the raw DHCPv4 options buffer along with its
 * length in bytes. IAM always performs initial address conflict detection for DHCPv4, using ARP probe 
 * settings assigned at the bottom of this function. Similarly to the static method, if
 * the number of ARP probes and the probe interval time are set to zero, IAM sends four
 * ARP probes at 200ms intervals by default.
 *
 * The Auto IP acquisition method also requires a boolean parameter that determines if it
 * is enabled for the specified interface. Initial and ongoing address conflict detection are always performed
 * for this method with ARP probe and announcement parameters assigned in the same manner as for the other
 * acquisition methods.
 *
 * @link customizeIamGetSettingsCallback is called by the default IAM methods at various stages of operation.
 * As mentioned earlier in section "Starting IAM", the first time this function is called is from function
 * @link naIamStart when it calls each acquisition method callback with the NA_IAM_COMMAND_INITIALIZE
 * command. Each callback in turn calls @link customizeIamGetSettingsCallback to determine if its method
 * is enabled for the specified interface/multihome pair. If enabled, each callback calls function 
 * @link naIamEnable to enable the method and start its IPv4 address acquisition process. If disabled, 
 * @link naIamDisable is called instead to disable the method. @link naIamEnable calls each method 
 * callback with the NA_IAM_COMMAND_ACQUIRE command. @link customizeIamGetSettingsCallback
 * is called again by all enabled method callbacks to retrieve configuration parameters needed for the 
 * acquisition process. For example, the DHCP method callback starts the DHCP client with the provided
 * options buffer and sends a request packet. Once an offer is accepted, the DHCP method then
 * performs initial address conflict detection using ARP probe parameters retireved from NVRAM. If the
 * acquired address is not in conflict, @link naIamAcquire is called from the context of the TCP/IP stack's
 * timer task with the newly obtained DHCP configuration in order to attempt to configure an interface.
 * @link customizeIamGetSettingsCallback is called again to determine if during the time of the initial
 * conflict detection the DHCP method was disabled and, if it was not, to determine if the NVRAM settings require
 * IAM to perform ongoing conflict detection. If the method was disabled during the conflict detection stage,
 * the DHCP client is instructed to release the acquired configuration and @link naIamDisable is called to
 * disable the DHCP method.
 *
 * <section> Initial and Ongoing Address Conflict Detection </section>
 *
 *           
 *     
 * <section> IAM Core Functions </section>
 *
 * This section describes IAM's core public API. IAM's core functionality
 * is implemented in the TCP/IP library, libtcpip.a, and it's public functions begin with the "naIam"
 * prefix. Functions beginning with the "customizeIam" prefix are part of the bsp library, libbsp.a, and their 
 * source code is available for customization.
 *
 * <section> naIamStart </section> 
 *
 * @link naIamStart has to be called for each interface/multihome pair and, as described earlier, 
 * calls each method callback with the NA_IAM_COMMAND_INITIALIZE command. This command forces each
 * callback to either call @link naIamEnable or @link naIamDisable depending on NVRAM settings retrieved by
 * @link customizeIamGetSettingsCallback. @link naIamStart also begins the acquisition of the 
 * stateless auto-configured link-local IPv6 address and performs auto-recovery if the address is found
 * to be in initial conflict. @link naIamStart does not call a default callback for the
 * NA_IAM_METHOD_IPV6_AUTOCFG method as one does not exist.      
 *
 * <section> naIamEnable </section>
 *
 * For IPv4, @link naIamEnable enables the method for which it is called and calls the method's callback function
 * with the NA_IAM_COMMAND_ACQUIRE command. The callback is only called, however, when an address has not been
 * configured on the interface or the method for which this function is called is higher priority than 
 * the currently configured one. This command forces each default method callback to
 * read IAM NVRAM settings by calling @link customizeIamGetSettingsCallback and start the acquisition
 * process using the retrieved settings. If a default method is using initial address conflict detection,
 * or as in the case of DHCP, it begins the acquisition process by first sending a DHCP request packet,
 * the TCP/IP stack is responsible for calling into IAM when a conflict is detected, ARP probes expire,
 * or a DHCP offer is received. Regardless of the asynchronous event, the stack calls either @link naIamAcquire or 
 * @link naIamRelease to attempt to configure an address or release the acquisition method respectively.
 *
 * For IPv6, @link naIamEnable behaves very differently from IPv4. When @link naIamEnable is called with the 
 * NA_IAM_METHOD_IPV6_AUTOCFG method and "ethx:3"(multihome index 4) or "wlnx:3" as the argument to "ifname",
 * stateless auto-configuration of the link-local IPv6 address is started. The reason for the fourth multihome
 * has to do with the fact that IPv6 addresses are stored at multihome index NA_MAX_HOMES_PER_IF and above,
 * with the IPv6 address at multihome index NA_MAX_HOMES_PER_IF(4) being the auto-configured link-local
 * address. If @link naIamEnable is called for IPv6 with a multihome index smaller or greater than
 * NA_MAX_HOMES_PER_IF, an error is returned. 
 *
 * There is no acquisition method callback that, by default, calls @link naIamEnable for IPv6. This function may
 * be called by the application when an auto-configured link-local IPv6 address has been removed
 * from an interface. Consequently, the IPv6 portion of an interface is considered closed when it does
 * not have a link-local address.
 *
 * <section> naIamDisable </section>
 *
 * For IPv4, @link naIamDisable calls the default method callbacks with the NA_IAM_COMMAND_RELEASE
 * command only when the method for which this function is called has been previously enabled and the 
 * currently configured address was obtained by the same method. A method can be disabled
 * without its callback being called with the NA_IAM_COMMAND_RELEASE command if the configured
 * address was acquired by a different method. When the
 * default method callbacks are called with the NA_IAM_COMMAND_RELEASE command, @link naIamRelease is called          
 * from each method callback to attempt to unconfigure the specified interface. @link naIamRelease can only
 * unconfigure an interface when the method for which it is called was used to configure it.
 *
 * When @link naIamRelease unconfigures an interface, it restarts the acquisition method for all
 * enabled methods, including itself, by calling each method's callback with the NA_IAM_COMMAND_ACQUIRE command.
 * This is needed since an interface is left without an address when @link naIamRelease unconfigures it.
 *
 * @link naIamDisable is called by the default method callbacks when NVRAM settings obtained by calling
 * @link customizeIamGetSettingsCallback indicate that a method is disabled.             
 *
 * For IPv6, @link naIamDisable behaves very differently from IPv4. When @link naIamDisable is called with the 
 * NA_IAM_METHOD_IPV6_AUTOCFG method and "ethx:3"(multihome index 4) or "wlnx:3" as the argument to "ifname",
 * the auto-configured link-local IPv6 address is unconfigured from the interface . The reason for the fourth multihome
 * has to do with the fact that IPv6 addresses are stored at multihome index NA_MAX_HOMES_PER_IF and above,
 * with the IPv6 address at multihome index NA_MAX_HOMES_PER_IF(4) being the auto-configured link-local
 * address. If @link naIamDisable is called for IPv6 with a multihome index smaller or greater than
 * NA_MAX_HOMES_PER_IF, an error is returned. Unconfiguring the link-local address from the IPv6 portion of the 
 * interface disables it because at the very minimum a link-local IPv6 address must be present in order for the 
 * interface to be configured.
 *
 * Similarly to @link naIamEnable, there is no acquisition method callback that, by default, calls 
 * @link naIamDisable for IPv6. This function may be called by the application when the auto-configured 
 * link-local IPv6 is found to be in conflict after it had been used to configure an interface.
 *
 * <section> naIamRelease </section>
 *
 * For IPv4, @link naIamRelease unconfigures an interface and restarts the acquisition method for all
 * enabled methods, including itself, by calling each method's callback with the NA_IAM_COMMAND_ACQUIRE 
 * command. The only way that @link naIamRelease can unconfigure an interface and call all enabled method
 * callbacks, however, is if the method used to configure the interface is called for @link naIamRelease. 
 *
 * Only the default DHCP method calls @link naIamRelease when the DHCP client looses its IPv4 address
 * due to lease expiration. When this event occurs, the default DHCP callback is forced to restart 
 * its acquistion process when it is called with the NA_IAM_COMMAND_ACQUIRE command.
 * 
 * Before unconfiguring the IPv4 address and restarting the acquisition process for all enabled
 * methods, @link naIamRelease also calls the application callback passed into @link naIamStart with the 
 * NA_IAM_ADDR_LOST event. Once this function returns, the interface is unconfigured.
 *
 * For IPv6, @link naIamRelease behaves very differently from IPv4. When @link naIamRelease is called with the 
 * NA_IAM_METHOD_IPV6_AUTOCFG method for interfaces with multihome indexes greater than or equal to
 * NA_MAX_HOMES_PER_IF(4), the corresponding auto-configured addresses are unconfigured from the interface.
 * For example, calling this function with the "eth0:4" interface unconfigures the second 
 * auto-configured IPv6 address on the first Ethernet interface. Calling with interface name "eth0:3",
 * disables the IPv6 portion of the interface since the fourth multihome index is used to store the
 * link-local address, which must be present at all times.
 *
 * Because @link naIamRelease is not called by any default method callbacks for IPv6 and is meant to
 * be called by the application only, it does not call the application callback with the
 * NA_IAM_ADDR_LOST event as it does for IPv4. The application, before calling this function for 
 * IPv6, should make sure that open sessions are closed gracefully before unconfiguring an IPv6
 * address in use. For IPv6, this function is intended to be used when an auto-configured IPv6 address
 * is found to be in conflict with another node on the same link after it was used to configure the 
 * interface.
 *
 * <section> naIamAcquire </section>
 *
 * @link naIamAcquire can be used to configure IPv4 addresses only. This function is called by each 
 * default method once configuration parameters have been obtained to attempt to configure an interface.
 * The interface is configured only if it is unconfigured or the configured method is lower 
 * priority than that for which this function is called. When initial address conflict 
 * detection or the DHCP default method is used, this function is called from the context of the TCP/IP
 * stack's timer task. Before this function is called, the default methods call 
 * @link customizeIamGetSettingsCallback to retrieve the number of ARP announcements to send after
 * the interface is configured and to enable ongoing address conflict detection which is done
 * by setting the appropriate flag in the "flags" parameter.
 *
 * <section> naIamGetCurrentMethod </section>
 *
 * @link naIamGetCurrentMethod can be used to determine the IPv4 method that was used to configure
 * the specified interface.                                                  
 *
 * <section> IAM Event Handling </section>                   
 *
 * The default application callback, @link customizeIamEventCallback, reproduced below and passed in as the "app_cb"
 * argument of function @link naIamStart is used to handle various events that occur during IAM's operation.
 * When "app_cb" is set to NULL, the application is not notified of any IAM events and default actions
 * are taken as detailed below.
 *
 * <example>
 * NaIamStatus_t customizeIamEventCallback(const char * ifname, int method, int event, NaIamAcquiredCfg_t * acquiredCfg, void * userData)
 * {
 * 
 *     NaIamStatus_t status = NA_IAM_STATUS_SUCCESS; // Assume success.
 *     static int configured = 0;
 *     char addrString[MAX_IP_ADDR_STR_LEN];
 *     char af;
 *     char *ip_addr;
 *     void * interface;
 *     unsigned multihome;
 * 
 *     naIfConfigGetInterfaceHandle(ifname, &interface, &multihome);
 *         
 *     (void)userData;
 * 
 *     switch(event)
 *     {
 *         case NA_IAM_ADDR_CONFIGURED: // Acquired IP address.
 *         {                
 * #ifdef IPV6_ENABLED
 *             // Only stateless auto-configured IPv6 addresses are
 *             // supported at this time. 
 *             if (method == NA_IAM_METHOD_IPV6_AUTOCFG)   
 *             {
 *                 // Register the IPv6 address. 
 *                 addr_cfg_acquired(interface, AF_INET6);
 *                 af = AF_INET6, 
 *                 ip_addr = (char *)&acquiredCfg->ipAddress.addr.ipv6.sin6_addr;
 *             }
 *             else 
 * #endif
 *             {
 *                 // Register the IPv4 address.
 *                 addr_cfg_acquired(interface, AF_INET);
 *                 af = AF_INET; 
 *                 ip_addr = (char *)&acquiredCfg->IPV4_ADDR(ipAddress);
 *             }
 * 
 *             // Convert address to ASCII.
 *             inet_ntop(af, ip_addr, addrString, MAX_IP_ADDR_STR_LEN);
 *  
 *             printf("IAM - Got %s IP address %s on interface %s\r\n",
 *                          iam_method_string[method], addrString, ifname);
 * 
 *             if (!configured) // Do only once. 
 *             {
 *                 // Determine if interface is configured.
 *                 if (addr_cfg_is_configured())
 *                 {
 *                     // Let the ROOT task know that we have configured all required
 *                     // ip addresses on an interface, which allows network 
 *                     // applications to come up. We require both v4 and v6
 *                     // addresses if running in dual stack mode.
 *                     NASetIPConfigureState(naIpStateConfigured);
 *                     configured = 1; 
 *                 }
 *             }      
 *         }
 *         break;
 * 
 *         case NA_IAM_ADDR_LOST: // Lost IP address.
 *         {
 * #ifdef IPV6_ENABLED
 *             if (method == NA_IAM_METHOD_IPV6_AUTOCFG)   
 *             {
 *                 // Register lost IPv6 address.
 *                 addr_cfg_lost(interface, AF_INET6); 
 *                 af = AF_INET6, 
 *                 ip_addr = (char *)&acquiredCfg->ipAddress.addr.ipv6.sin6_addr;
 *             }
 *             else
 * #endif
 *             {
 *                 // Register lost IPv6 address.
 *                 addr_cfg_lost(interface, AF_INET);
 *                 af = AF_INET; 
 *                 ip_addr = (char *)&acquiredCfg->IPV4_ADDR(ipAddress);
 *             }
 *             
 *             // Convert address to ASCII.
 *             inet_ntop(af, ip_addr, addrString, MAX_IP_ADDR_STR_LEN);
 * 
 *             printf("IAM - lost %s IP address %s on interface %s\r\n",
 *                        iam_method_string[method], addrString, ifname);
 *         }            
 *         break;
 * 
 *         // This event is informational only for IPv6 as all auto-configured 
 *         // addresses are never configured if found to be in initial conflict.
 *         // In the case of an auto-configured link-local scope IPv6 address
 *         // found to be in initial conflict, a random EUI64 Interface ID is
 *         // generated by IAM to form a new link-local address for the interface
 *         // after this function returns. 
 *         case NA_IAM_ADDR_INITIAL_CONFLICT:// Initial IP address conflict.
 *         {
 * #ifdef IPV6_ENABLED
 *             if (method == NA_IAM_METHOD_IPV6_AUTOCFG)   
 *             {
 *                 af = AF_INET6, 
 *                 ip_addr = (char *)&acquiredCfg->ipAddress.addr.ipv6.sin6_addr;
 *             }
 *             else
 * #endif
 *             {
 *                 af = AF_INET; 
 *                 ip_addr = (char *)&acquiredCfg->IPV4_ADDR(ipAddress);
 *             }
 * 
 *             inet_ntop(af, ip_addr, addrString, MAX_IP_ADDR_STR_LEN);
 * 
 *             printf("IAM - %s IP address %s on interface %s is in initial conflict!\r\n",
 *                                     iam_method_string[method], addrString, ifname);
 * 
 *             // If the IPv6 auto-configured link-local scope address is in 
 *             // conflict, a random EUI64 interface ID will be generated to configure
 *             // a new link local address. Other IPv6 auto-configured addresses are
 *             // never configured when they're in initial conflict.
 * #ifdef IPV6_ENABLED 
 *             if (method == NA_IAM_METHOD_IPV6_AUTOCFG &&
 *                 IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)ip_addr))
 *             {
 *                 printf("      A random EUI64 Interface ID will be generated.\r\n");  
 *             }
 *             else
 * #endif
 *             if (af == AF_INET)
 *             {
 *                 printf("      This address will not be used. \r\n");  
 *                 // By returning an error, the address in conflict is not 
 *                 // configured on the interface.     
 *                 status = NA_IAM_STATUS_ERROR;
 *             }
 *             else
 *             {
 *                 printf("      This auto-configured address will not be used. \r\n");
 *             }     
 *         }            
 *         break;
 * 
 *         case NA_IAM_ADDR_CONFLICT:// Ongoing IP address conflict.
 *         {
 * #ifdef IPV6_ENABLED
 *             if (method == NA_IAM_METHOD_IPV6_AUTOCFG)   
 *             {
 *                 af = AF_INET6, 
 *                 ip_addr = (char *)&acquiredCfg->ipAddress.addr.ipv6.sin6_addr;
 *             }
 *             else
 * #endif
 *             {
 *                 af = AF_INET; 
 *                 ip_addr = (char *)&acquiredCfg->IPV4_ADDR(ipAddress);
 *             }
 * 
 *             inet_ntop(af, ip_addr, addrString, MAX_IP_ADDR_STR_LEN);
 * 
 *             printf("IAM - %s IP address %s on interface %s is in conflict!",
 *                             iam_method_string[method], addrString, ifname);
 *         }            
 *         break;
 * 
 *         case NA_IAM_ADDR_OFFER: // DHCP offer
 *         {
 *             // We always Accept the first DHCP offer. This is where an offer
 *             // may be parsed and inspected. Returning NA_IAM_STATUS_ERROR
 *             // rejects the offer.
 *         } 
 *     }
 * 
 *     return status;
 * }
 * </example> 
 *
 * IAM calls @link customizeIamEventCallback for the following events:
 *
 * <list type="unordered">
 *	 <item>@link NA_IAM_ADDR_ACQUIRED - IPv4 only. The method has acquired a new configuration for 
 *                                      the interface/multihome that can be accepted by returning
 *                                      NA_IAM_STATUS_SUCCESS or rejected by returning NA_IAM_STATUS_ERROR.</item>
 *	 <item>@link NA_IAM_ADDR_CONFIGURED - IPv4 and IPv6. The interface/multihome has been configured with an acquired
 *	                                      address. For IPv6, the address passed Duplicate Address Detection(DAD) and 
 *                                        has been configured on the interface.</item>
 *	 <item>@link NA_IAM_ADDR_LOST -  The interface/multihome has lost its configured IP address. For IPv4, the 
 *                                   address is removed when the callback returns. For IPv6, this
 *                                   event is called when a stateless auto-configured address has been
 *                                   invalidated and removed.</item>
 *	 <item>@link NA_IAM_ADDR_CONFLICT - The configured IPv4/IPv6 address has been found to be in conflict with 
 *	                                 another node on the network. Returning NA_IAM_STATUS_ERROR disables 
 *                                   ongoing Address Conflict Detection(ACD) for the IPv4 address. Auto IP always
 *                                   enables ongoing ACD.</item>
 *   <item>@link NA_IAM_ADDR_INITIAL_CONFLICT - The acquired IPv4/IPv6 address has been found to be in conflict with 
 *	                                 another node on the network. An acquired IP address is one that has
 *									 not been used to configure an interface/multihome. For IPv4, this event can
 *									 only be generated if initial ACD has been enabled for an acquisition method 
 *									 If NA_IAM_STATUS_SUCCESS is returned for IPv4
 *                                   this address is used to configure the interface in spite of being in conflict.
 *                                   Returning NA_IAM_STATUS_ERROR ignores the IPv4 address and does not configure it.
 *                                   For IPv6, this address cannot be used to configure the interface and this 
 *                                   event is informational only. DAD is always enabled for IPv6 and if the
 *                                   auto-configured address in conflict is a link-local scope address, IAM generates
 *                                   a random interface ID to form a new IPv6 link-local address as part of its
 *                                   auto-recovery mechanism, which ensures that a valid link-local address is 
 *                                   always generated. Due to the implementation of the DHCPv4 client, initial ACD
 *                                   is always performed for DHCP and an address in conflict is never allowed to
 *                                   be configured, hence this event will never be reported for DHCPv4.
 *                                   Auto IP also always performs initial ACD and like DHCP Auto IP will never report
 *                                   this event; however, unlike DHCP, Auto IP generates random addresses to
 *                                   recover from initial conflicts, similarly to the auto-configured IPv6 link-local
 *                                   auto-recovery mechanism described above.   
 *                                   </item>
 *   <item>@link NA_IAM_ADDR_OFFER - The DHCPv4 client has received an offer that can be accepted by returning 
 *                                   NA_IAM_STATUS_SUCCESS or rejected by returning NA_IAM_STATUS_ERROR.</item>
 * </list>
 *
 * The default implementation of @link customizeIamEventCallback accepts all acquired addresses and does not configure
 * any IPv4 addresses found to be in initial conflict by returning NA_IAM_STATUS_ERROR. In addition, this function
 * accepts the first DHCP offer received by the DHCP client and does not stop ongoing conflict detection when either
 * an IPv4 or IPv6 address is found to be in conflict after being configured on an interface. The customization
 * of this function is left up to the user. 
 *
 * When an application callback is not passed into @link naIamStart, IAM follows the following rules:
 *
 * <list>
 *  <item> Address Acquisition - All acquired IP addresses are configured based on their priority. </item>
 *  <item> Ongoing Address Conflicts - Ongoing address conflict detection is not disabled. </item>
 *  <item> Initial Address Conflicts - IPv4 addresses in initial conflict are not configured. </item>
 *  <item> DHCP Offers - The first DHCP offer received is always accepted. </item>
 * </list>
 *
 * <section> Adding A User Defined IPv4 Acquisition Method To IAM</section>
 *
 * A user defined IPv4 acquistion method can be added to IAM by including its callback in the global acquisition
 * method list "method_list" defined in file, iamCallbacks.c and described above in section "Starting IAM" before
 * @link naIamStart is called in function @link customizeIamStart. The user callback
 * may be inserted in the list in the slot corresponding to the desired method priority. Alternatively, only the user
 * callback can be included in the list if the default IPv4 acquisition methods are not needed. The callback is called
 * with one of three commands as described in the previous sections. The callback implementation
 * should follow the procedure outlined by the default method callbacks where @link naIamEnable is called in
 * response to the NA_IAM_COMMAND_INITIALIZE command, followed by @link naIamAcquire in response to the
 * NA_IAM_COMMAND_ACQUIRE command. @link naIamRelease should be called in response to the 
 * NA_IAM_COMMAND_RELEASE command and @link naIamDisable when the user method is disabled in NVRAM. Before
 * @link naIamAcquire is called to attempt to configure an interface, @link naIfConfigDetectInitialAddressConflict
 * can be used to test the IPv4 address for initial conflicts. This function does not block and when a conflict is detected
 * or ARP probing expires, a callback, registered with this function, is called from the context of the TCP/IP stack's
 * timer task. This function must call @link naIfConfigStopConflictDetection to end the probing process. Following this step,
 * this callback can then call @link naIamAcquire to configure the tested address. The user method can also request
 * ongoing address conflict detection by setting the NA_IAM_ENABLE_ACD_FLAG flag in the "flags" 
 * parameter of @link naIamAcquire.             
 *
 * @external
 * @category Networking:IAM
 * @since 7.0
 * @overview Internet Address Manager (IAM)
 * @platform all
 * @include 	"iam.hh"
 * @library 	bsp, tcpip
*ad*/

/*ad*
 * This category of the IAM API consist of function callbacks invoked by IAM at various
 * stages of operation. Function @link customizeIamEventCallback is registered by NET+OS
 * in @link customizeIamStart and is called by IAM to notify the application of various events. 
 * Function @link customizeIamGetSettingsCallback is called by IAM to retrieve NVRAM
 * settings. Both of these functions can be customized to suit application needs. 
 *
 * @external
 * @category Networking:IAM:callbacks
 * @since 7.0
 * @overview IAM Callbacks API
 * @platform all
 * @include  "iam.hh"
 * @library  bsp, tcpip
*ad*/

/*ad*
 * This category of the IAM API consist of functions used to read and write
 * IAM NVRAM settings. 
 *
 * @external
 * @category Networking:IAM:iam_params
 * @since 7.0
 * @overview IAM Parameters API
 * @platform all
 * @include  "iam.hh"
 * @library  bsp, tcpip
*ad*/

/*ad*
 * This category of the IAM API consist of functions used retrieve IP addresses,
 * configured by IAM.
 *
 * @external
 * @category Networking:IAM:config_addresses
 * @since 7.0
 * @overview Retrieving confugured IP addresses
 * @platform all
 * @include  "iam.hh"
 * @library  bsp, tcpip
*ad*/

/*ad*
 * This category of the IAM API consist of functions used to start and modify IAM.
 *
 * @external
 * @category Networking:IAM:core
 * @since 7.0
 * @overview IAM Core API
 * @platform all
 * @include  "iam.hh"
 * @library  bsp, tcpip
*ad*/


#ifdef IPV6_ENABLED
/* In fact clears out sockaddr_storage and not just the address. */
#define NA_IAM_UNKNOWN_IP_ADDRESS   \
        {{{ 0, 0, 0, 0, {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}, 0}}}
#else
#define NA_IAM_UNKNOWN_IP_ADDRESS   \
        {{{ 0, 0, 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0}}}}
#endif

#define NA_IAM_UNKNOWN_SUBNET_MASK 0
#define NA_IAM_UNKNOWN_PREFIX      0
#define NA_IAM_DEFAULT_PREFIX_LEN  64
#define NA_IAM_ARP_PROBE_200MS     200


#ifdef IPV6_ENABLED
/*ad*
 * Autoconfigured IPv6 address and prefix length data type.         
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.0
 *
 * @param ipAddress         Autoconfigured IPv6 address.
 * @param prefixLen         Autoconfigured IPv6 address prefix length in bytes.       .
 *   
*ad*/
typedef struct
{
    struct sockaddr_storage ipAddress;
    unsigned char prefixLen;
} NaIamV6AutoCfg_t; 


/*ad*
 * Autoconfigured IPv6 addresses list data type. NA_MAX_HOMES_PER_IF
 * autoconfigured addresses are available.         
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.0
 *
 * @param addr         List of autoconfigured IPv6 addresses NA_MAX_HOMES_PER_IF long.
 *   
*ad*/
typedef struct
{
    NaIamV6AutoCfg_t addr[NA_MAX_HOMES_PER_IF];    
} NaIamV6AutoCfgInfo_t;

/*ad*
 * IPv6 configuration data type.         
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.0
 *
 * @param autoCfgInfo       Autoconfigured IPv6 addresses.
 * @param ipAddress         IPv6 address.       .
 * @param gatewayTunnel     Default gateway tunnel for IPv6 over IPv4.
 * @param prefixLen         IPv6 address prefix length in bytes.
 *   
*ad*/
typedef struct
{
    NaIamV6AutoCfgInfo_t    autoCfgInfo; 
    struct sockaddr_storage ipAddress;
    struct sockaddr_storage gatewayTunnel;
    unsigned char prefixLen;    
} NaIamV6Info_t; 

#endif     


/*ad*
 * IPv4 configuration data type.         
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.0
 *
 * @param ipAddress         IPv4 address.
 * @param defaultGateway    IPv4 default gateway.       .
 * @param subnetMask        IPv4 address subnet mask..
 *   
*ad*/
typedef struct
{
  struct sockaddr_storage ipAddress;
  struct sockaddr_storage defaultGateway;
  unsigned long subnetMask;
} NaIamV4Info_t;

/*ad*
 * IP address information data type used by @link customizeIamGetIfAddrInfo to retrieve
 * configured addresses on a network interface.          
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.0
 *
 * @param mtu                Maximum Transmission Unit (MTU) for the interface.
 * @param method             IAM acquisition method.
 * @param primaryDnsServer   Primary DNS server address.
 * @param secondaryDnsServer Secondary DNS server address.
 * @param v4Info             IPv4 configuration.
 * @param v6Info             IPv6 configuration, available only when IPV6_ENABLED is defined.
 *   
*ad*/
typedef struct
{
    int mtu;
    int method;
    struct sockaddr_storage primaryDnsServer;
    struct sockaddr_storage secondaryDnsServer;
    NaIamV4Info_t v4Info;
#ifdef IPV6_ENABLED
    NaIamV6Info_t v6Info;
#endif   
} NaIamIfAddrInfo_t; 


/*ad*
 * IP address information data type used by @link customizeIamGetIfAddress to retrieve
 * configured IP address on a network interface home.          
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.5
 *
 * @see NaIamIfIpCfg_t
 *
 * @param ipAddress			IPv4 or IPv6 address.
 * @param ipv4SubnetMask	IPv4 subnet mask.
 * @param ipv6PrefixLen		IPv6 prefix length.
 * @param subnet			Union of ipv4SubnetMask and ipv6PrefixLen.
 * @param method            IAM acquisition method.
 * @param homeIndex			Interface home index. 
 *   
*ad*/
typedef struct 
{
	struct sockaddr_storage ipAddress;
	union 
	{
		unsigned long ipv4SubnetMask;
		unsigned int  ipv6PrefixLen;
	} subnet;
	NaIamMethod_t method;
	int homeIndex;

} NaIamIfAddress_t;

/*ad*
 * IP address information data type used by @link customizeIamGetIfconfig to retrieve
 * IP configuration on a network interface.          
 *
 * @external
 * @include "iam.hh"
 * @category Networking:IAM:iam_params 
 * @since 7.5
 *
 * @param mtu                Maximum Transmission Unit (MTU) for the interface.
 * @param defaultV4Gateway   IPv4 default gateway.
 * @param gatewayTunnel		 Default gateway tunnel for IPv6 over IPv4.
 * @param primaryDnsServer   Primary DNS server address.
 * @param secondaryDnsServer Secondary DNS server address.
 * @param addrV4             IPv4 addresses.
 * @param autoCfgV6          IPv6 auto configured addresses.
 * @param staticV6			 Static IPv6 address.
 * @param dhcpV6			 DHCPv6 IP address.
 *   
*ad*/
typedef struct 
{
	int mtu;
	struct sockaddr_storage defaultV4Gateway;
	struct sockaddr_storage gatewayTunnel;
	struct sockaddr_storage primaryDnsServer;
    struct sockaddr_storage secondaryDnsServer;
	NaIamIfAddress_t addrV4[NA_MAX_HOMES_PER_IF];
	NaIamIfAddress_t autoCfgV6[NA_MAX_HOMES_PER_IF];
	NaIamIfAddress_t staticV6;
	NaIamIfAddress_t dhcpV6;

} NaIamIfIpCfg_t;


NaIamStatus_t customizeIamGetIfAddress(const char * ifname, int addrFamily, NaIamIfAddress_t * addr); 
NaIamStatus_t customizeIamGetIfconfig(const char * ifname, NaIamIfIpCfg_t * config); 

NaIamStatus_t customizeIamGetIfAddrInfo(const char * ifname, NaIamIfAddrInfo_t * addrInfo);    
NaIamStatus_t customizeIamGetStaticIpv6Gateway(const char * ifname, struct sockaddr_storage * gateway); 

          
NaIamParams_t * customizeIamFindInterfaceConfig(char const * ifname, NaIamParamsInfo_t * config);
NaIamParams_t * customizeIamFindUnusedInterfaceConfig(NaIamParamsInfo_t * config, BOOLEAN forceIt);
int customizeIamGetAutoipConfig(char const * ifname, NaIamAutoipParams_t * config);
int customizeIamGetConfig(NaIamParamsInfo_t * config);
int customizeIamGetDefaultConfig(NaIamParamsInfo_t * config);
int customizeIamGetDefaultInterfaceConfig(char const * ifname, NaIamParams_t * config);
int customizeIamGetDefaultEthernetConfig(NaIamParams_t * config, unsigned idx);
int customizeIamGetDefaultWirelessConfig(NaIamParams_t * config, unsigned idx);
int customizeIamGetDhcpConfig(char const * ifname, NaIamDhcpParams_t * config);
int customizeIamGetStaticConfig(char const * ifname, NaIamStaticParams_t * config);
int customizeIamSetAutoipConfig(char const * ifname, NaIamAutoipParams_t const * config);
int customizeIamSetDhcpConfig(char const * ifname, NaIamDhcpParams_t const * config);
int customizeIamSetInterfaceConfig(char const * ifname, NaIamParams_t const * config);
int customizeIamSetStaticConfig(char const * ifname, NaIamStaticParams_t const * config);
int customizeIamStart(void);
void iamInstallEthernetLinkCallback(NaLinkStatusCallbackFn_t callbackFn);
#endif
