Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers libDHCPv6.c Source File

libDHCPv6.c

00001 /*
00002  * Copyright (c) 2014-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * \file libDHCPv6.c
00020  * \brief Add short description about this file!!!
00021  *
00022  */
00023 #include "nsconfig.h"
00024 #include <string.h>
00025 #include <ns_types.h>
00026 #include "ns_trace.h"
00027 #include "common_functions.h"
00028 #include "libDHCPv6/libDHCPv6.h"
00029 #include "randLIB.h"
00030 #include "nsdynmemLIB.h"
00031 #ifdef HAVE_DHCPV6
00032 #define TRACE_GROUP "dhcp"
00033 
00034 
00035 static NS_LARGE NS_LIST_DEFINE(dhcpv6_client_nonTemporal_list, dhcpv6_client_server_data_t, link);
00036 
00037 //Allocate
00038 static dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_entry_allocate(void)
00039 {
00040     dhcpv6_client_server_data_t *newEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_client_server_data_t));
00041     if (newEntry) {
00042         newEntry->T0 = 0;
00043         newEntry->T1 = 0;
00044         newEntry->reNewTimer = 0;
00045         newEntry->iaNonTemporalStructValid = false;
00046         newEntry->GlobalAddress = false;
00047         newEntry->useServerAddress = false;
00048         newEntry->iaNontemporalAddress.preferredTime = 0;
00049         newEntry->iaNontemporalAddress.validLifetime = 0;
00050     }
00051     return newEntry;
00052 }
00053 
00054 static uint32_t libdhcpv6_IAID_generate(void)
00055 {
00056     uint32_t iaId;
00057     bool notUnique = true;
00058     while (notUnique) {
00059         notUnique = false;
00060         iaId = randLIB_get_32bit();
00061         if (libdhcpv6_nonTemporal_entry_get_by_iaid(iaId)) {
00062             notUnique = true;
00063         }
00064 
00065     }
00066     return iaId;
00067 }
00068 
00069 static uint32_t libdhcpv6_Tx_timer_generate(uint32_t lifetime, bool T1_get)
00070 {
00071     uint32_t timeout = lifetime;
00072 
00073     if (T1_get) {
00074         timeout = (timeout >> 1);
00075     } else {
00076         timeout = (timeout >> 2);
00077         timeout = (timeout * 3);
00078     }
00079 
00080     return timeout;
00081 }
00082 
00083 uint32_t libdhcpv6_txid_get(void)
00084 {
00085     uint32_t transaction_id = randLIB_get_32bit();
00086     transaction_id &= 0x00ffffff;
00087     return transaction_id;
00088 }
00089 
00090 uint32_t libdhcpv6_renew_time_define(dhcpv6_client_server_data_t *addresInfo)
00091 {
00092     uint32_t renewTimer = 0xffffffff;
00093 
00094     if (addresInfo->iaNontemporalAddress.preferredTime < renewTimer) {
00095         renewTimer = addresInfo->iaNontemporalAddress.preferredTime;
00096     }
00097 
00098     if (renewTimer ==  0xffffffff) {
00099         //Check T1
00100         renewTimer = 0;
00101     } else if (renewTimer < 100) {
00102         renewTimer = 100;
00103     }
00104 
00105     if (addresInfo->T0 == 0) {
00106         //Calculate
00107         if (renewTimer != 0) {
00108             addresInfo->T0 = libdhcpv6_Tx_timer_generate(renewTimer, true);
00109             addresInfo->T1 = libdhcpv6_Tx_timer_generate(renewTimer, false);
00110         } else {
00111             addresInfo->T0 = 0xffffffff;
00112             addresInfo->T1 = 0xffffffff;
00113         }
00114     }
00115 
00116     //Calculate Renew Time
00117     if (addresInfo->T0 != 0xffffffff) {
00118         renewTimer = addresInfo->T0;
00119     } else {
00120         renewTimer = 0;
00121     }
00122 
00123     return renewTimer;
00124 }
00125 
00126 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)
00127 {
00128     uint32_t iaId;
00129     dhcpv6_client_server_data_t *new_entry = NULL;
00130     if (duiId) {
00131         //allocate new Entry
00132         iaId = libdhcpv6_IAID_generate();
00133         new_entry = libdhcvp6_nontemporalAddress_entry_allocate();
00134         if (new_entry) {
00135             new_entry->IAID = iaId;
00136             new_entry->interfaceId = interfaceId;
00137             new_entry->instanceId = instanceId;
00138             //save Cliet ID
00139             memcpy(new_entry->clientId, duiId, 8);
00140             new_entry->clientLinkIdType = duiLinkType;
00141             if (serverIPv6Address) {
00142                 memcpy(new_entry->server_address, serverIPv6Address, 16);
00143                 new_entry->useServerAddress = true;
00144             }
00145             if (nonTemporalPrefix) {
00146                 uint8_t *ptr = new_entry->iaNontemporalAddress.addressPrefix;
00147                 memcpy(ptr, nonTemporalPrefix, 8);
00148                 memset((ptr + 8), 0, 8);
00149                 new_entry->iaNonTemporalStructValid = true;
00150                 new_entry->iaNontemporalAddress.preferredTime = 0;
00151                 new_entry->iaNontemporalAddress.validLifetime = 0;
00152             }
00153             ns_list_add_to_end(&dhcpv6_client_nonTemporal_list, new_entry);
00154         }
00155     }
00156     return new_entry;
00157 }
00158 
00159 void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *removedEntry)
00160 {
00161     if (removedEntry) {
00162         ns_list_remove(&dhcpv6_client_nonTemporal_list, removedEntry);
00163         ns_dyn_mem_free(removedEntry);
00164     }
00165 }
00166 
00167 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_instance(uint8_t instanceId)
00168 {
00169     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00170         if (cur->instanceId == instanceId) {
00171             return cur;
00172         }
00173     }
00174     return NULL;
00175 }
00176 uint8_t libdhcpv6_nonTemporal_entry_get_unique_instance_id(void)
00177 {
00178     uint8_t unique_id = 1;
00179     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00180         if (cur->instanceId == unique_id) {
00181             unique_id++;
00182             cur = ns_list_get_first(&dhcpv6_client_nonTemporal_list);
00183         }
00184     }
00185     return unique_id;
00186 }
00187 
00188 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_iaid(uint32_t iaId)
00189 {
00190     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00191         if (cur->IAID == iaId) {
00192             return cur;
00193         }
00194     }
00195     return NULL;
00196 }
00197 
00198 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_transactionId(uint32_t txId)
00199 {
00200     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00201         if (cur->transActionId == txId) {
00202             return cur;
00203         }
00204     }
00205     return NULL;
00206 }
00207 
00208 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t interfaceId, uint8_t *prefix)
00209 {
00210     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00211         if ((cur->interfaceId == interfaceId) && cur->iaNonTemporalStructValid) {
00212             if (memcmp(cur->iaNontemporalAddress.addressPrefix, prefix , 8) == 0) {
00213                 return cur;
00214             }
00215         }
00216     }
00217     return NULL;
00218 }
00219 
00220 uint16_t libdhcpv6_duid_option_size(uint16_t linkType)
00221 {
00222     uint16_t length = 8; // Type & Length header part *2
00223     if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) {
00224         length += 8;
00225     } else {
00226         length += 6;
00227     }
00228 
00229     return length;
00230 }
00231 
00232 uint16_t libdhcpv6_client_data_option_size(uint16_t linkType)
00233 {
00234     uint16_t optionLength = 4;
00235     optionLength += libdhcpv6_duid_option_size(linkType);
00236     optionLength += libdhcpv6_ia_address_option_size();
00237     optionLength += libdhcpv6_client_last_transaction_time_option_size();
00238     return optionLength;
00239 }
00240 
00241 uint16_t libdhcvp6_request_option_size(uint8_t optionCnt)
00242 {
00243     uint16_t optionLength = 4;
00244     optionLength += 2 * optionCnt;
00245     return optionLength;
00246 }
00247 
00248 uint16_t libdhcpv6_non_temporal_address_size(bool addressDefined)
00249 {
00250     uint16_t optionLength = 16;
00251     if (addressDefined) {
00252         optionLength += libdhcpv6_ia_address_option_size();
00253     }
00254     return optionLength;
00255 }
00256 
00257 int libdhcpv6_message_malformed_check(uint8_t *ptr, uint16_t data_len)
00258 {
00259     uint8_t *dptr;
00260     uint16_t length;
00261     if (data_len > 4) {
00262         dptr = ptr + 4; //Skip Type & TXID
00263         data_len -= 4;
00264         while (data_len) {
00265             if (data_len >= 4) {
00266 
00267                 length = common_read_16_bit(dptr + 2); //Skip Type
00268                 dptr += 4;
00269                 data_len -= 4;
00270                 if (data_len >= length) {
00271                     data_len -= length;
00272                     dptr += length;
00273                 }
00274             } else {
00275                 return -1;
00276             }
00277         }
00278     }
00279     return 0;
00280 }
00281 
00282 
00283 /**
00284  * This Function write dhcpv6 basic header
00285  *
00286  * \param ptr pointer where header will be writed
00287  * \param msgType dhcpv6 message type
00288  * \param transActionId 24-bit unique Trasnaction ID
00289  *
00290  * return incremented pointer after write
00291  */
00292 uint8_t *libdhcpv6_header_write(uint8_t *ptr, uint8_t msgType, uint32_t transActionId)
00293 {
00294     *ptr++ = msgType;
00295     ptr = common_write_24_bit(transActionId, ptr);
00296     return ptr;
00297 }
00298 
00299 uint8_t *libdhcpv6_elapsed_time_option_write(uint8_t *ptr, uint16_t elapsedTime)
00300 {
00301     //Elapsed time
00302     ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION, ptr);
00303     ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION_LEN, ptr);
00304     ptr = common_write_16_bit(elapsedTime, ptr);
00305     return ptr;
00306 }
00307 
00308 uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr)
00309 {
00310     ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT, ptr);
00311     ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT_LEN, ptr);
00312     return ptr;
00313 }
00314 
00315 uint8_t *libdhcvp6_vendor_specific_option_write(uint8_t *ptr, uint8_t *data, uint16_t dataLength)
00316 {
00317     ptr = common_write_16_bit(DHCPV6_OPTION_VENDOR_SPECIFIC_INFO, ptr);
00318     ptr = common_write_16_bit(dataLength, ptr);
00319     memcpy(ptr, data, dataLength);
00320     ptr += dataLength;
00321     return ptr;
00322 }
00323 
00324 uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_t *optionPtr)
00325 {
00326     uint16_t optionLength = libdhcvp6_request_option_size(optionCnt);
00327     ptr = common_write_16_bit(DHCPV6_OPTION_REQUEST_OPTION, ptr);
00328     ptr = common_write_16_bit((optionLength - 4), ptr);
00329     while (optionCnt) {
00330         ptr = common_write_16_bit(*optionPtr++, ptr);
00331         optionCnt--;
00332     }
00333     return ptr;
00334 }
00335 
00336 uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_link_options_params_t *duid)
00337 {
00338     uint16_t length = libdhcpv6_duid_option_size(duid->linkType);
00339 
00340     length -= 4; //Cut normal option header out
00341     ptr = common_write_16_bit(duidRole, ptr);
00342     ptr = common_write_16_bit(length, ptr);
00343     ptr = common_write_16_bit(DHCPV6_DUID_LINK_LAYER_TYPE, ptr);
00344     ptr = common_write_16_bit(duid->linkType, ptr);
00345     length -= 4; //Cut normal option header out
00346     memcpy(ptr, duid->linkID, length);
00347     ptr += length;
00348     return ptr;
00349 }
00350 
00351 uint8_t *libdhcpv6_prefix_delegation_info_option_write(uint8_t *ptr, uint32_t iaId)
00352 {
00353     ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION, ptr);
00354     ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION_MIN_LENGTH, ptr);
00355     ptr = common_write_32_bit(iaId, ptr);
00356     ptr = common_write_32_bit(0, ptr); //T1
00357     ptr = common_write_32_bit(0, ptr);//T2
00358     return ptr;
00359 }
00360 
00361 uint8_t *libdhcpv6_identity_association_option_write(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, bool withAddress)
00362 {
00363     uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(withAddress);
00364 
00365     ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
00366     ptr = common_write_16_bit((optionMsgLen - 4), ptr);
00367 
00368     ptr = common_write_32_bit(iaID, ptr); //iaId
00369     ptr = common_write_32_bit(TimerT1, ptr); //T1
00370     ptr = common_write_32_bit(TimerT2, ptr);//T2
00371     return ptr;
00372 }
00373 
00374 uint8_t *libdhcpv6_identity_association_option_write_with_status(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, uint16_t status)
00375 {
00376     uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(false);
00377 
00378     optionMsgLen += 6; // add status option length
00379 
00380     ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
00381     ptr = common_write_16_bit((optionMsgLen - 4), ptr);
00382 
00383     ptr = common_write_32_bit(iaID, ptr); //iaId
00384     ptr = common_write_32_bit(TimerT1, ptr); //T1
00385     ptr = common_write_32_bit(TimerT2, ptr);//T2
00386     ptr = libdhcpv6_status_code_write(ptr, status);
00387     return ptr;
00388 }
00389 
00390 uint8_t *libdhcpv6_ia_address_option_write(uint8_t *ptr, const uint8_t *addressPtr, uint32_t preferredValidLifeTime, uint32_t validLifeTime)
00391 {
00392     ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION, ptr);
00393     ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION_LEN, ptr);
00394     memcpy(ptr, addressPtr, 16);
00395     ptr += 16;
00396     ptr = common_write_32_bit(preferredValidLifeTime, ptr); //Preferred
00397     ptr = common_write_32_bit(validLifeTime, ptr);//Valid
00398     return ptr;
00399 }
00400 
00401 uint8_t *libdhcpv6_status_code_write(uint8_t *ptr, uint16_t statusCode)
00402 {
00403     ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION, ptr);
00404     ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION_LEN, ptr);
00405     ptr = common_write_16_bit(statusCode, ptr);
00406     return ptr;
00407 }
00408 
00409 uint8_t *libdhcpv6_client_last_transaction_time_option_write(uint8_t *ptr, uint32_t last_transaction_Time)
00410 {
00411 
00412     uint16_t Length = libdhcpv6_client_last_transaction_time_option_size();
00413     ptr = common_write_16_bit(DHCPV6_OPTION_CLT_TIME, ptr);
00414     ptr = common_write_16_bit((Length - 4), ptr);
00415     ptr = common_write_32_bit(last_transaction_Time, ptr); //SET Last time we heard from this child either from mle or data packets.
00416     return ptr;
00417 }
00418 
00419 int libdhcpv6_message_option_discover(uint8_t *ptr, uint16_t data_len, uint16_t discovered_type, dhcp_options_msg_t *option_info)
00420 {
00421     uint8_t *dptr;
00422     uint16_t type, length;
00423     dptr = ptr;
00424     if( data_len < 4 ){
00425         tr_warn("libdhcpv6_message_option_discover() data_len<4");
00426         return -1;
00427     }
00428     while (data_len >= 4) {
00429         type = common_read_16_bit(dptr);
00430         dptr += 2;
00431         length = common_read_16_bit(dptr);
00432         dptr += 2;
00433         data_len -= 4;
00434         if (data_len >= length) {
00435             if (type == discovered_type) {
00436                 option_info->len = length;
00437                 option_info->type = type;
00438                 option_info->msg_ptr = dptr;
00439                 return 0;
00440             }
00441             data_len -= length;
00442             dptr += length;
00443         } else {
00444             tr_warn("libdhcpv6_message_option_discover() data_len<length=%"PRIu16, length);
00445             break;
00446         }
00447     }
00448     return -1;
00449 }
00450 
00451 int libdhcpv6_compare_DUID(dhcp_link_options_params_t *targetId, dhcp_link_options_params_t *parsedId)
00452 {
00453     if (targetId->linkType == parsedId->linkType) {
00454         uint8_t cmpLen;
00455         if (targetId->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) {
00456             //Compare Current Interface EUID64
00457             cmpLen = 8;
00458         } else {
00459             cmpLen = 6;
00460         }
00461         if (memcmp(targetId->linkID, parsedId->linkID, cmpLen) == 0) {
00462             return 0;
00463         }
00464     }
00465     return -1;
00466 }
00467 
00468 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)
00469 {
00470     /**
00471      * Solication Message Should Include Next Options:
00472      *  - DHCPV6_SERVER_ID_OPTION
00473      *  - DHCPV6_CLIENT_ID_OPTION
00474      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00475      *
00476      */
00477     /** Verify Client ID */
00478     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION , clientId) != 0) {
00479         return -1;
00480     }
00481 
00482     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
00483         return -1;
00484     }
00485 
00486     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00487         return -1;
00488     }
00489 
00490     return 0;
00491 }
00492 
00493 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)
00494 {
00495     /**
00496      * Solication Message Should Include Next Options:
00497      *  - DHCPV6_SERVER_ID_OPTION
00498      *  - DHCPV6_CLIENT_ID_OPTION
00499      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00500      *
00501      */
00502     /** Verify Client ID to own EUID64 */
00503     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION , clientId) != 0) {
00504         return -1;
00505     }
00506 
00507     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
00508         return -1;
00509     }
00510 
00511     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00512         return -1;
00513     }
00514 
00515     return 0;
00516 }
00517 #ifdef HAVE_DHCPV6_SERVER
00518 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)
00519 {
00520 
00521     /**
00522          * Renew Message Should Include Next Options:
00523          *  - DHCPV6_ELAPSED_TIME_OPTION
00524          *  - DHCPV6_CLIENT_ID_OPTION
00525          *  - DHCPV6_SERVER_ID_OPTION
00526          *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00527          *  - DHCPV6_OPTION_REQUEST_OPTION
00528          * Optionally:
00529          *  - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
00530          */
00531 
00532     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00533     if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
00534         return -1;
00535     }
00536     /** Verify DHCPV6_CLIENT_ID_OPTION */
00537     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLinkData) != 0) {
00538         return -1;
00539     }
00540     /** Verify DHCPV6_SERVER_ID_OPTION */
00541     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverLinkData) != 0) {
00542         return -1;
00543     }
00544 
00545     /** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
00546     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00547         return -1;
00548     }
00549 
00550     return 0;
00551 }
00552 
00553 
00554 
00555 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)
00556 {
00557     /**
00558      * Solication Message Should Include Next Options:
00559      *  - DHCPV6_ELAPSED_TIME_OPTION
00560      *  - DHCPV6_CLIENT_ID_OPTION
00561      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00562      *  - DHCPV6_OPTION_REQUEST_OPTION
00563      * Optionally:
00564      *  - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
00565      */
00566     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00567 
00568     if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
00569         return -1;
00570     }
00571     /** Verify DHCPV6_CLIENT_ID_OPTION */
00572     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLink) != 0) {
00573         return -1;
00574     }
00575 
00576 
00577     /** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
00578     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00579         return -1;
00580     }
00581 
00582     return 0;
00583 }
00584 #endif
00585 
00586 bool libdhcpv6_time_elapsed_option_at_packet(uint8_t *ptr, uint16_t length)
00587 {
00588     bool retVal = false;
00589     dhcp_options_msg_t option_msg;
00590     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00591 
00592     if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_ELAPSED_TIME_OPTION, &option_msg) == 0) {
00593         if (option_msg.len == DHCPV6_ELAPSED_TIME_OPTION_LEN) {
00594             retVal = true;
00595         }
00596     }
00597     return retVal;
00598 }
00599 
00600 bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length)
00601 {
00602     bool retVal = false;
00603     dhcp_options_msg_t option_msg;
00604     if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_OPTION_RAPID_COMMIT, &option_msg) == 0) {
00605         retVal = true;
00606     }
00607     return retVal;
00608 }
00609 
00610 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)
00611 {
00612     dhcp_options_msg_t option_msg;
00613 
00614     /** Verify DHCPV6_CLIENT_ID_OPTION */
00615     if (libdhcpv6_message_option_discover(ptr, data_length, type, &option_msg) == 0) {
00616         if (option_msg.len >= DHCPV6_SERVER_ID_MAC48_OPTION_LEN) {
00617             uint8_t *t_ptr = option_msg.msg_ptr;
00618             type = common_read_16_bit(t_ptr);
00619             t_ptr += 2;
00620             params->linkType = common_read_16_bit(t_ptr);
00621             t_ptr += 2;
00622             if (type == DHCPV6_DUID_LINK_LAYER_TYPE) {
00623                 params->linkID = t_ptr;
00624                 if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC48_OPTION_LEN)) {
00625                     return 0;
00626                 } else if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) {
00627                     return 0;
00628                 }
00629             }
00630         }
00631     }
00632 
00633     return -1;
00634 }
00635 
00636 int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params)
00637 {
00638     dhcp_options_msg_t option_msg;
00639     uint16_t status_code = 0;
00640 
00641     if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
00642         if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
00643             status_code = common_read_16_bit(option_msg.msg_ptr);
00644             if (status_code == DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE) {
00645                 return -1;
00646             }
00647         }
00648     }
00649 
00650     if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_IDENTITY_ASSOCIATION_OPTION, &option_msg) == 0) {
00651         if (option_msg.len < DHCPV6_IDENTITY_ASSOCIATION_OPTION_MIN_LEN) {
00652             return -1;
00653         }
00654         uint8_t *t_ptr;
00655         uint16_t length;
00656         t_ptr = option_msg.msg_ptr;
00657         length = (option_msg.len - 12);
00658         params->iaId = common_read_32_bit(t_ptr);
00659         t_ptr += 4;
00660         params->T0 = common_read_32_bit(t_ptr);
00661         t_ptr += 4;
00662         params->T1 = common_read_32_bit(t_ptr);
00663         t_ptr += 4;
00664 
00665         if(length > 4) {
00666             if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
00667                 if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
00668                     status_code = common_read_16_bit(option_msg.msg_ptr);
00669                     if (status_code != 0) {
00670                         return -1;
00671                     }
00672                 }
00673             }
00674 
00675             if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_IA_ADDRESS_OPTION, &option_msg) == 0) {
00676                 if (option_msg.len >= DHCPV6_IA_ADDRESS_OPTION_LEN) {
00677                     t_ptr = option_msg.msg_ptr;
00678                     params->nonTemporalAddress = t_ptr;
00679                     t_ptr += 16;
00680                     params->preferredValidLifeTime = common_read_32_bit(t_ptr);
00681                     t_ptr += 4;
00682                     params->validLifeTime = common_read_32_bit(t_ptr);
00683                     return 0;
00684                 }
00685             }
00686         }
00687     }
00688     return -1;
00689 }
00690 
00691 uint16_t libdhcpv6_address_request_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint8_t requstOptionCnt)
00692 {
00693     uint16_t length = 0;
00694     length += libdhcpv6_header_size();
00695     length += libdhcpv6_elapsed_time_option_size();
00696     length += libdhcpv6_duid_option_size(clientLinkType);
00697     length += libdhcpv6_duid_option_size(serverLinkType);
00698     length += libdhcvp6_request_option_size(requstOptionCnt);
00699     length += libdhcpv6_rapid_commit_option_size();
00700     length += libdhcpv6_non_temporal_address_size(true);
00701     return length;
00702 }
00703 #ifdef HAVE_DHCPV6_SERVER
00704 uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint16_t vendorDataLen, bool rapidCommon, bool status)
00705 {
00706     uint16_t length = 0;
00707 
00708     length += libdhcpv6_header_size();
00709     length += libdhcpv6_duid_option_size(clientLinkType);
00710     length += libdhcpv6_duid_option_size(serverLinkType);
00711     if (rapidCommon) {
00712         length += libdhcpv6_rapid_commit_option_size();
00713     }
00714 
00715     if (vendorDataLen) {
00716         length += (vendorDataLen + 4);
00717     }
00718 
00719     if (status) {
00720         length += libdhcpv6_non_temporal_address_size(true);
00721     } else {
00722         length += libdhcpv6_non_temporal_address_size(false);
00723         length += libdhcpv6_status_option_size();
00724     }
00725 
00726     return length;
00727 }
00728 #endif
00729 
00730 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)
00731 {
00732     bool add_address = false;
00733     if (nonTemporalAddress) {
00734         add_address = true;
00735     }
00736     //Start Build Packet
00737     ptr = libdhcpv6_header_write(ptr, packet->messageType, packet->transActionId);
00738     //Elapsed time
00739     ptr = libdhcpv6_elapsed_time_option_write(ptr, 0);
00740     //Client Identifier
00741     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &packet->clientDUID); //16
00742     //SET Server ID if It is defined
00743     if (serverLink) {
00744         ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, serverLink);
00745     }
00746 
00747     //SET Server ID
00748     ptr = libdhcpv6_rapid_commit_option_write(ptr);
00749     //Request Option
00750     ptr = libdhcvp6_request_option_write(ptr, packet->requestedOptionCnt, packet->requestedOptionList);
00751     //CLient Identity Association
00752 
00753     ptr = libdhcpv6_identity_association_option_write(ptr, packet->iaID, packet->timerT0, packet->timerT1, add_address);
00754     if (add_address) {
00755         ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
00756     }
00757 
00758     return ptr;
00759 }
00760 
00761 
00762 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)
00763 {
00764     ptr = libdhcpv6_header_write(ptr, DHCPV6_REPLY_TYPE, replyPacket->transaction_ID);
00765     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, &replyPacket->serverDUID); //16
00766     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &replyPacket->clientDUID); //16
00767 
00768     if (nonTemporalAddress) {
00769         ptr = libdhcpv6_identity_association_option_write(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, true);
00770         ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
00771     } else {
00772         ptr = libdhcpv6_identity_association_option_write_with_status(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE);
00773     }
00774 
00775     if (vendorData) {
00776         ptr = libdhcvp6_vendor_specific_option_write(ptr, vendorData->vendorData, vendorData->vendorDataLength);
00777     }
00778 
00779     if (replyPacket->rapidCommit) {
00780         ptr = libdhcpv6_rapid_commit_option_write(ptr);
00781     }
00782 
00783     return ptr;
00784 }
00785 
00786 uint16_t libdhcpv6_solication_message_length(uint16_t clientLinkType, bool addressDefined, uint8_t requestOptionCount)
00787 {
00788     uint16_t length = 0;
00789     length += libdhcpv6_header_size();
00790     length += libdhcpv6_elapsed_time_option_size();
00791     length += libdhcpv6_rapid_commit_option_size();
00792     length += libdhcpv6_duid_option_size(clientLinkType);
00793     length += libdhcpv6_non_temporal_address_size(addressDefined);
00794     length += libdhcvp6_request_option_size(requestOptionCount);
00795     return length;
00796 }
00797 
00798 #endif