AzureMXChip/MXCHIPAZ3166/core/lib/netxduo/addons/dhcp/nxd_dhcpv6_server.c
UINT  _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, 
                                                   UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address)
{

UINT                status;
UINT                add_on;
UINT                record_index;
ULONG               option_code;
ULONG               option_length;
UCHAR               *buffer_ptr;
UINT                index;
ULONG               returned_xid;
NX_DHCPV6_SVR_DUID  client_duid, server_duid;
UINT                client_duid_received;
UINT                server_duid_received;
NX_DHCPV6_CLIENT    temp_client_rec;
ULONG               received_message_type;
UINT                matching;

    NX_PARAMETER_NOT_USED(iface_index);

    *dhcpv6_client_ptr = NX_NULL;

    /* Create a scratch record for this client so we can qualify it before adding it to the server table. */
    memset(&temp_client_rec, 0, sizeof(NX_DHCPV6_CLIENT));

    /* Initialize the record with the DHCPv6 Client ID. */
    temp_client_rec.nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID;

    /* Assume the Client is not bound to an IP address yet.  */
    temp_client_rec.nx_dhcpv6_state =  NX_DHCPV6_STATE_UNBOUND;

    /* Check packet for message type and transaction ID. */
    if (packet_ptr -> nx_packet_length < 4)
    {

        /* Reported length of the packet may be incorrect.  */
        return NX_DHCPV6_PROCESSING_ERROR;
    }

    /* Set a pointer to the start of DHCPv6 data. */
    buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;

    /* Initialize local variables. */
    index = 0;
    client_duid_received = NX_FALSE;
    server_duid_received = NX_FALSE;

    /* Extract the message type which should be the first byte.  */
    _nx_dhcpv6_server_utility_get_data(buffer_ptr, 1, &received_message_type);

    /* Check for an illegal message type. */
    if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) ||
        (received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
    {

        /* These should only be sent to DHCPv6 clients! The Inform Request is actually
           legal to receive but should NOT be used to add clients to the server table. */
        return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE;
    }

    /* Copy the source address to the Client record. */
    COPY_IPV6_ADDRESS(&source_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_address.v6[0]);
    temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;

    /* Copy the destination address to the Client record. */
    COPY_IPV6_ADDRESS(&destination_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
    temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;

    /* Advance to the data pointer. */
    buffer_ptr++;

    /* Parse the transaction ID. */
    _nx_dhcpv6_server_utility_get_data(buffer_ptr, 3, &returned_xid);

    temp_client_rec.nx_dhcpv6_message_type = received_message_type;

    /* Set the message ID. The server will need this to reply to the Client. */
    temp_client_rec.nx_dhcpv6_message_xid = returned_xid;

    buffer_ptr += 3;

    /* Update index for message type and transaction ID.  */
    index += 4;

    /* Now parse all the DHCPv6 option blocks in the packet buffer. */
    /* 4 bytes for option code and option length. */
    while (index + 4 <= packet_ptr -> nx_packet_length)
    {

        /* Get the option code and length of data of the current option block. */
        status = _nx_dhcpv6_server_utility_get_block_option_length(buffer_ptr, &option_code, &option_length);

        /* Check that the block data is valid. */
        if (status != NX_SUCCESS)
        {

            /* No, return the error status. */
            return status;
        }

        /* Keep track of how far into the packet we have parsed. */
        index += option_length + 4; 

        /* This is a double check to verify we haven't gone off the end of the packet buffer. */
        if (index > packet_ptr -> nx_packet_length)
        {

            /* Reported length of the packet may be incorrect. At any rate, we don't know
               exactly what the end of the message is, so abort. */
            return NX_DHCPV6_PROCESSING_ERROR;
        }

        /* Update buffer pointer to option data.  */
        buffer_ptr += 4;

        /* Process the option code with an option specific API. */
        switch (option_code)
        {

            /* Note - these 'process' functions will not move the buffer pointer. */

            case NX_DHCPV6_OP_DUID_CLIENT:

                client_duid.nx_op_code = (USHORT)option_code;
                client_duid.nx_option_length = (USHORT)option_length;

                status = _nx_dhcpv6_process_duid(&client_duid, option_code, option_length, buffer_ptr);

                if (status != NX_SUCCESS)
                {

                    return status;
                }

                /*  Copy to the temporary client record. */
                memcpy(&temp_client_rec.nx_dhcpv6_client_duid, &client_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */

                /* Indicate the message contained the required Client DUID. */
                client_duid_received = NX_TRUE;

            break;

            case NX_DHCPV6_OP_DUID_SERVER:

                server_duid.nx_op_code = (USHORT)option_code;
                server_duid.nx_option_length = (USHORT)option_length;

                status = _nx_dhcpv6_process_duid(&server_duid, option_code, option_length, buffer_ptr);

                if (status != NX_SUCCESS)
                {

                    return status;
                }

                /*  Copy to the temporary client record. */
                memcpy(&temp_client_rec.nx_dhcpv6_server_duid, &server_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */

                /* Indicate the message contained the required Server DUID. */
                server_duid_received = NX_TRUE;

            break;


            case NX_DHCPV6_OP_IA_NA:

                status = _nx_dhcpv6_server_process_iana(&temp_client_rec, option_code, option_length, buffer_ptr);

                if (status != NX_SUCCESS)
                {
                    return status;
                }

            break;

            /* This should not happen. The IA address option must be embedded in the IANA option. */
            case NX_DHCPV6_OP_IA_ADDRESS:

                /* Don't process an IA address option outside of an address association (IANA). */
                status = NX_DHCPV6_IANA_OPTION_MISSING;
                
            break;

            case NX_DHCPV6_OP_OPTION_REQUEST:

                /* Option request option contains request usually for network configuration parameters
                   such as the DNS server. */
                status = _nx_dhcpv6_process_option_request(&temp_client_rec, option_code, option_length, buffer_ptr);

                if (status != NX_SUCCESS)
                {

                    return status;
                }

            break;

            case NX_DHCPV6_OP_ELAPSED_TIME:

                /* The elapsed time is time elapsed since the client initiated the IP lease request. */
                status = _nx_dhcpv6_process_elapsed_time(&temp_client_rec, option_code, option_length, buffer_ptr); 

                if (status != NX_SUCCESS)
                {

                    return status;
                }

            break;


            default:
                break; 
        }

        /* Check for errors from option block processing. */
        if (status != NX_SUCCESS)
        {


            return status;
        }

        /* Move to the next top level option. */
         buffer_ptr += option_length;
    }

    /* Check for an improperly formatted packet. */
    if (index != packet_ptr -> nx_packet_length)
    {

        /* If we get here if we are not at the expected end of the buffer. Oops */
        return NX_DHCPV6_PROCESSING_ERROR;
    }

    /* Check if the message is missing the required DUID(s). */
    if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
        (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
    {

        if (!client_duid_received)
        {

            return NX_DHCPV6_MESSAGE_DUID_MISSING;
        }
    }
    /* The following message types must include a client and server DUID. */
    else if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
             (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW)   ||
             (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE))
    {

        if (!server_duid_received || !client_duid_received)
        {

            return NX_DHCPV6_MESSAGE_DUID_MISSING;
        }
    }
    /* An inform request only requires a server DUID. */
    else if (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)
    {

        /* The Inform request message should NOT include an IA. */
        if (temp_client_rec.nx_dhcpv6_ia.nx_op_code != 0)
        {
            return NX_DHCPV6_INVALID_IA_DATA;
        }
    }

    /* Validate the client message, and determine how (if) the server should respond to it. */
    status = _nx_dhcpv6_validate_client_message(dhcpv6_server_ptr, &temp_client_rec);

    /* Check for errors. */
    if (status != NX_SUCCESS)
    {

        /* Return all other errors as completion status. Do not send a message to the client. */
        return(status);
    }

    if (temp_client_rec.nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) 
    {

        /* Not responding to client. So do not assign an IP address or update 
           the client record with invalid message. */
        return  NX_SUCCESS;
    }

    /* Look up the client record in the server table. If not found, or this is 
       a new request e.g. a SOLICIT message, create a new client entry in the table and 
       fill in the extracted information. */
    add_on = NX_FALSE;

    if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
    {

        /* Check first if the validation process indicates we do not reply to this message. */
        if (temp_client_rec.nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)
        {

            /* Ok to update or create a new record. */
            add_on = NX_TRUE;
        }
    }

    /* Check if the client is already in the server table. */
    status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &client_duid, &record_index, 
                                                   add_on, temp_client_rec.nx_dhcpv6_message_xid, &matching);

    /* Check for error during search. */
    if (status != NX_SUCCESS)
    {

        return(status);
    }

    /* Set a local pointer to the client record in the server table. */
    *dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[record_index];

    /* Was a match was found? */
    if (!matching)
    {

        /* No, this is a new record. Create a new client record. */
        status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr);
    }
    else
    {

        /* A match was found. Check if this is a different message request than the previous client request. */
        if ((temp_client_rec.nx_dhcpv6_message_type != (*dhcpv6_client_ptr) -> nx_dhcpv6_message_type) &&
            (received_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
        {

            /*  This is a different message from the Client. Before updating the record check the client global address 
                to be the same as what the server assigned or is offering to assign. */
            if (!CHECK_IPV6_ADDRESSES_SAME(&temp_client_rec.nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], 
                                          &(*dhcpv6_client_ptr )-> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
            {

                /* This is a different address. Disregard this message. */
                (*dhcpv6_client_ptr) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;

                return NX_SUCCESS;
            }

            /* This is a valid request. Update the client record with the new data. */
            status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr);
        }
    }

    /* Yes we're done with no processing errors detected. */
    return NX_SUCCESS;
}
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_dhcpv6_server_extract_packet_information        PORTABLE C      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function extracts data from DHCPv6 Client request packets. A   */
/*    request is checked for valid message type and required DHCPv6 data. */
/*    A client record is created if one does not exist for the client and */
/*    the data updated into it.                                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    dhcpv6_server_ptr                   Pointer to DHCPv6 server        */
/*    dhcpv6_client_ptr                   Pointer to DHCPv6 client        */
/*    packet_ptr                          Pointer to received packet      */
/*    iface_index                         Interface packet received on    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                              Actual completion status        */
/*    NX_SUCCESS                          Successful completion status    */
/*    NX_DHCPV6_ILLEGAL_MESSAGE_TYPE      Packet message type illegal     */
/*    NX_DHCPV6_BAD_TRANSACTION_ID        Message ID fails to match up    */
/*    NX_DHCPV6_PROCESSING_ERROR          Packet length is different than */
/*                                                   expected             */
/*    NX_DHCPV6_UNKNOWN_OPTION            Unknown option in message       */
/*    NX_DHCPV6_INVALID_HW_ADDRESS        Missing or invalid MAC address  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_dhcpv6_server_utility_get_data  Extract data from reply packet  */
/*    _nx_dhcpv6_server_utility_get_block_option_length                   */
/*                                        Extract option header data      */
/*    _nx_dhcpv6_process_duid             Extract DUID from Client message*/
/*    _nx_dhcpv6_process_DNS_server       Extract DNS server from message */
/*    memcpy                              Copies specified area of memory */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_dhcpv6_listen_for_messages       Waits to receive client message*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  09-30-2020     Yuxin Zhou               Modified comment(s), improved */
/*                                            packet length verification, */
/*                                            verified memcpy use cases,  */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
FUNCTION                                               RELEASE

_nx_dhcpv6_server_extract_packet_information        PORTABLE C
6.1
AUTHOR

Yuxin Zhou, Microsoft Corporation

DESCRIPTION

This function extracts data from DHCPv6 Client request packets. A
request is checked for valid message type and required DHCPv6 data.
A client record is created if one does not exist for the client and
the data updated into it.

INPUT

dhcpv6_server_ptr                   Pointer to DHCPv6 server
dhcpv6_client_ptr                   Pointer to DHCPv6 client
packet_ptr                          Pointer to received packet
iface_index                         Interface packet received on

OUTPUT

status                              Actual completion status
NX_SUCCESS                          Successful completion status
NX_DHCPV6_ILLEGAL_MESSAGE_TYPE      Packet message type illegal
NX_DHCPV6_BAD_TRANSACTION_ID        Message ID fails to match up
NX_DHCPV6_PROCESSING_ERROR          Packet length is different than
expected
NX_DHCPV6_UNKNOWN_OPTION            Unknown option in message
NX_DHCPV6_INVALID_HW_ADDRESS        Missing or invalid MAC address

CALLS

_nx_dhcpv6_server_utility_get_data  Extract data from reply packet
_nx_dhcpv6_server_utility_get_block_option_length
Extract option header data
_nx_dhcpv6_process_duid             Extract DUID from Client message
_nx_dhcpv6_process_DNS_server       Extract DNS server from message
memcpy                              Copies specified area of memory

CALLED BY

_nx_dhcpv6_listen_for_messages       Waits to receive client message

RELEASE HISTORY

DATE              NAME                      DESCRIPTION

05-19-2020     Yuxin Zhou               Initial Version 6.0
09-30-2020     Yuxin Zhou               Modified comment(s), improved
packet length verification,
verified memcpy use cases,
resulting in version 6.1
FUNCTION RELEASE _nx_dhcpv6_server_extract_packet_information PORTABLE C 6 . 1 AUTHOR Yuxin Zhou Microsoft Corporation DESCRIPTION This function extracts data from DHCPv6 Client request packets . A request is checked for valid message type and required DHCPv6 data . A client record is created if one does not exist for the client and the data updated into it . INPUT dhcpv6_server_ptr Pointer to DHCPv6 server dhcpv6_client_ptr Pointer to DHCPv6 client packet_ptr Pointer to received packet iface_index Interface packet received on OUTPUT status Actual completion status NX_SUCCESS Successful completion status NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up NX_DHCPV6_PROCESSING_ERROR Packet length is different than expected NX_DHCPV6_UNKNOWN_OPTION Unknown option in message NX_DHCPV6_INVALID_HW_ADDRESS Missing or invalid MAC address CALLS _nx_dhcpv6_server_utility_get_data Extract data from reply packet _nx_dhcpv6_server_utility_get_block_option_length Extract option header data _nx_dhcpv6_process_duid Extract DUID from Client message _nx_dhcpv6_process_DNS_server Extract DNS server from message memcpy Copies specified area of memory CALLED BY _nx_dhcpv6_listen_for_messages Waits to receive client message RELEASE HISTORY DATE NAME DESCRIPTION 05 - 19 - 2020 Yuxin Zhou Initial Version 6 . 0 09 - 30 - 2020 Yuxin Zhou Modified comment ( s ) improved packet length verification verified memcpy use cases resulting in version 6 . 1
UINT  _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, 
                                                   UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address)
{
UINT                status;
UINT                add_on;
UINT                record_index;
ULONG               option_code;
ULONG               option_length;
UCHAR               *buffer_ptr;
UINT                index;
ULONG               returned_xid;
NX_DHCPV6_SVR_DUID  client_duid, server_duid;
UINT                client_duid_received;
UINT                server_duid_received;
NX_DHCPV6_CLIENT    temp_client_rec;
ULONG               received_message_type;
UINT                matching;
    NX_PARAMETER_NOT_USED(iface_index);
    *dhcpv6_client_ptr = NX_NULL;
    memset(&temp_client_rec, 0, sizeof(NX_DHCPV6_CLIENT));
    temp_client_rec.nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID;
    temp_client_rec.nx_dhcpv6_state =  NX_DHCPV6_STATE_UNBOUND;
    if (packet_ptr -> nx_packet_length < 4)
    {
        return NX_DHCPV6_PROCESSING_ERROR;
    }
    buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
    index = 0;
    client_duid_received = NX_FALSE;
    server_duid_received = NX_FALSE;
    _nx_dhcpv6_server_utility_get_data(buffer_ptr, 1, &received_message_type);
    if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) ||
        (received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
    {
        return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE;
    }
    COPY_IPV6_ADDRESS(&source_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_address.v6[0]);
    temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
    COPY_IPV6_ADDRESS(&destination_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
    temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
    buffer_ptr++;
    _nx_dhcpv6_server_utility_get_data(buffer_ptr, 3, &returned_xid);
    temp_client_rec.nx_dhcpv6_message_type = received_message_type;
    temp_client_rec.nx_dhcpv6_message_xid = returned_xid;
    buffer_ptr += 3;
    index += 4;
    while (index + 4 <= packet_ptr -> nx_packet_length)
    {
        status = _nx_dhcpv6_server_utility_get_block_option_length(buffer_ptr, &option_code, &option_length);
        if (status != NX_SUCCESS)
        {
            return status;
        }
        index += option_length + 4; 
        if (index > packet_ptr -> nx_packet_length)
        {
            return NX_DHCPV6_PROCESSING_ERROR;
        }
        buffer_ptr += 4;
        switch (option_code)
        {
            case NX_DHCPV6_OP_DUID_CLIENT:
                client_duid.nx_op_code = (USHORT)option_code;
                client_duid.nx_option_length = (USHORT)option_length;
                status = _nx_dhcpv6_process_duid(&client_duid, option_code, option_length, buffer_ptr);
                if (status != NX_SUCCESS)
                {
                    return status;
                }
                memcpy(&temp_client_rec.nx_dhcpv6_client_duid, &client_duid, sizeof(NX_DHCPV6_SVR_DUID)); 
                client_duid_received = NX_TRUE;
            break;
            case NX_DHCPV6_OP_DUID_SERVER:
                server_duid.nx_op_code = (USHORT)option_code;
                server_duid.nx_option_length = (USHORT)option_length;
                status = _nx_dhcpv6_process_duid(&server_duid, option_code, option_length, buffer_ptr);
                if (status != NX_SUCCESS)
                {
                    return status;
                }
                memcpy(&temp_client_rec.nx_dhcpv6_server_duid, &server_duid, sizeof(NX_DHCPV6_SVR_DUID)); 
                server_duid_received = NX_TRUE;
            break;
            case NX_DHCPV6_OP_IA_NA:
                status = _nx_dhcpv6_server_process_iana(&temp_client_rec, option_code, option_length, buffer_ptr);
                if (status != NX_SUCCESS)
                {
                    return status;
                }
            break;
            case NX_DHCPV6_OP_IA_ADDRESS:
                status = NX_DHCPV6_IANA_OPTION_MISSING;
            break;
            case NX_DHCPV6_OP_OPTION_REQUEST:
                status = _nx_dhcpv6_process_option_request(&temp_client_rec, option_code, option_length, buffer_ptr);
                if (status != NX_SUCCESS)
                {
                    return status;
                }
            break;
            case NX_DHCPV6_OP_ELAPSED_TIME:
                status = _nx_dhcpv6_process_elapsed_time(&temp_client_rec, option_code, option_length, buffer_ptr); 
                if (status != NX_SUCCESS)
                {
                    return status;
                }
            break;
            default:
                break; 
        }
        if (status != NX_SUCCESS)
        {
            return status;
        }
         buffer_ptr += option_length;
    }
    if (index != packet_ptr -> nx_packet_length)
    {
        return NX_DHCPV6_PROCESSING_ERROR;
    }
    if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
        (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
    {
        if (!client_duid_received)
        {
            return NX_DHCPV6_MESSAGE_DUID_MISSING;
        }
    }
    else if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
             (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW)   ||
             (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE))
    {
        if (!server_duid_received || !client_duid_received)
        {
            return NX_DHCPV6_MESSAGE_DUID_MISSING;
        }
    }
    else if (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)
    {
        if (temp_client_rec.nx_dhcpv6_ia.nx_op_code != 0)
        {
            return NX_DHCPV6_INVALID_IA_DATA;
        }
    }
    status = _nx_dhcpv6_validate_client_message(dhcpv6_server_ptr, &temp_client_rec);
    if (status != NX_SUCCESS)
    {
        return(status);
    }
    if (temp_client_rec.nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) 
    {
        return  NX_SUCCESS;
    }
    add_on = NX_FALSE;
    if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) ||
        (received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
    {
        if (temp_client_rec.nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)
        {
            add_on = NX_TRUE;
        }
    }
    status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &client_duid, &record_index, 
                                                   add_on, temp_client_rec.nx_dhcpv6_message_xid, &matching);
    if (status != NX_SUCCESS)
    {
        return(status);
    }
    *dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[record_index];
    if (!matching)
    {
        status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr);
    }
    else
    {
        if ((temp_client_rec.nx_dhcpv6_message_type != (*dhcpv6_client_ptr) -> nx_dhcpv6_message_type) &&
            (received_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
        {
            if (!CHECK_IPV6_ADDRESSES_SAME(&temp_client_rec.nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], 
                                          &(*dhcpv6_client_ptr )-> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
            {
                (*dhcpv6_client_ptr) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
                return NX_SUCCESS;
            }
            status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr);
        }
    }
    return NX_SUCCESS;
}
UINT _nx_dhcpv6_server_extract_packet_information ( NX_DHCPV6_SERVER * dhcpv6_server_ptr , NX_DHCPV6_CLIENT * * dhcpv6_client_ptr , NX_PACKET * packet_ptr , UINT iface_index , NXD_ADDRESS source_address , NXD_ADDRESS destination_address ) { UINT status ; UINT add_on ; UINT record_index ; ULONG option_code ; ULONG option_length ; UCHAR * buffer_ptr ; UINT index ; ULONG returned_xid ; NX_DHCPV6_SVR_DUID client_duid , server_duid ; UINT client_duid_received ; UINT server_duid_received ; NX_DHCPV6_CLIENT temp_client_rec ; ULONG received_message_type ; UINT matching ; NX_PARAMETER_NOT_USED ( iface_index ) ; * dhcpv6_client_ptr = NX_NULL ; memset ( & temp_client_rec , 0 , sizeof ( NX_DHCPV6_CLIENT ) ) ; temp_client_rec . nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID ; temp_client_rec . nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND ; if ( packet_ptr -> nx_packet_length < 4 ) { return NX_DHCPV6_PROCESSING_ERROR ; } buffer_ptr = packet_ptr -> nx_packet_prepend_ptr ; index = 0 ; client_duid_received = NX_FALSE ; server_duid_received = NX_FALSE ; _nx_dhcpv6_server_utility_get_data ( buffer_ptr , 1 , & received_message_type ) ; if ( ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE ) || ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY ) || ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE ) || ( received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST ) ) { return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE ; } COPY_IPV6_ADDRESS ( & source_address . nxd_ip_address . v6 [ 0 ] , & temp_client_rec . nx_dhcp_source_ip_address . nxd_ip_address . v6 [ 0 ] ) ; temp_client_rec . nx_dhcp_source_ip_address . nxd_ip_version = NX_IP_VERSION_V6 ; COPY_IPV6_ADDRESS ( & destination_address . nxd_ip_address . v6 [ 0 ] , & temp_client_rec . nx_dhcp_destination_ip_address . nxd_ip_address . v6 [ 0 ] ) ; temp_client_rec . nx_dhcp_destination_ip_address . nxd_ip_version = NX_IP_VERSION_V6 ; buffer_ptr ++ ; _nx_dhcpv6_server_utility_get_data ( buffer_ptr , 3 , & returned_xid ) ; temp_client_rec . nx_dhcpv6_message_type = received_message_type ; temp_client_rec . nx_dhcpv6_message_xid = returned_xid ; buffer_ptr += 3 ; index += 4 ; while ( index + 4 <= packet_ptr -> nx_packet_length ) { status = _nx_dhcpv6_server_utility_get_block_option_length ( buffer_ptr , & option_code , & option_length ) ; if ( status != NX_SUCCESS ) { return status ; } index += option_length + 4 ; if ( index > packet_ptr -> nx_packet_length ) { return NX_DHCPV6_PROCESSING_ERROR ; } buffer_ptr += 4 ; switch ( option_code ) { case NX_DHCPV6_OP_DUID_CLIENT : client_duid . nx_op_code = ( USHORT ) option_code ; client_duid . nx_option_length = ( USHORT ) option_length ; status = _nx_dhcpv6_process_duid ( & client_duid , option_code , option_length , buffer_ptr ) ; if ( status != NX_SUCCESS ) { return status ; } memcpy ( & temp_client_rec . nx_dhcpv6_client_duid , & client_duid , sizeof ( NX_DHCPV6_SVR_DUID ) ) ; client_duid_received = NX_TRUE ; break ; case NX_DHCPV6_OP_DUID_SERVER : server_duid . nx_op_code = ( USHORT ) option_code ; server_duid . nx_option_length = ( USHORT ) option_length ; status = _nx_dhcpv6_process_duid ( & server_duid , option_code , option_length , buffer_ptr ) ; if ( status != NX_SUCCESS ) { return status ; } memcpy ( & temp_client_rec . nx_dhcpv6_server_duid , & server_duid , sizeof ( NX_DHCPV6_SVR_DUID ) ) ; server_duid_received = NX_TRUE ; break ; case NX_DHCPV6_OP_IA_NA : status = _nx_dhcpv6_server_process_iana ( & temp_client_rec , option_code , option_length , buffer_ptr ) ; if ( status != NX_SUCCESS ) { return status ; } break ; case NX_DHCPV6_OP_IA_ADDRESS : status = NX_DHCPV6_IANA_OPTION_MISSING ; break ; case NX_DHCPV6_OP_OPTION_REQUEST : status = _nx_dhcpv6_process_option_request ( & temp_client_rec , option_code , option_length , buffer_ptr ) ; if ( status != NX_SUCCESS ) { return status ; } break ; case NX_DHCPV6_OP_ELAPSED_TIME : status = _nx_dhcpv6_process_elapsed_time ( & temp_client_rec , option_code , option_length , buffer_ptr ) ; if ( status != NX_SUCCESS ) { return status ; } break ; default : break ; } if ( status != NX_SUCCESS ) { return status ; } buffer_ptr += option_length ; } if ( index != packet_ptr -> nx_packet_length ) { return NX_DHCPV6_PROCESSING_ERROR ; } if ( ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT ) || ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND ) ) { if ( ! client_duid_received ) { return NX_DHCPV6_MESSAGE_DUID_MISSING ; } } else if ( ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST ) || ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW ) || ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE ) ) { if ( ! server_duid_received || ! client_duid_received ) { return NX_DHCPV6_MESSAGE_DUID_MISSING ; } } else if ( temp_client_rec . nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST ) { if ( temp_client_rec . nx_dhcpv6_ia . nx_op_code != 0 ) { return NX_DHCPV6_INVALID_IA_DATA ; } } status = _nx_dhcpv6_validate_client_message ( dhcpv6_server_ptr , & temp_client_rec ) ; if ( status != NX_SUCCESS ) { return ( status ) ; } if ( temp_client_rec . nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT ) { return NX_SUCCESS ; } add_on = NX_FALSE ; if ( ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT ) || ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM ) || ( received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST ) ) { if ( temp_client_rec . nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT ) { add_on = NX_TRUE ; } } status = _nx_dhcpv6_find_client_record_by_duid ( dhcpv6_server_ptr , & client_duid , & record_index , add_on , temp_client_rec . nx_dhcpv6_message_xid , & matching ) ; if ( status != NX_SUCCESS ) { return ( status ) ; } * dhcpv6_client_ptr = & dhcpv6_server_ptr -> nx_dhcpv6_clients [ record_index ] ; if ( ! matching ) { status = _nx_dhcpv6_update_client_record ( dhcpv6_server_ptr , & temp_client_rec , * dhcpv6_client_ptr ) ; } else { if ( ( temp_client_rec . nx_dhcpv6_message_type != ( * dhcpv6_client_ptr ) -> nx_dhcpv6_message_type ) && ( received_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST ) ) { if ( ! CHECK_IPV6_ADDRESSES_SAME ( & temp_client_rec . nx_dhcpv6_ia . nx_global_address . nxd_ip_address . v6 [ 0 ] , & ( * dhcpv6_client_ptr ) -> nx_dhcpv6_ia . nx_global_address . nxd_ip_address . v6 [ 0 ] ) ) { ( * dhcpv6_client_ptr ) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT ; return NX_SUCCESS ; } status = _nx_dhcpv6_update_client_record ( dhcpv6_server_ptr , & temp_client_rec , * dhcpv6_client_ptr ) ; } } return NX_SUCCESS ; }
FUNCTION                                               RELEASE
FUNCTION RELEASE
/* Create a scratch record for this client so we can qualify it before adding it to the server table. */ /* Initialize the record with the DHCPv6 Client ID. */ /* Assume the Client is not bound to an IP address yet.  */ /* Check packet for message type and transaction ID. */ /* Reported length of the packet may be incorrect.  */ /* Set a pointer to the start of DHCPv6 data. */ /* Initialize local variables. */ /* Extract the message type which should be the first byte.  */ /* Check for an illegal message type. */ /* These should only be sent to DHCPv6 clients! The Inform Request is actually
           legal to receive but should NOT be used to add clients to the server table. */ /* Copy the source address to the Client record. */ /* Copy the destination address to the Client record. */ /* Advance to the data pointer. */ /* Parse the transaction ID. */ /* Set the message ID. The server will need this to reply to the Client. */ /* Update index for message type and transaction ID.  */ /* Now parse all the DHCPv6 option blocks in the packet buffer. */ /* 4 bytes for option code and option length. */ /* Get the option code and length of data of the current option block. */ /* Check that the block data is valid. */ /* No, return the error status. */ /* Keep track of how far into the packet we have parsed. */ /* This is a double check to verify we haven't gone off the end of the packet buffer. */ /* Reported length of the packet may be incorrect. At any rate, we don't know
               exactly what the end of the message is, so abort. */ /* Update buffer pointer to option data.  */ /* Process the option code with an option specific API. */ /* Note - these 'process' functions will not move the buffer pointer. */ /*  Copy to the temporary client record. */ /* Use case of memcpy is verified. */ /* Indicate the message contained the required Client DUID. */ /*  Copy to the temporary client record. */ /* Use case of memcpy is verified. */ /* Indicate the message contained the required Server DUID. */ /* This should not happen. The IA address option must be embedded in the IANA option. */ /* Don't process an IA address option outside of an address association (IANA). */ /* Option request option contains request usually for network configuration parameters
                   such as the DNS server. */ /* The elapsed time is time elapsed since the client initiated the IP lease request. */ /* Check for errors from option block processing. */ /* Move to the next top level option. */ /* Check for an improperly formatted packet. */ /* If we get here if we are not at the expected end of the buffer. Oops */ /* Check if the message is missing the required DUID(s). */ /* The following message types must include a client and server DUID. */ /* An inform request only requires a server DUID. */ /* The Inform request message should NOT include an IA. */ /* Validate the client message, and determine how (if) the server should respond to it. */ /* Check for errors. */ /* Return all other errors as completion status. Do not send a message to the client. */ /* Not responding to client. So do not assign an IP address or update 
           the client record with invalid message. */ /* Look up the client record in the server table. If not found, or this is 
       a new request e.g. a SOLICIT message, create a new client entry in the table and 
       fill in the extracted information. */ /* Check first if the validation process indicates we do not reply to this message. */ /* Ok to update or create a new record. */ /* Check if the client is already in the server table. */ /* Check for error during search. */ /* Set a local pointer to the client record in the server table. */ /* Was a match was found? */ /* No, this is a new record. Create a new client record. */ /* A match was found. Check if this is a different message request than the previous client request. */ /*  This is a different message from the Client. Before updating the record check the client global address 
                to be the same as what the server assigned or is offering to assign. */ /* This is a different address. Disregard this message. */ /* This is a valid request. Update the client record with the new data. */ /* Yes we're done with no processing errors detected. */