AzureMXChip/MXCHIPAZ3166/core/lib/netxduo/common/src/nxd_ipv6_address_set.c
UINT  _nxd_ipv6_address_set(NX_IP *ip_ptr, UINT interface_index, NXD_ADDRESS *ip_address, ULONG prefix_length, UINT *address_index)
{
#ifdef FEATURE_NX_IPV6

TX_INTERRUPT_SAVE_AREA
#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
VOID                (*address_change_notify)(NX_IP *, UINT, UINT, UINT, ULONG *);
#endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
NXD_IPV6_ADDRESS *ipv6_addr;
NXD_IPV6_ADDRESS *interface_ipv6_address;
UINT              index = (UINT)0xFFFFFFFF;
UINT              i;
ULONG             multicast_address[4];

    /* Place protection while the IPv6 address is modified. */
    tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);

    if (ip_address)
    {

        /* Perform duplicate address detection.  */
        for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
        {
            if ((ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[0] == ip_address -> nxd_ip_address.v6[0]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[1] == ip_address -> nxd_ip_address.v6[1]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[2] == ip_address -> nxd_ip_address.v6[2]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[3] == ip_address -> nxd_ip_address.v6[3]))
            {

                /* The IPv6 address already exists.  */
                tx_mutex_put(&(ip_ptr -> nx_ip_protection));
                return(NX_DUPLICATED_ENTRY);
            }
        }
    }

    /* Find an avaiable IPv6 address structure. */
    for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
    {
        /* Look for invalid entries. */
        if (!ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid)
        {

            /* An available entry is found. */
            index = i;
            break;
        }
    }

    if (index == (UINT)0xFFFFFFFF)
    {
        tx_mutex_put(&(ip_ptr -> nx_ip_protection));
        return(NX_NO_MORE_ENTRIES);
    }

    if (address_index)
    {
        *address_index = index;
    }

    /* Pointer to the IPv6 address that needs to be modified. */
    ipv6_addr = &(ip_ptr -> nx_ipv6_address[index]);

    /* The address is null.  */
    if ((!ip_address) && (prefix_length == 10))
    {

    /* No address supplied. Assume it is link local address, constructed from the physical interface. */
    ULONG word2, word3;

        /* Construct Interface Identifier, following RFC2464, page 3 */
        /* Assign link local address.
           LL address is constructed by:
           0xFE80::{64 bit interface ID}.  See RFC 4291 */

        word2 = ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_msw << 16 |
            ((ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0xFF000000) >> 16) | 0xFF;

        /* Fix the 2nd lower-order bit of the 1st byte, RFC2464, page 3 */
        word2 = (word2 & 0xFDFFFFFF) | (~(word2 | 0xFDFFFFFF));
        word3 = (ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0x00FFFFFF) | 0xFE000000;

        /* Point to interface link list head  */
        interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;

        /* Perform link local duplicate address detection.  */
        while (interface_ipv6_address)
        {
            if ((interface_ipv6_address -> nxd_ipv6_address[0] == 0xFE800000) &&
                (interface_ipv6_address -> nxd_ipv6_address[1] == 0x00000000) &&
                (interface_ipv6_address -> nxd_ipv6_address[2] == word2) &&
                (interface_ipv6_address -> nxd_ipv6_address[3] == word3))
            {

                /* The IPv6 address already exists.  */
                tx_mutex_put(&(ip_ptr -> nx_ip_protection));
                return(NX_DUPLICATED_ENTRY);
            }

            /* Walk down the list.  */
            interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
        }

        /* Set up the link local address. */
        ipv6_addr -> nxd_ipv6_address[0] = 0xFE800000;
        ipv6_addr -> nxd_ipv6_address[1] = 0x00000000;
        ipv6_addr -> nxd_ipv6_address[2] = word2;
        ipv6_addr -> nxd_ipv6_address[3] = word3;
    }
    else if (ip_address != NX_NULL)
    {
        ipv6_addr -> nxd_ipv6_address[0] = ip_address -> nxd_ip_address.v6[0];
        ipv6_addr -> nxd_ipv6_address[1] = ip_address -> nxd_ip_address.v6[1];
        ipv6_addr -> nxd_ipv6_address[2] = ip_address -> nxd_ip_address.v6[2];
        ipv6_addr -> nxd_ipv6_address[3] = ip_address -> nxd_ip_address.v6[3];
    }
    else
    {
        tx_mutex_put(&(ip_ptr -> nx_ip_protection));
        return(NX_IP_ADDRESS_ERROR);
    }

    ipv6_addr -> nxd_ipv6_address_valid = NX_TRUE;
    ipv6_addr -> nxd_ipv6_address_type = NX_IP_VERSION_V6;
    ipv6_addr -> nxd_ipv6_address_prefix_length = (UCHAR)(prefix_length & 0xFF);
    ipv6_addr -> nxd_ipv6_address_next = NX_NULL;

    /* Attach to the interface.  */
    ipv6_addr -> nxd_ipv6_address_attached = &ip_ptr -> nx_ip_interface[interface_index];

    /* Point to interface link list head  */
    interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;

    /* Walk to the end of the list.  */
    while (interface_ipv6_address)
    {

        /* If the next entry does not exist, we already reach the end of the list.
            Add the IPv6 address towards the end. */
        if (interface_ipv6_address -> nxd_ipv6_address_next)
        {
            interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
        }
        else
        {
            interface_ipv6_address -> nxd_ipv6_address_next = ipv6_addr;
            break;
        }
    }

    /* Check whether the head is NULL  */
    if (interface_ipv6_address == NX_NULL)
    {
        /* This interface does not have IPv6 addresses yet.  */
        ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head = ipv6_addr;
    }

    /* If trace is enabled, insert this event into the trace buffer.  */
    NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INTERFACE_ADDRESS_SET, ip_ptr, ipv6_addr -> nxd_ipv6_address[3], prefix_length, index, NX_TRACE_IP_EVENTS, 0, 0);

    /* Set the configuration type to manual. */
    ipv6_addr -> nxd_ipv6_address_ConfigurationMethod = NX_IPV6_ADDRESS_MANUAL_CONFIG;

    /* Release the IP protection.  nx_ipv6_multicast_join would need to obtain the mutex. */
    tx_mutex_put(&(ip_ptr -> nx_ip_protection));
    /* Join the solicited-node multicast group */
    /* FF02::1:FFXX:XXXX */
    SET_SOLICITED_NODE_MULTICAST_ADDRESS(multicast_address, ipv6_addr -> nxd_ipv6_address);
    _nx_ipv6_multicast_join(ip_ptr, &multicast_address[0], ipv6_addr -> nxd_ipv6_address_attached);

    /* Obtain the IP protection again. */
    tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);

    TX_DISABLE
#ifndef NX_DISABLE_IPV6_DAD

    /* If ICMPv6 is enabled, mark the address as tentative, per RFC2462.
       If DAD is not enabled, start the address in VALID state. */
    if (ip_ptr -> nx_ip_icmpv6_packet_process)
    {

        /* Start DAD */
        ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_TENTATIVE;
        ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = NX_IPV6_DAD_TRANSMITS;

        /* If trace is enabled, log the start of DAD process. */
        NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INITIATE_DAD_PROCESS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
    }
    else
    {

        /* If ICMPv6 is not enabled on this interface, the DAD process is eliminated,
           so mark the input IP address directly as valid. */
        ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_VALID;
        ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = 0;
    }
#else
    /* Set the input address as valid. */
    ipv6_addr -> nxd_ipv6_address_state                     = NX_IPV6_ADDR_STATE_VALID;
#endif

    /* Restore interrupts.  */
    TX_RESTORE
#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
    /* Pickup the current notification callback and additional information pointers.  */
    address_change_notify =  ip_ptr -> nx_ipv6_address_change_notify;
#endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */
    /* Release the protection while the IPv6 address is modified. */
    tx_mutex_put(&(ip_ptr -> nx_ip_protection));

#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
    /* Is the application configured for notification of address changes and/or
       prefix_length change?  */
    if (address_change_notify)
    {

        /* Yes, call the application's address change notify function.  */
        (address_change_notify)(ip_ptr, NX_IPV6_ADDRESS_MANUAL_CONFIG, interface_index, index, &ipv6_addr -> nxd_ipv6_address[0]);
    }
#endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */

    /* Return completion status.  */
    return(NX_SUCCESS);

#else /* !FEATURE_NX_IPV6 */
    NX_PARAMETER_NOT_USED(ip_ptr);
    NX_PARAMETER_NOT_USED(interface_index);
    NX_PARAMETER_NOT_USED(ip_address);
    NX_PARAMETER_NOT_USED(prefix_length);
    NX_PARAMETER_NOT_USED(address_index);

    return(NX_NOT_SUPPORTED);

#endif /* FEATURE_NX_IPV6 */
}
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nxd_ipv6_address_set                               PORTABLE C      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets the IP address and the prefix length for the     */
/*    supplied IP instance.                                               */
/*                                                                        */
/*    For the IPv6 address, an application is only allowed to change the  */
/*    global IP address.  The link local address is generated through the */
/*    underlying interface address, therefore cannot be reconfigured by   */
/*    user level applications.                                            */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ip_ptr                                IP control block pointer      */
/*    interface_index                       The index to the physical     */
/*                                            interface this address      */
/*                                            belongs to                  */
/*    ip_address                            Pointer to IP address         */
/*                                            structure                   */
/*    prefix_length                         Prefix length                 */
/*    address_index                         Index to the IPv6 address     */
/*                                            table                       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    NX_SUCCESS                            Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_ipv6_multicast_join               Multicast group join service  */
/*    [ipv6_address_change_notify]          User callback function        */
/*    tx_mutex_get                          Get protection mutex          */
/*    tx_mutex_put                          Put protection mutex          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
FUNCTION                                               RELEASE

_nxd_ipv6_address_set                               PORTABLE C
6.1
AUTHOR

Yuxin Zhou, Microsoft Corporation

DESCRIPTION

This function sets the IP address and the prefix length for the
supplied IP instance.

For the IPv6 address, an application is only allowed to change the
global IP address.  The link local address is generated through the
underlying interface address, therefore cannot be reconfigured by
user level applications.

INPUT

ip_ptr                                IP control block pointer
interface_index                       The index to the physical
interface this address
belongs to
ip_address                            Pointer to IP address
structure
prefix_length                         Prefix length
address_index                         Index to the IPv6 address
table

OUTPUT



CALLS

_nx_ipv6_multicast_join               Multicast group join service
[ipv6_address_change_notify]          User callback function
tx_mutex_get                          Get protection mutex
tx_mutex_put                          Put protection mutex

CALLED BY

Application Code

RELEASE HISTORY

DATE              NAME                      DESCRIPTION

05-19-2020     Yuxin Zhou               Initial Version 6.0
09-30-2020     Yuxin Zhou               Modified comment(s),
resulting in version 6.1
FUNCTION RELEASE _nxd_ipv6_address_set PORTABLE C 6 . 1 AUTHOR Yuxin Zhou Microsoft Corporation DESCRIPTION This function sets the IP address and the prefix length for the supplied IP instance . For the IPv6 address an application is only allowed to change the global IP address . The link local address is generated through the underlying interface address therefore cannot be reconfigured by user level applications . INPUT ip_ptr IP control block pointer interface_index The index to the physical interface this address belongs to ip_address Pointer to IP address structure prefix_length Prefix length address_index Index to the IPv6 address table OUTPUT CALLS _nx_ipv6_multicast_join Multicast group join service [ ipv6_address_change_notify ] User callback function tx_mutex_get Get protection mutex tx_mutex_put Put protection mutex CALLED BY Application Code RELEASE HISTORY DATE NAME DESCRIPTION 05 - 19 - 2020 Yuxin Zhou Initial Version 6 . 0 09 - 30 - 2020 Yuxin Zhou Modified comment ( s ) resulting in version 6 . 1
UINT  _nxd_ipv6_address_set(NX_IP *ip_ptr, UINT interface_index, NXD_ADDRESS *ip_address, ULONG prefix_length, UINT *address_index)
{
#ifdef FEATURE_NX_IPV6
TX_INTERRUPT_SAVE_AREA
#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
VOID                (*address_change_notify)(NX_IP *, UINT, UINT, UINT, ULONG *);
#endif 
NXD_IPV6_ADDRESS *ipv6_addr;
NXD_IPV6_ADDRESS *interface_ipv6_address;
UINT              index = (UINT)0xFFFFFFFF;
UINT              i;
ULONG             multicast_address[4];
    tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
    if (ip_address)
    {
        for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
        {
            if ((ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[0] == ip_address -> nxd_ip_address.v6[0]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[1] == ip_address -> nxd_ip_address.v6[1]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[2] == ip_address -> nxd_ip_address.v6[2]) &&
                (ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address[3] == ip_address -> nxd_ip_address.v6[3]))
            {
                tx_mutex_put(&(ip_ptr -> nx_ip_protection));
                return(NX_DUPLICATED_ENTRY);
            }
        }
    }
    for (i = 0; i < NX_MAX_IPV6_ADDRESSES; i++)
    {
        if (!ip_ptr -> nx_ipv6_address[i].nxd_ipv6_address_valid)
        {
            index = i;
            break;
        }
    }
    if (index == (UINT)0xFFFFFFFF)
    {
        tx_mutex_put(&(ip_ptr -> nx_ip_protection));
        return(NX_NO_MORE_ENTRIES);
    }
    if (address_index)
    {
        *address_index = index;
    }
    ipv6_addr = &(ip_ptr -> nx_ipv6_address[index]);
    if ((!ip_address) && (prefix_length == 10))
    {
    ULONG word2, word3;
        word2 = ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_msw << 16 |
            ((ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0xFF000000) >> 16) | 0xFF;
        word2 = (word2 & 0xFDFFFFFF) | (~(word2 | 0xFDFFFFFF));
        word3 = (ip_ptr -> nx_ip_interface[interface_index].nx_interface_physical_address_lsw & 0x00FFFFFF) | 0xFE000000;
        interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;
        while (interface_ipv6_address)
        {
            if ((interface_ipv6_address -> nxd_ipv6_address[0] == 0xFE800000) &&
                (interface_ipv6_address -> nxd_ipv6_address[1] == 0x00000000) &&
                (interface_ipv6_address -> nxd_ipv6_address[2] == word2) &&
                (interface_ipv6_address -> nxd_ipv6_address[3] == word3))
            {
                tx_mutex_put(&(ip_ptr -> nx_ip_protection));
                return(NX_DUPLICATED_ENTRY);
            }
            interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
        }
        ipv6_addr -> nxd_ipv6_address[0] = 0xFE800000;
        ipv6_addr -> nxd_ipv6_address[1] = 0x00000000;
        ipv6_addr -> nxd_ipv6_address[2] = word2;
        ipv6_addr -> nxd_ipv6_address[3] = word3;
    }
    else if (ip_address != NX_NULL)
    {
        ipv6_addr -> nxd_ipv6_address[0] = ip_address -> nxd_ip_address.v6[0];
        ipv6_addr -> nxd_ipv6_address[1] = ip_address -> nxd_ip_address.v6[1];
        ipv6_addr -> nxd_ipv6_address[2] = ip_address -> nxd_ip_address.v6[2];
        ipv6_addr -> nxd_ipv6_address[3] = ip_address -> nxd_ip_address.v6[3];
    }
    else
    {
        tx_mutex_put(&(ip_ptr -> nx_ip_protection));
        return(NX_IP_ADDRESS_ERROR);
    }
    ipv6_addr -> nxd_ipv6_address_valid = NX_TRUE;
    ipv6_addr -> nxd_ipv6_address_type = NX_IP_VERSION_V6;
    ipv6_addr -> nxd_ipv6_address_prefix_length = (UCHAR)(prefix_length & 0xFF);
    ipv6_addr -> nxd_ipv6_address_next = NX_NULL;
    ipv6_addr -> nxd_ipv6_address_attached = &ip_ptr -> nx_ip_interface[interface_index];
    interface_ipv6_address = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head;
    while (interface_ipv6_address)
    {
        if (interface_ipv6_address -> nxd_ipv6_address_next)
        {
            interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
        }
        else
        {
            interface_ipv6_address -> nxd_ipv6_address_next = ipv6_addr;
            break;
        }
    }
    if (interface_ipv6_address == NX_NULL)
    {
        ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head = ipv6_addr;
    }
    NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INTERFACE_ADDRESS_SET, ip_ptr, ipv6_addr -> nxd_ipv6_address[3], prefix_length, index, NX_TRACE_IP_EVENTS, 0, 0);
    ipv6_addr -> nxd_ipv6_address_ConfigurationMethod = NX_IPV6_ADDRESS_MANUAL_CONFIG;
    tx_mutex_put(&(ip_ptr -> nx_ip_protection));
    SET_SOLICITED_NODE_MULTICAST_ADDRESS(multicast_address, ipv6_addr -> nxd_ipv6_address);
    _nx_ipv6_multicast_join(ip_ptr, &multicast_address[0], ipv6_addr -> nxd_ipv6_address_attached);
    tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
    TX_DISABLE
#ifndef NX_DISABLE_IPV6_DAD
    if (ip_ptr -> nx_ip_icmpv6_packet_process)
    {
        ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_TENTATIVE;
        ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = NX_IPV6_DAD_TRANSMITS;
        NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IPV6_INITIATE_DAD_PROCESS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
    }
    else
    {
        ipv6_addr -> nxd_ipv6_address_state                 = NX_IPV6_ADDR_STATE_VALID;
        ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = 0;
    }
#else
    ipv6_addr -> nxd_ipv6_address_state                     = NX_IPV6_ADDR_STATE_VALID;
#endif
    TX_RESTORE
#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
    address_change_notify =  ip_ptr -> nx_ipv6_address_change_notify;
#endif 
    tx_mutex_put(&(ip_ptr -> nx_ip_protection));
#ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
    if (address_change_notify)
    {
        (address_change_notify)(ip_ptr, NX_IPV6_ADDRESS_MANUAL_CONFIG, interface_index, index, &ipv6_addr -> nxd_ipv6_address[0]);
    }
#endif 
    return(NX_SUCCESS);
#else 
    NX_PARAMETER_NOT_USED(ip_ptr);
    NX_PARAMETER_NOT_USED(interface_index);
    NX_PARAMETER_NOT_USED(ip_address);
    NX_PARAMETER_NOT_USED(prefix_length);
    NX_PARAMETER_NOT_USED(address_index);
    return(NX_NOT_SUPPORTED);
#endif 
}
UINT _nxd_ipv6_address_set ( NX_IP * ip_ptr , UINT interface_index , NXD_ADDRESS * ip_address , ULONG prefix_length , UINT * address_index ) { #ifdef FEATURE_NX_IPV6 TX_INTERRUPT_SAVE_AREA #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY VOID ( * address_change_notify ) ( NX_IP * , UINT , UINT , UINT , ULONG * ) ; #endif NXD_IPV6_ADDRESS * ipv6_addr ; NXD_IPV6_ADDRESS * interface_ipv6_address ; UINT index = ( UINT ) 0xFFFFFFFF ; UINT i ; ULONG multicast_address [ 4 ] ; tx_mutex_get ( & ( ip_ptr -> nx_ip_protection ) , TX_WAIT_FOREVER ) ; if ( ip_address ) { for ( i = 0 ; i < NX_MAX_IPV6_ADDRESSES ; i ++ ) { if ( ( ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address_valid ) && ( ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address [ 0 ] == ip_address -> nxd_ip_address . v6 [ 0 ] ) && ( ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address [ 1 ] == ip_address -> nxd_ip_address . v6 [ 1 ] ) && ( ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address [ 2 ] == ip_address -> nxd_ip_address . v6 [ 2 ] ) && ( ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address [ 3 ] == ip_address -> nxd_ip_address . v6 [ 3 ] ) ) { tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; return ( NX_DUPLICATED_ENTRY ) ; } } } for ( i = 0 ; i < NX_MAX_IPV6_ADDRESSES ; i ++ ) { if ( ! ip_ptr -> nx_ipv6_address [ i ] . nxd_ipv6_address_valid ) { index = i ; break ; } } if ( index == ( UINT ) 0xFFFFFFFF ) { tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; return ( NX_NO_MORE_ENTRIES ) ; } if ( address_index ) { * address_index = index ; } ipv6_addr = & ( ip_ptr -> nx_ipv6_address [ index ] ) ; if ( ( ! ip_address ) && ( prefix_length == 10 ) ) { ULONG word2 , word3 ; word2 = ip_ptr -> nx_ip_interface [ interface_index ] . nx_interface_physical_address_msw << 16 | ( ( ip_ptr -> nx_ip_interface [ interface_index ] . nx_interface_physical_address_lsw & 0xFF000000 ) >> 16 ) | 0xFF ; word2 = ( word2 & 0xFDFFFFFF ) | ( ~ ( word2 | 0xFDFFFFFF ) ) ; word3 = ( ip_ptr -> nx_ip_interface [ interface_index ] . nx_interface_physical_address_lsw & 0x00FFFFFF ) | 0xFE000000 ; interface_ipv6_address = ip_ptr -> nx_ip_interface [ interface_index ] . nxd_interface_ipv6_address_list_head ; while ( interface_ipv6_address ) { if ( ( interface_ipv6_address -> nxd_ipv6_address [ 0 ] == 0xFE800000 ) && ( interface_ipv6_address -> nxd_ipv6_address [ 1 ] == 0x00000000 ) && ( interface_ipv6_address -> nxd_ipv6_address [ 2 ] == word2 ) && ( interface_ipv6_address -> nxd_ipv6_address [ 3 ] == word3 ) ) { tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; return ( NX_DUPLICATED_ENTRY ) ; } interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next ; } ipv6_addr -> nxd_ipv6_address [ 0 ] = 0xFE800000 ; ipv6_addr -> nxd_ipv6_address [ 1 ] = 0x00000000 ; ipv6_addr -> nxd_ipv6_address [ 2 ] = word2 ; ipv6_addr -> nxd_ipv6_address [ 3 ] = word3 ; } else if ( ip_address != NX_NULL ) { ipv6_addr -> nxd_ipv6_address [ 0 ] = ip_address -> nxd_ip_address . v6 [ 0 ] ; ipv6_addr -> nxd_ipv6_address [ 1 ] = ip_address -> nxd_ip_address . v6 [ 1 ] ; ipv6_addr -> nxd_ipv6_address [ 2 ] = ip_address -> nxd_ip_address . v6 [ 2 ] ; ipv6_addr -> nxd_ipv6_address [ 3 ] = ip_address -> nxd_ip_address . v6 [ 3 ] ; } else { tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; return ( NX_IP_ADDRESS_ERROR ) ; } ipv6_addr -> nxd_ipv6_address_valid = NX_TRUE ; ipv6_addr -> nxd_ipv6_address_type = NX_IP_VERSION_V6 ; ipv6_addr -> nxd_ipv6_address_prefix_length = ( UCHAR ) ( prefix_length & 0xFF ) ; ipv6_addr -> nxd_ipv6_address_next = NX_NULL ; ipv6_addr -> nxd_ipv6_address_attached = & ip_ptr -> nx_ip_interface [ interface_index ] ; interface_ipv6_address = ip_ptr -> nx_ip_interface [ interface_index ] . nxd_interface_ipv6_address_list_head ; while ( interface_ipv6_address ) { if ( interface_ipv6_address -> nxd_ipv6_address_next ) { interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next ; } else { interface_ipv6_address -> nxd_ipv6_address_next = ipv6_addr ; break ; } } if ( interface_ipv6_address == NX_NULL ) { ip_ptr -> nx_ip_interface [ interface_index ] . nxd_interface_ipv6_address_list_head = ipv6_addr ; } NX_TRACE_IN_LINE_INSERT ( NXD_TRACE_IPV6_INTERFACE_ADDRESS_SET , ip_ptr , ipv6_addr -> nxd_ipv6_address [ 3 ] , prefix_length , index , NX_TRACE_IP_EVENTS , 0 , 0 ) ; ipv6_addr -> nxd_ipv6_address_ConfigurationMethod = NX_IPV6_ADDRESS_MANUAL_CONFIG ; tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; SET_SOLICITED_NODE_MULTICAST_ADDRESS ( multicast_address , ipv6_addr -> nxd_ipv6_address ) ; _nx_ipv6_multicast_join ( ip_ptr , & multicast_address [ 0 ] , ipv6_addr -> nxd_ipv6_address_attached ) ; tx_mutex_get ( & ( ip_ptr -> nx_ip_protection ) , TX_WAIT_FOREVER ) ; TX_DISABLE #ifndef NX_DISABLE_IPV6_DAD if ( ip_ptr -> nx_ip_icmpv6_packet_process ) { ipv6_addr -> nxd_ipv6_address_state = NX_IPV6_ADDR_STATE_TENTATIVE ; ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = NX_IPV6_DAD_TRANSMITS ; NX_TRACE_IN_LINE_INSERT ( NXD_TRACE_IPV6_INITIATE_DAD_PROCESS , ip_ptr , 0 , 0 , 0 , NX_TRACE_INTERNAL_EVENTS , 0 , 0 ) ; } else { ipv6_addr -> nxd_ipv6_address_state = NX_IPV6_ADDR_STATE_VALID ; ipv6_addr -> nxd_ipv6_address_DupAddrDetectTransmit = 0 ; } #else ipv6_addr -> nxd_ipv6_address_state = NX_IPV6_ADDR_STATE_VALID ; #endif TX_RESTORE #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY address_change_notify = ip_ptr -> nx_ipv6_address_change_notify ; #endif tx_mutex_put ( & ( ip_ptr -> nx_ip_protection ) ) ; #ifdef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY if ( address_change_notify ) { ( address_change_notify ) ( ip_ptr , NX_IPV6_ADDRESS_MANUAL_CONFIG , interface_index , index , & ipv6_addr -> nxd_ipv6_address [ 0 ] ) ; } #endif return ( NX_SUCCESS ) ; #else NX_PARAMETER_NOT_USED ( ip_ptr ) ; NX_PARAMETER_NOT_USED ( interface_index ) ; NX_PARAMETER_NOT_USED ( ip_address ) ; NX_PARAMETER_NOT_USED ( prefix_length ) ; NX_PARAMETER_NOT_USED ( address_index ) ; return ( NX_NOT_SUPPORTED ) ; #endif }
FUNCTION                                               RELEASE
FUNCTION RELEASE
/* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */ /* Place protection while the IPv6 address is modified. */ /* Perform duplicate address detection.  */ /* The IPv6 address already exists.  */ /* Find an avaiable IPv6 address structure. */ /* Look for invalid entries. */ /* An available entry is found. */ /* Pointer to the IPv6 address that needs to be modified. */ /* The address is null.  */ /* No address supplied. Assume it is link local address, constructed from the physical interface. */ /* Construct Interface Identifier, following RFC2464, page 3 */ /* Assign link local address.
           LL address is constructed by:
           0xFE80::{64 bit interface ID}.  See RFC 4291 */ /* Fix the 2nd lower-order bit of the 1st byte, RFC2464, page 3 */ /* Point to interface link list head  */ /* Perform link local duplicate address detection.  */ /* The IPv6 address already exists.  */ /* Walk down the list.  */ /* Set up the link local address. */ /* Attach to the interface.  */ /* Point to interface link list head  */ /* Walk to the end of the list.  */ /* If the next entry does not exist, we already reach the end of the list.
            Add the IPv6 address towards the end. */ /* Check whether the head is NULL  */ /* This interface does not have IPv6 addresses yet.  */ /* If trace is enabled, insert this event into the trace buffer.  */ /* Set the configuration type to manual. */ /* Release the IP protection.  nx_ipv6_multicast_join would need to obtain the mutex. */ /* Join the solicited-node multicast group */ /* FF02::1:FFXX:XXXX */ /* Obtain the IP protection again. */ /* If ICMPv6 is enabled, mark the address as tentative, per RFC2462.
       If DAD is not enabled, start the address in VALID state. */ /* Start DAD */ /* If trace is enabled, log the start of DAD process. */ /* If ICMPv6 is not enabled on this interface, the DAD process is eliminated,
           so mark the input IP address directly as valid. */ /* Set the input address as valid. */ /* Restore interrupts.  */ /* Pickup the current notification callback and additional information pointers.  */ /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */ /* Release the protection while the IPv6 address is modified. */ /* Is the application configured for notification of address changes and/or
       prefix_length change?  */ /* Yes, call the application's address change notify function.  */ /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */ /* Return completion status.  */ /* !FEATURE_NX_IPV6 */ /* FEATURE_NX_IPV6 */