mirror of https://github.com/ARMmbed/mbed-os.git
799 lines
26 KiB
C
799 lines
26 KiB
C
/*
|
|
* Copyright (c) 2014-2017, Arm Limited and affiliates.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* \file libDHCPv6.c
|
|
* \brief Add short description about this file!!!
|
|
*
|
|
*/
|
|
#include "nsconfig.h"
|
|
#include <string.h>
|
|
#include <ns_types.h>
|
|
#include "ns_trace.h"
|
|
#include "common_functions.h"
|
|
#include "libDHCPv6/libDHCPv6.h"
|
|
#include "randLIB.h"
|
|
#include "nsdynmemLIB.h"
|
|
#ifdef HAVE_DHCPV6
|
|
#define TRACE_GROUP "dhcp"
|
|
|
|
|
|
static NS_LARGE NS_LIST_DEFINE(dhcpv6_client_nonTemporal_list, dhcpv6_client_server_data_t, link);
|
|
|
|
//Allocate
|
|
static dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_entry_allocate(void)
|
|
{
|
|
dhcpv6_client_server_data_t *newEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_client_server_data_t));
|
|
if (newEntry) {
|
|
newEntry->T0 = 0;
|
|
newEntry->T1 = 0;
|
|
newEntry->reNewTimer = 0;
|
|
newEntry->iaNonTemporalStructValid = false;
|
|
newEntry->GlobalAddress = false;
|
|
newEntry->useServerAddress = false;
|
|
newEntry->iaNontemporalAddress.preferredTime = 0;
|
|
newEntry->iaNontemporalAddress.validLifetime = 0;
|
|
}
|
|
return newEntry;
|
|
}
|
|
|
|
static uint32_t libdhcpv6_IAID_generate(void)
|
|
{
|
|
uint32_t iaId;
|
|
bool notUnique = true;
|
|
while (notUnique) {
|
|
notUnique = false;
|
|
iaId = randLIB_get_32bit();
|
|
if (libdhcpv6_nonTemporal_entry_get_by_iaid(iaId)) {
|
|
notUnique = true;
|
|
}
|
|
|
|
}
|
|
return iaId;
|
|
}
|
|
|
|
static uint32_t libdhcpv6_Tx_timer_generate(uint32_t lifetime, bool T1_get)
|
|
{
|
|
uint32_t timeout = lifetime;
|
|
|
|
if (T1_get) {
|
|
timeout = (timeout >> 1);
|
|
} else {
|
|
timeout = (timeout >> 2);
|
|
timeout = (timeout * 3);
|
|
}
|
|
|
|
return timeout;
|
|
}
|
|
|
|
uint32_t libdhcpv6_txid_get(void)
|
|
{
|
|
uint32_t transaction_id = randLIB_get_32bit();
|
|
transaction_id &= 0x00ffffff;
|
|
return transaction_id;
|
|
}
|
|
|
|
uint32_t libdhcpv6_renew_time_define(dhcpv6_client_server_data_t *addresInfo)
|
|
{
|
|
uint32_t renewTimer = 0xffffffff;
|
|
|
|
if (addresInfo->iaNontemporalAddress.preferredTime < renewTimer) {
|
|
renewTimer = addresInfo->iaNontemporalAddress.preferredTime;
|
|
}
|
|
|
|
if (renewTimer == 0xffffffff) {
|
|
//Check T1
|
|
renewTimer = 0;
|
|
} else if (renewTimer < 100) {
|
|
renewTimer = 100;
|
|
}
|
|
|
|
if (addresInfo->T0 == 0) {
|
|
//Calculate
|
|
if (renewTimer != 0) {
|
|
addresInfo->T0 = libdhcpv6_Tx_timer_generate(renewTimer, true);
|
|
addresInfo->T1 = libdhcpv6_Tx_timer_generate(renewTimer, false);
|
|
} else {
|
|
addresInfo->T0 = 0xffffffff;
|
|
addresInfo->T1 = 0xffffffff;
|
|
}
|
|
}
|
|
|
|
//Calculate Renew Time
|
|
if (addresInfo->T0 != 0xffffffff) {
|
|
renewTimer = addresInfo->T0;
|
|
} else {
|
|
renewTimer = 0;
|
|
}
|
|
|
|
return renewTimer;
|
|
}
|
|
|
|
dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *duiId, uint16_t duiLinkType, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address)
|
|
{
|
|
uint32_t iaId;
|
|
dhcpv6_client_server_data_t *new_entry = NULL;
|
|
if (duiId) {
|
|
//allocate new Entry
|
|
iaId = libdhcpv6_IAID_generate();
|
|
new_entry = libdhcvp6_nontemporalAddress_entry_allocate();
|
|
if (new_entry) {
|
|
new_entry->IAID = iaId;
|
|
new_entry->interfaceId = interfaceId;
|
|
new_entry->instanceId = instanceId;
|
|
//save Cliet ID
|
|
memcpy(new_entry->clientId, duiId, 8);
|
|
new_entry->clientLinkIdType = duiLinkType;
|
|
if (serverIPv6Address) {
|
|
memcpy(new_entry->server_address, serverIPv6Address, 16);
|
|
new_entry->useServerAddress = true;
|
|
}
|
|
if (nonTemporalPrefix) {
|
|
uint8_t *ptr = new_entry->iaNontemporalAddress.addressPrefix;
|
|
memcpy(ptr, nonTemporalPrefix, 8);
|
|
memset((ptr + 8), 0, 8);
|
|
new_entry->iaNonTemporalStructValid = true;
|
|
new_entry->iaNontemporalAddress.preferredTime = 0;
|
|
new_entry->iaNontemporalAddress.validLifetime = 0;
|
|
}
|
|
ns_list_add_to_end(&dhcpv6_client_nonTemporal_list, new_entry);
|
|
}
|
|
}
|
|
return new_entry;
|
|
}
|
|
|
|
void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *removedEntry)
|
|
{
|
|
if (removedEntry) {
|
|
ns_list_remove(&dhcpv6_client_nonTemporal_list, removedEntry);
|
|
ns_dyn_mem_free(removedEntry);
|
|
}
|
|
}
|
|
|
|
dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_instance(uint8_t instanceId)
|
|
{
|
|
ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
|
|
if (cur->instanceId == instanceId) {
|
|
return cur;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
uint8_t libdhcpv6_nonTemporal_entry_get_unique_instance_id(void)
|
|
{
|
|
uint8_t unique_id = 1;
|
|
ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
|
|
if (cur->instanceId == unique_id) {
|
|
unique_id++;
|
|
cur = ns_list_get_first(&dhcpv6_client_nonTemporal_list);
|
|
}
|
|
}
|
|
return unique_id;
|
|
}
|
|
|
|
dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_iaid(uint32_t iaId)
|
|
{
|
|
ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
|
|
if (cur->IAID == iaId) {
|
|
return cur;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_transactionId(uint32_t txId)
|
|
{
|
|
ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
|
|
if (cur->transActionId == txId) {
|
|
return cur;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t interfaceId, uint8_t *prefix)
|
|
{
|
|
ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
|
|
if ((cur->interfaceId == interfaceId) && cur->iaNonTemporalStructValid) {
|
|
if (memcmp(cur->iaNontemporalAddress.addressPrefix, prefix , 8) == 0) {
|
|
return cur;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
uint16_t libdhcpv6_duid_option_size(uint16_t linkType)
|
|
{
|
|
uint16_t length = 8; // Type & Length header part *2
|
|
if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) {
|
|
length += 8;
|
|
} else {
|
|
length += 6;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
uint16_t libdhcpv6_client_data_option_size(uint16_t linkType)
|
|
{
|
|
uint16_t optionLength = 4;
|
|
optionLength += libdhcpv6_duid_option_size(linkType);
|
|
optionLength += libdhcpv6_ia_address_option_size();
|
|
optionLength += libdhcpv6_client_last_transaction_time_option_size();
|
|
return optionLength;
|
|
}
|
|
|
|
uint16_t libdhcvp6_request_option_size(uint8_t optionCnt)
|
|
{
|
|
uint16_t optionLength = 4;
|
|
optionLength += 2 * optionCnt;
|
|
return optionLength;
|
|
}
|
|
|
|
uint16_t libdhcpv6_non_temporal_address_size(bool addressDefined)
|
|
{
|
|
uint16_t optionLength = 16;
|
|
if (addressDefined) {
|
|
optionLength += libdhcpv6_ia_address_option_size();
|
|
}
|
|
return optionLength;
|
|
}
|
|
|
|
int libdhcpv6_message_malformed_check(uint8_t *ptr, uint16_t data_len)
|
|
{
|
|
uint8_t *dptr;
|
|
uint16_t length;
|
|
if (data_len > 4) {
|
|
dptr = ptr + 4; //Skip Type & TXID
|
|
data_len -= 4;
|
|
while (data_len) {
|
|
if (data_len >= 4) {
|
|
|
|
length = common_read_16_bit(dptr + 2); //Skip Type
|
|
dptr += 4;
|
|
data_len -= 4;
|
|
if (data_len >= length) {
|
|
data_len -= length;
|
|
dptr += length;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* This Function write dhcpv6 basic header
|
|
*
|
|
* \param ptr pointer where header will be writed
|
|
* \param msgType dhcpv6 message type
|
|
* \param transActionId 24-bit unique Trasnaction ID
|
|
*
|
|
* return incremented pointer after write
|
|
*/
|
|
uint8_t *libdhcpv6_header_write(uint8_t *ptr, uint8_t msgType, uint32_t transActionId)
|
|
{
|
|
*ptr++ = msgType;
|
|
ptr = common_write_24_bit(transActionId, ptr);
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_elapsed_time_option_write(uint8_t *ptr, uint16_t elapsedTime)
|
|
{
|
|
//Elapsed time
|
|
ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION_LEN, ptr);
|
|
ptr = common_write_16_bit(elapsedTime, ptr);
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr)
|
|
{
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT_LEN, ptr);
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcvp6_vendor_specific_option_write(uint8_t *ptr, uint8_t *data, uint16_t dataLength)
|
|
{
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_VENDOR_SPECIFIC_INFO, ptr);
|
|
ptr = common_write_16_bit(dataLength, ptr);
|
|
memcpy(ptr, data, dataLength);
|
|
ptr += dataLength;
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_t *optionPtr)
|
|
{
|
|
uint16_t optionLength = libdhcvp6_request_option_size(optionCnt);
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_REQUEST_OPTION, ptr);
|
|
ptr = common_write_16_bit((optionLength - 4), ptr);
|
|
while (optionCnt) {
|
|
ptr = common_write_16_bit(*optionPtr++, ptr);
|
|
optionCnt--;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_link_options_params_t *duid)
|
|
{
|
|
uint16_t length = libdhcpv6_duid_option_size(duid->linkType);
|
|
|
|
length -= 4; //Cut normal option header out
|
|
ptr = common_write_16_bit(duidRole, ptr);
|
|
ptr = common_write_16_bit(length, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_DUID_LINK_LAYER_TYPE, ptr);
|
|
ptr = common_write_16_bit(duid->linkType, ptr);
|
|
length -= 4; //Cut normal option header out
|
|
memcpy(ptr, duid->linkID, length);
|
|
ptr += length;
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_prefix_delegation_info_option_write(uint8_t *ptr, uint32_t iaId)
|
|
{
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION_MIN_LENGTH, ptr);
|
|
ptr = common_write_32_bit(iaId, ptr);
|
|
ptr = common_write_32_bit(0, ptr); //T1
|
|
ptr = common_write_32_bit(0, ptr);//T2
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_identity_association_option_write(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, bool withAddress)
|
|
{
|
|
uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(withAddress);
|
|
|
|
ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
|
|
ptr = common_write_16_bit((optionMsgLen - 4), ptr);
|
|
|
|
ptr = common_write_32_bit(iaID, ptr); //iaId
|
|
ptr = common_write_32_bit(TimerT1, ptr); //T1
|
|
ptr = common_write_32_bit(TimerT2, ptr);//T2
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_identity_association_option_write_with_status(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, uint16_t status)
|
|
{
|
|
uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(false);
|
|
|
|
optionMsgLen += 6; // add status option length
|
|
|
|
ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
|
|
ptr = common_write_16_bit((optionMsgLen - 4), ptr);
|
|
|
|
ptr = common_write_32_bit(iaID, ptr); //iaId
|
|
ptr = common_write_32_bit(TimerT1, ptr); //T1
|
|
ptr = common_write_32_bit(TimerT2, ptr);//T2
|
|
ptr = libdhcpv6_status_code_write(ptr, status);
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_ia_address_option_write(uint8_t *ptr, const uint8_t *addressPtr, uint32_t preferredValidLifeTime, uint32_t validLifeTime)
|
|
{
|
|
ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION_LEN, ptr);
|
|
memcpy(ptr, addressPtr, 16);
|
|
ptr += 16;
|
|
ptr = common_write_32_bit(preferredValidLifeTime, ptr); //Preferred
|
|
ptr = common_write_32_bit(validLifeTime, ptr);//Valid
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_status_code_write(uint8_t *ptr, uint16_t statusCode)
|
|
{
|
|
ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION, ptr);
|
|
ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION_LEN, ptr);
|
|
ptr = common_write_16_bit(statusCode, ptr);
|
|
return ptr;
|
|
}
|
|
|
|
uint8_t *libdhcpv6_client_last_transaction_time_option_write(uint8_t *ptr, uint32_t last_transaction_Time)
|
|
{
|
|
|
|
uint16_t Length = libdhcpv6_client_last_transaction_time_option_size();
|
|
ptr = common_write_16_bit(DHCPV6_OPTION_CLT_TIME, ptr);
|
|
ptr = common_write_16_bit((Length - 4), ptr);
|
|
ptr = common_write_32_bit(last_transaction_Time, ptr); //SET Last time we heard from this child either from mle or data packets.
|
|
return ptr;
|
|
}
|
|
|
|
int libdhcpv6_message_option_discover(uint8_t *ptr, uint16_t data_len, uint16_t discovered_type, dhcp_options_msg_t *option_info)
|
|
{
|
|
uint8_t *dptr;
|
|
uint16_t type, length;
|
|
dptr = ptr;
|
|
if( data_len < 4 ){
|
|
tr_warn("libdhcpv6_message_option_discover() data_len<4");
|
|
return -1;
|
|
}
|
|
while (data_len >= 4) {
|
|
type = common_read_16_bit(dptr);
|
|
dptr += 2;
|
|
length = common_read_16_bit(dptr);
|
|
dptr += 2;
|
|
data_len -= 4;
|
|
if (data_len >= length) {
|
|
if (type == discovered_type) {
|
|
option_info->len = length;
|
|
option_info->type = type;
|
|
option_info->msg_ptr = dptr;
|
|
return 0;
|
|
}
|
|
data_len -= length;
|
|
dptr += length;
|
|
} else {
|
|
tr_warn("libdhcpv6_message_option_discover() data_len<length=%"PRIu16, length);
|
|
break;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int libdhcpv6_compare_DUID(dhcp_link_options_params_t *targetId, dhcp_link_options_params_t *parsedId)
|
|
{
|
|
if (targetId->linkType == parsedId->linkType) {
|
|
uint8_t cmpLen;
|
|
if (targetId->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) {
|
|
//Compare Current Interface EUID64
|
|
cmpLen = 8;
|
|
} else {
|
|
cmpLen = 6;
|
|
}
|
|
if (memcmp(targetId->linkID, parsedId->linkID, cmpLen) == 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int libdhcpv6_reply_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
|
|
{
|
|
/**
|
|
* Solication Message Should Include Next Options:
|
|
* - DHCPV6_SERVER_ID_OPTION
|
|
* - DHCPV6_CLIENT_ID_OPTION
|
|
* - DHCPV6_IDENTITY_ASSOCIATION_OPTION
|
|
*
|
|
*/
|
|
/** Verify Client ID */
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION , clientId) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int libdhcpv6_advertisment_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
|
|
{
|
|
/**
|
|
* Solication Message Should Include Next Options:
|
|
* - DHCPV6_SERVER_ID_OPTION
|
|
* - DHCPV6_CLIENT_ID_OPTION
|
|
* - DHCPV6_IDENTITY_ASSOCIATION_OPTION
|
|
*
|
|
*/
|
|
/** Verify Client ID to own EUID64 */
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION , clientId) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#ifdef HAVE_DHCPV6_SERVER
|
|
int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLinkData, dhcp_link_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
|
|
{
|
|
|
|
/**
|
|
* Renew Message Should Include Next Options:
|
|
* - DHCPV6_ELAPSED_TIME_OPTION
|
|
* - DHCPV6_CLIENT_ID_OPTION
|
|
* - DHCPV6_SERVER_ID_OPTION
|
|
* - DHCPV6_IDENTITY_ASSOCIATION_OPTION
|
|
* - DHCPV6_OPTION_REQUEST_OPTION
|
|
* Optionally:
|
|
* - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
|
|
*/
|
|
|
|
/** Verify First DHCPV6_ELAPSED_TIME_OPTION */
|
|
if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
|
|
return -1;
|
|
}
|
|
/** Verify DHCPV6_CLIENT_ID_OPTION */
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLinkData) != 0) {
|
|
return -1;
|
|
}
|
|
/** Verify DHCPV6_SERVER_ID_OPTION */
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverLinkData) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
/** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
|
|
if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
|
|
{
|
|
/**
|
|
* Solication Message Should Include Next Options:
|
|
* - DHCPV6_ELAPSED_TIME_OPTION
|
|
* - DHCPV6_CLIENT_ID_OPTION
|
|
* - DHCPV6_IDENTITY_ASSOCIATION_OPTION
|
|
* - DHCPV6_OPTION_REQUEST_OPTION
|
|
* Optionally:
|
|
* - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
|
|
*/
|
|
/** Verify First DHCPV6_ELAPSED_TIME_OPTION */
|
|
|
|
if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
|
|
return -1;
|
|
}
|
|
/** Verify DHCPV6_CLIENT_ID_OPTION */
|
|
if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLink) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
/** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
|
|
if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
bool libdhcpv6_time_elapsed_option_at_packet(uint8_t *ptr, uint16_t length)
|
|
{
|
|
bool retVal = false;
|
|
dhcp_options_msg_t option_msg;
|
|
/** Verify First DHCPV6_ELAPSED_TIME_OPTION */
|
|
|
|
if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_ELAPSED_TIME_OPTION, &option_msg) == 0) {
|
|
if (option_msg.len == DHCPV6_ELAPSED_TIME_OPTION_LEN) {
|
|
retVal = true;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length)
|
|
{
|
|
bool retVal = false;
|
|
dhcp_options_msg_t option_msg;
|
|
if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_OPTION_RAPID_COMMIT, &option_msg) == 0) {
|
|
retVal = true;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type , dhcp_link_options_params_t *params)
|
|
{
|
|
dhcp_options_msg_t option_msg;
|
|
|
|
/** Verify DHCPV6_CLIENT_ID_OPTION */
|
|
if (libdhcpv6_message_option_discover(ptr, data_length, type, &option_msg) == 0) {
|
|
if (option_msg.len >= DHCPV6_SERVER_ID_MAC48_OPTION_LEN) {
|
|
uint8_t *t_ptr = option_msg.msg_ptr;
|
|
type = common_read_16_bit(t_ptr);
|
|
t_ptr += 2;
|
|
params->linkType = common_read_16_bit(t_ptr);
|
|
t_ptr += 2;
|
|
if (type == DHCPV6_DUID_LINK_LAYER_TYPE) {
|
|
params->linkID = t_ptr;
|
|
if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC48_OPTION_LEN)) {
|
|
return 0;
|
|
} else if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params)
|
|
{
|
|
dhcp_options_msg_t option_msg;
|
|
uint16_t status_code = 0;
|
|
|
|
if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
|
|
if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
|
|
status_code = common_read_16_bit(option_msg.msg_ptr);
|
|
if (status_code == DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_IDENTITY_ASSOCIATION_OPTION, &option_msg) == 0) {
|
|
if (option_msg.len < DHCPV6_IDENTITY_ASSOCIATION_OPTION_MIN_LEN) {
|
|
return -1;
|
|
}
|
|
uint8_t *t_ptr;
|
|
uint16_t length;
|
|
t_ptr = option_msg.msg_ptr;
|
|
length = (option_msg.len - 12);
|
|
params->iaId = common_read_32_bit(t_ptr);
|
|
t_ptr += 4;
|
|
params->T0 = common_read_32_bit(t_ptr);
|
|
t_ptr += 4;
|
|
params->T1 = common_read_32_bit(t_ptr);
|
|
t_ptr += 4;
|
|
|
|
if(length > 4) {
|
|
if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
|
|
if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
|
|
status_code = common_read_16_bit(option_msg.msg_ptr);
|
|
if (status_code != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_IA_ADDRESS_OPTION, &option_msg) == 0) {
|
|
if (option_msg.len >= DHCPV6_IA_ADDRESS_OPTION_LEN) {
|
|
t_ptr = option_msg.msg_ptr;
|
|
params->nonTemporalAddress = t_ptr;
|
|
t_ptr += 16;
|
|
params->preferredValidLifeTime = common_read_32_bit(t_ptr);
|
|
t_ptr += 4;
|
|
params->validLifeTime = common_read_32_bit(t_ptr);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint16_t libdhcpv6_address_request_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint8_t requstOptionCnt)
|
|
{
|
|
uint16_t length = 0;
|
|
length += libdhcpv6_header_size();
|
|
length += libdhcpv6_elapsed_time_option_size();
|
|
length += libdhcpv6_duid_option_size(clientLinkType);
|
|
length += libdhcpv6_duid_option_size(serverLinkType);
|
|
length += libdhcvp6_request_option_size(requstOptionCnt);
|
|
length += libdhcpv6_rapid_commit_option_size();
|
|
length += libdhcpv6_non_temporal_address_size(true);
|
|
return length;
|
|
}
|
|
#ifdef HAVE_DHCPV6_SERVER
|
|
uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint16_t vendorDataLen, bool rapidCommon, bool status)
|
|
{
|
|
uint16_t length = 0;
|
|
|
|
length += libdhcpv6_header_size();
|
|
length += libdhcpv6_duid_option_size(clientLinkType);
|
|
length += libdhcpv6_duid_option_size(serverLinkType);
|
|
if (rapidCommon) {
|
|
length += libdhcpv6_rapid_commit_option_size();
|
|
}
|
|
|
|
if (vendorDataLen) {
|
|
length += (vendorDataLen + 4);
|
|
}
|
|
|
|
if (status) {
|
|
length += libdhcpv6_non_temporal_address_size(true);
|
|
} else {
|
|
length += libdhcpv6_non_temporal_address_size(false);
|
|
length += libdhcpv6_status_option_size();
|
|
}
|
|
|
|
return length;
|
|
}
|
|
#endif
|
|
|
|
uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_link_options_params_t *serverLink)
|
|
{
|
|
bool add_address = false;
|
|
if (nonTemporalAddress) {
|
|
add_address = true;
|
|
}
|
|
//Start Build Packet
|
|
ptr = libdhcpv6_header_write(ptr, packet->messageType, packet->transActionId);
|
|
//Elapsed time
|
|
ptr = libdhcpv6_elapsed_time_option_write(ptr, 0);
|
|
//Client Identifier
|
|
ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &packet->clientDUID); //16
|
|
//SET Server ID if It is defined
|
|
if (serverLink) {
|
|
ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, serverLink);
|
|
}
|
|
|
|
//SET Server ID
|
|
ptr = libdhcpv6_rapid_commit_option_write(ptr);
|
|
//Request Option
|
|
ptr = libdhcvp6_request_option_write(ptr, packet->requestedOptionCnt, packet->requestedOptionList);
|
|
//CLient Identity Association
|
|
|
|
ptr = libdhcpv6_identity_association_option_write(ptr, packet->iaID, packet->timerT0, packet->timerT1, add_address);
|
|
if (add_address) {
|
|
ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
uint8_t *libdhcpv6_reply_message_write(uint8_t *ptr, dhcpv6_reply_packet_s *replyPacket, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcpv6_vendor_data_packet_s *vendorData)
|
|
{
|
|
ptr = libdhcpv6_header_write(ptr, DHCPV6_REPLY_TYPE, replyPacket->transaction_ID);
|
|
ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, &replyPacket->serverDUID); //16
|
|
ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &replyPacket->clientDUID); //16
|
|
|
|
if (nonTemporalAddress) {
|
|
ptr = libdhcpv6_identity_association_option_write(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, true);
|
|
ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
|
|
} else {
|
|
ptr = libdhcpv6_identity_association_option_write_with_status(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE);
|
|
}
|
|
|
|
if (vendorData) {
|
|
ptr = libdhcvp6_vendor_specific_option_write(ptr, vendorData->vendorData, vendorData->vendorDataLength);
|
|
}
|
|
|
|
if (replyPacket->rapidCommit) {
|
|
ptr = libdhcpv6_rapid_commit_option_write(ptr);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
uint16_t libdhcpv6_solication_message_length(uint16_t clientLinkType, bool addressDefined, uint8_t requestOptionCount)
|
|
{
|
|
uint16_t length = 0;
|
|
length += libdhcpv6_header_size();
|
|
length += libdhcpv6_elapsed_time_option_size();
|
|
length += libdhcpv6_rapid_commit_option_size();
|
|
length += libdhcpv6_duid_option_size(clientLinkType);
|
|
length += libdhcpv6_non_temporal_address_size(addressDefined);
|
|
length += libdhcvp6_request_option_size(requestOptionCount);
|
|
return length;
|
|
}
|
|
|
|
#endif
|