Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers libDHCPv6.c Source File

libDHCPv6.c

00001 /*
00002  * Copyright (c) 2014-2019, 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     uint8_t *temporary_duid = ns_dyn_mem_alloc(16); //Support DUID-LL, DUID-LLP and DUID-UUID  by default
00042     if (!newEntry || !temporary_duid) {
00043         ns_dyn_mem_free(newEntry);
00044         ns_dyn_mem_free(temporary_duid);
00045         return NULL;
00046     }
00047 
00048     newEntry->T0 = 0;
00049     newEntry->T1 = 0;
00050     newEntry->reNewTimer = 0;
00051     newEntry->iaNonTemporalStructValid = false;
00052     newEntry->GlobalAddress = false;
00053     newEntry->useServerAddress = false;
00054     newEntry->iaNontemporalAddress.preferredTime = 0;
00055     newEntry->iaNontemporalAddress.validLifetime = 0;
00056     newEntry->dyn_server_duid_length = 16;
00057     newEntry->serverDynamic_DUID = temporary_duid;
00058     return newEntry;
00059 }
00060 
00061 static uint32_t libdhcpv6_IAID_generate(void)
00062 {
00063     uint32_t iaId;
00064     bool notUnique = true;
00065     while (notUnique) {
00066         notUnique = false;
00067         iaId = randLIB_get_32bit();
00068         if (libdhcpv6_nonTemporal_entry_get_by_iaid(iaId)) {
00069             notUnique = true;
00070         }
00071 
00072     }
00073     return iaId;
00074 }
00075 
00076 static uint32_t libdhcpv6_Tx_timer_generate(uint32_t lifetime, bool T1_get)
00077 {
00078     uint32_t timeout = lifetime;
00079 
00080     if (T1_get) {
00081         timeout = (timeout >> 1);
00082     } else {
00083         timeout = (timeout >> 2);
00084         timeout = (timeout * 3);
00085     }
00086 
00087     return timeout;
00088 }
00089 
00090 uint32_t libdhcpv6_txid_get(void)
00091 {
00092     uint32_t transaction_id = randLIB_get_32bit();
00093     transaction_id &= 0x00ffffff;
00094     return transaction_id;
00095 }
00096 
00097 uint32_t libdhcpv6_renew_time_define(dhcpv6_client_server_data_t *addresInfo)
00098 {
00099     uint32_t renewTimer = 0xffffffff;
00100 
00101     if (addresInfo->iaNontemporalAddress.preferredTime < renewTimer) {
00102         renewTimer = addresInfo->iaNontemporalAddress.preferredTime;
00103     }
00104 
00105     if (renewTimer ==  0xffffffff) {
00106         //Check T1
00107         renewTimer = 0;
00108     } else if (renewTimer < 100) {
00109         renewTimer = 100;
00110     }
00111 
00112     if (addresInfo->T0 == 0) {
00113         //Calculate
00114         if (renewTimer != 0) {
00115             addresInfo->T0 = libdhcpv6_Tx_timer_generate(renewTimer, true);
00116             addresInfo->T1 = libdhcpv6_Tx_timer_generate(renewTimer, false);
00117         } else {
00118             addresInfo->T0 = 0xffffffff;
00119             addresInfo->T1 = 0xffffffff;
00120         }
00121     }
00122 
00123     //Calculate Renew Time
00124     if (addresInfo->T0 != 0xffffffff) {
00125         renewTimer = addresInfo->T0;
00126     } else {
00127         renewTimer = 0;
00128     }
00129 
00130     return renewTimer;
00131 }
00132 
00133 dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address)
00134 {
00135     uint32_t iaId;
00136     uint8_t *ptr;
00137     dhcpv6_client_server_data_t *new_entry = NULL;
00138     //allocate new Entry
00139     iaId = libdhcpv6_IAID_generate();
00140     new_entry = libdhcvp6_nontemporalAddress_entry_allocate();
00141     if (new_entry) {
00142         new_entry->IAID = iaId;
00143         new_entry->interfaceId = interfaceId;
00144         new_entry->instanceId = instanceId;
00145         new_entry->serverDUID.duid = NULL;
00146         new_entry->serverDUID.duid_length = 0;
00147 
00148         if (serverIPv6Address) {
00149             memcpy(new_entry->server_address, serverIPv6Address, 16);
00150             new_entry->useServerAddress = true;
00151         }
00152         if (nonTemporalPrefix) {
00153             ptr = new_entry->iaNontemporalAddress.addressPrefix;
00154             memcpy(ptr, nonTemporalPrefix, 8);
00155             memset((ptr + 8), 0, 8);
00156             new_entry->iaNonTemporalStructValid = true;
00157             new_entry->iaNontemporalAddress.preferredTime = 0;
00158             new_entry->iaNontemporalAddress.validLifetime = 0;
00159         }
00160         ns_list_add_to_end(&dhcpv6_client_nonTemporal_list, new_entry);
00161     }
00162     return new_entry;
00163 }
00164 
00165 void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *removedEntry)
00166 {
00167     if (removedEntry) {
00168         ns_list_remove(&dhcpv6_client_nonTemporal_list, removedEntry);
00169         ns_dyn_mem_free(removedEntry->serverDynamic_DUID);
00170         ns_dyn_mem_free(removedEntry);
00171     }
00172 }
00173 
00174 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_instance(uint8_t instanceId)
00175 {
00176     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00177         if (cur->instanceId == instanceId) {
00178             return cur;
00179         }
00180     }
00181     return NULL;
00182 }
00183 uint8_t libdhcpv6_nonTemporal_entry_get_unique_instance_id(void)
00184 {
00185     uint8_t unique_id = 1;
00186     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00187         if (cur->instanceId == unique_id) {
00188             unique_id++;
00189             cur = ns_list_get_first(&dhcpv6_client_nonTemporal_list);
00190         }
00191     }
00192     return unique_id;
00193 }
00194 
00195 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_iaid(uint32_t iaId)
00196 {
00197     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00198         if (cur->IAID == iaId) {
00199             return cur;
00200         }
00201     }
00202     return NULL;
00203 }
00204 
00205 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_transactionId(uint32_t txId)
00206 {
00207     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00208         if (cur->transActionId == txId) {
00209             return cur;
00210         }
00211     }
00212     return NULL;
00213 }
00214 
00215 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t interfaceId, uint8_t *prefix)
00216 {
00217     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00218         if (cur->interfaceId == interfaceId) {
00219             if (memcmp(cur->iaNontemporalAddress.addressPrefix, prefix, 8) == 0) {
00220                 return cur;
00221             }
00222         }
00223     }
00224     return NULL;
00225 }
00226 
00227 dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_validate_class_pointer(void *class_ptr)
00228 {
00229     ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) {
00230         if (cur == class_ptr) {
00231             return cur;
00232         }
00233     }
00234     return NULL;
00235 }
00236 
00237 
00238 uint16_t libdhcpv6_duid_option_size(uint16_t duidLength)
00239 {
00240     return duidLength + 6; //ID Type 2, length 2 ,Duid Type 2 + duid data
00241 }
00242 
00243 uint8_t libdhcpv6_duid_linktype_size(uint16_t linkType)
00244 {
00245     if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
00246             linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
00247         return 8;
00248     }
00249 
00250     return 6;
00251 }
00252 
00253 uint16_t libdhcvp6_request_option_size(uint8_t optionCnt)
00254 {
00255     uint16_t optionLength = 4;
00256     optionLength += 2 * optionCnt;
00257     return optionLength;
00258 }
00259 
00260 uint16_t libdhcpv6_non_temporal_address_size(bool addressDefined)
00261 {
00262     uint16_t optionLength = 16;
00263     if (addressDefined) {
00264         optionLength += libdhcpv6_ia_address_option_size();
00265     }
00266     return optionLength;
00267 }
00268 
00269 int libdhcpv6_message_malformed_check(uint8_t *ptr, uint16_t data_len)
00270 {
00271     uint8_t *dptr;
00272     uint16_t length;
00273     if (data_len > 4) {
00274         dptr = ptr + 4; //Skip Type & TXID
00275         data_len -= 4;
00276         while (data_len) {
00277             if (data_len >= 4) {
00278 
00279                 length = common_read_16_bit(dptr + 2); //Skip Type
00280                 dptr += 4;
00281                 data_len -= 4;
00282                 if (data_len >= length) {
00283                     data_len -= length;
00284                     dptr += length;
00285                 }
00286             } else {
00287                 return -1;
00288             }
00289         }
00290     }
00291     return 0;
00292 }
00293 
00294 
00295 /**
00296  * This Function write dhcpv6 basic header
00297  *
00298  * \param ptr pointer where header will be writed
00299  * \param msgType dhcpv6 message type
00300  * \param transActionId 24-bit unique Trasnaction ID
00301  *
00302  * return incremented pointer after write
00303  */
00304 uint8_t *libdhcpv6_header_write(uint8_t *ptr, uint8_t msgType, uint32_t transActionId)
00305 {
00306     *ptr++ = msgType;
00307     ptr = common_write_24_bit(transActionId, ptr);
00308     return ptr;
00309 }
00310 
00311 uint8_t *libdhcpv6_elapsed_time_option_write(uint8_t *ptr, uint16_t elapsedTime)
00312 {
00313     //Elapsed time
00314     ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION, ptr);
00315     ptr = common_write_16_bit(DHCPV6_ELAPSED_TIME_OPTION_LEN, ptr);
00316     ptr = common_write_16_bit(elapsedTime, ptr);
00317     return ptr;
00318 }
00319 
00320 uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr)
00321 {
00322     ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT, ptr);
00323     ptr = common_write_16_bit(DHCPV6_OPTION_RAPID_COMMIT_LEN, ptr);
00324     return ptr;
00325 }
00326 
00327 uint8_t *libdhcvp6_vendor_specific_option_write(uint8_t *ptr, uint8_t *data, uint16_t dataLength)
00328 {
00329     ptr = common_write_16_bit(DHCPV6_OPTION_VENDOR_SPECIFIC_INFO, ptr);
00330     ptr = common_write_16_bit(dataLength, ptr);
00331     memcpy(ptr, data, dataLength);
00332     ptr += dataLength;
00333     return ptr;
00334 }
00335 
00336 uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_t *optionPtr)
00337 {
00338     uint16_t optionLength = libdhcvp6_request_option_size(optionCnt);
00339     ptr = common_write_16_bit(DHCPV6_OPTION_REQUEST_OPTION, ptr);
00340     ptr = common_write_16_bit((optionLength - 4), ptr);
00341     while (optionCnt) {
00342         ptr = common_write_16_bit(*optionPtr++, ptr);
00343         optionCnt--;
00344     }
00345     return ptr;
00346 }
00347 
00348 uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_duid_options_params_t *duid)
00349 {
00350     uint16_t length = duid->duid_length + 2;
00351     ptr = common_write_16_bit(duidRole, ptr);
00352     ptr = common_write_16_bit(length, ptr);
00353     ptr = common_write_16_bit(duid->type, ptr);
00354     memcpy(ptr, duid->duid, duid->duid_length);
00355     ptr += duid->duid_length;
00356     return ptr;
00357 }
00358 
00359 uint8_t *libdhcpv6_prefix_delegation_info_option_write(uint8_t *ptr, uint32_t iaId)
00360 {
00361     ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION, ptr);
00362     ptr = common_write_16_bit(DHCPV6_OPTION_IA_PREFIX_DELEGATION_MIN_LENGTH, ptr);
00363     ptr = common_write_32_bit(iaId, ptr);
00364     ptr = common_write_32_bit(0, ptr); //T1
00365     ptr = common_write_32_bit(0, ptr);//T2
00366     return ptr;
00367 }
00368 
00369 uint8_t *libdhcpv6_identity_association_option_write(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, bool withAddress)
00370 {
00371     uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(withAddress);
00372 
00373     ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
00374     ptr = common_write_16_bit((optionMsgLen - 4), ptr);
00375 
00376     ptr = common_write_32_bit(iaID, ptr); //iaId
00377     ptr = common_write_32_bit(TimerT1, ptr); //T1
00378     ptr = common_write_32_bit(TimerT2, ptr);//T2
00379     return ptr;
00380 }
00381 
00382 uint8_t *libdhcpv6_identity_association_option_write_with_status(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, uint16_t status)
00383 {
00384     uint16_t optionMsgLen = libdhcpv6_non_temporal_address_size(false);
00385 
00386     optionMsgLen += 6; // add status option length
00387 
00388     ptr = common_write_16_bit(DHCPV6_IDENTITY_ASSOCIATION_OPTION, ptr);
00389     ptr = common_write_16_bit((optionMsgLen - 4), ptr);
00390 
00391     ptr = common_write_32_bit(iaID, ptr); //iaId
00392     ptr = common_write_32_bit(TimerT1, ptr); //T1
00393     ptr = common_write_32_bit(TimerT2, ptr);//T2
00394     ptr = libdhcpv6_status_code_write(ptr, status);
00395     return ptr;
00396 }
00397 
00398 uint8_t *libdhcpv6_ia_address_option_write(uint8_t *ptr, const uint8_t *addressPtr, uint32_t preferredValidLifeTime, uint32_t validLifeTime)
00399 {
00400     ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION, ptr);
00401     ptr = common_write_16_bit(DHCPV6_IA_ADDRESS_OPTION_LEN, ptr);
00402     memcpy(ptr, addressPtr, 16);
00403     ptr += 16;
00404     ptr = common_write_32_bit(preferredValidLifeTime, ptr); //Preferred
00405     ptr = common_write_32_bit(validLifeTime, ptr);//Valid
00406     return ptr;
00407 }
00408 
00409 uint8_t *libdhcpv6_status_code_write(uint8_t *ptr, uint16_t statusCode)
00410 {
00411     ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION, ptr);
00412     ptr = common_write_16_bit(DHCPV6_STATUS_CODE_OPTION_LEN, ptr);
00413     ptr = common_write_16_bit(statusCode, ptr);
00414     return ptr;
00415 }
00416 
00417 uint8_t *libdhcpv6_client_last_transaction_time_option_write(uint8_t *ptr, uint32_t last_transaction_Time)
00418 {
00419 
00420     uint16_t Length = libdhcpv6_client_last_transaction_time_option_size();
00421     ptr = common_write_16_bit(DHCPV6_OPTION_CLT_TIME, ptr);
00422     ptr = common_write_16_bit((Length - 4), ptr);
00423     ptr = common_write_32_bit(last_transaction_Time, ptr); //SET Last time we heard from this child either from mle or data packets.
00424     return ptr;
00425 }
00426 
00427 int libdhcpv6_message_option_discover(uint8_t *ptr, uint16_t data_len, uint16_t discovered_type, dhcp_options_msg_t *option_info)
00428 {
00429     uint8_t *dptr;
00430     uint16_t type, length;
00431     dptr = ptr;
00432     if (data_len < 4) {
00433         tr_warn("libdhcpv6_message_option_discover() data_len<4");
00434         return -1;
00435     }
00436     while (data_len >= 4) {
00437         type = common_read_16_bit(dptr);
00438         dptr += 2;
00439         length = common_read_16_bit(dptr);
00440         dptr += 2;
00441         data_len -= 4;
00442         if (data_len >= length) {
00443             if (type == discovered_type) {
00444                 option_info->len = length;
00445                 option_info->type = type;
00446                 option_info->msg_ptr = dptr;
00447                 return 0;
00448             }
00449             data_len -= length;
00450             dptr += length;
00451         } else {
00452             tr_warn("libdhcpv6_message_option_discover() data_len<length=%"PRIu16, length);
00453             break;
00454         }
00455     }
00456     return -1;
00457 }
00458 
00459 int libdhcpv6_compare_DUID(dhcp_duid_options_params_t *targetId, dhcp_duid_options_params_t *parsedId)
00460 {
00461     if (targetId->type != parsedId->type) {
00462         return -1;
00463     }
00464 
00465     if (targetId->duid_length != parsedId->duid_length) {
00466         return -1;
00467     }
00468 
00469     if (memcmp(targetId->duid, parsedId->duid, targetId->duid_length) != 0) {
00470         return -1;
00471     }
00472     return 0;
00473 }
00474 
00475 int libdhcpv6_reply_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
00476 {
00477     /**
00478      * Solication Message Should Include Next Options:
00479      *  - DHCPV6_SERVER_ID_OPTION
00480      *  - DHCPV6_CLIENT_ID_OPTION
00481      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00482      *
00483      */
00484     /** Verify Client ID */
00485     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientId) != 0) {
00486         return -1;
00487     }
00488 
00489     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
00490         return -1;
00491     }
00492 
00493     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00494         return -1;
00495     }
00496 
00497     return 0;
00498 }
00499 
00500 int libdhcpv6_advertisment_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
00501 {
00502     /**
00503      * Solication Message Should Include Next Options:
00504      *  - DHCPV6_SERVER_ID_OPTION
00505      *  - DHCPV6_CLIENT_ID_OPTION
00506      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00507      *
00508      */
00509     /** Verify Client ID to own EUID64 */
00510     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientId) != 0) {
00511         return -1;
00512     }
00513 
00514     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverId) != 0) {
00515         return -1;
00516     }
00517 
00518     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00519         return -1;
00520     }
00521 
00522     return 0;
00523 }
00524 #ifdef HAVE_DHCPV6_SERVER
00525 int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLinkData, dhcp_duid_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
00526 {
00527 
00528     /**
00529          * Renew Message Should Include Next Options:
00530          *  - DHCPV6_ELAPSED_TIME_OPTION
00531          *  - DHCPV6_CLIENT_ID_OPTION
00532          *  - DHCPV6_SERVER_ID_OPTION
00533          *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00534          *  - DHCPV6_OPTION_REQUEST_OPTION
00535          * Optionally:
00536          *  - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
00537          */
00538 
00539     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00540     if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
00541         return -1;
00542     }
00543     /** Verify DHCPV6_CLIENT_ID_OPTION */
00544     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLinkData) != 0) {
00545         return -1;
00546     }
00547     /** Verify DHCPV6_SERVER_ID_OPTION */
00548     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_SERVER_ID_OPTION, serverLinkData) != 0) {
00549         return -1;
00550     }
00551 
00552     /** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
00553     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00554         return -1;
00555     }
00556 
00557     return 0;
00558 }
00559 
00560 
00561 
00562 int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
00563 {
00564     /**
00565      * Solication Message Should Include Next Options:
00566      *  - DHCPV6_ELAPSED_TIME_OPTION
00567      *  - DHCPV6_CLIENT_ID_OPTION
00568      *  - DHCPV6_IDENTITY_ASSOCIATION_OPTION
00569      *  - DHCPV6_OPTION_REQUEST_OPTION
00570      * Optionally:
00571      *  - DHCPV6_OPTION_REQUEST_RAPID_COMMIT
00572      */
00573     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00574 
00575     if (libdhcpv6_time_elapsed_option_at_packet(ptr, data_length) == false) {
00576         return -1;
00577     }
00578     /** Verify DHCPV6_CLIENT_ID_OPTION */
00579     if (libdhcpv6_get_duid_by_selected_type_id_opt(ptr, data_length, DHCPV6_CLIENT_ID_OPTION, clientLink) != 0) {
00580         return -1;
00581     }
00582 
00583 
00584     /** Verify DHCPV6_IDENTITY_ASSOCIATION_OPTION */
00585     if (libdhcpv6_get_IA_address(ptr, data_length, dhcp_ia_non_temporal_params) != 0) {
00586         return -1;
00587     }
00588 
00589     return 0;
00590 }
00591 #endif
00592 
00593 bool libdhcpv6_time_elapsed_option_at_packet(uint8_t *ptr, uint16_t length)
00594 {
00595     bool retVal = false;
00596     dhcp_options_msg_t option_msg;
00597     /** Verify First DHCPV6_ELAPSED_TIME_OPTION */
00598 
00599     if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_ELAPSED_TIME_OPTION, &option_msg) == 0) {
00600         if (option_msg.len == DHCPV6_ELAPSED_TIME_OPTION_LEN) {
00601             retVal = true;
00602         }
00603     }
00604     return retVal;
00605 }
00606 
00607 bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length)
00608 {
00609     bool retVal = false;
00610     dhcp_options_msg_t option_msg;
00611     if (libdhcpv6_message_option_discover(ptr, length, DHCPV6_OPTION_RAPID_COMMIT, &option_msg) == 0) {
00612         retVal = true;
00613     }
00614     return retVal;
00615 }
00616 
00617 bool libdhcpv6_duid_length_validate(uint16_t duid_type, uint16_t duid_length)
00618 {
00619     uint16_t min_length;
00620     switch (duid_type) {
00621         case DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE:
00622             //hardware type (16 bits) + time (32 bits) +link layer address (variable length 1 min)
00623             min_length = 7; //Link Time Time
00624             break;
00625         case DHCPV6_DUID_EN_TYPE: //enterprise-number (32-bits) +identifier (variable length 1 min)
00626             min_length = 5;
00627             break;
00628         case DHCPV6_DUID_LINK_LAYER_TYPE:
00629             //hardware type (16 bits)  + link layer address (variable length 1 min)
00630             min_length = 3; //Type 2 and MiN DUI-id 1
00631             break;
00632 
00633         case DHCPV6_DUID_UUID_TYPE:
00634             //UUID (128-bits)
00635             if (duid_length != 16) {
00636                 return false;
00637             }
00638             min_length = 16;
00639             break;
00640 
00641         default://Unsupported type set length to inpossible
00642             min_length = 0xffff;
00643             break;
00644     }
00645 
00646     //Validate min and MAX length
00647     if (min_length > duid_length || min_length == 0xffff) {
00648         //Too short
00649         return false;
00650     }
00651 
00652     if (duid_length > 128 - min_length) {
00653         //Too Long
00654         return false;
00655     }
00656 
00657     return true;
00658 }
00659 
00660 
00661 int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_duid_options_params_t *params)
00662 {
00663     dhcp_options_msg_t option_msg;
00664 
00665     /** Verify DHCPV6_CLIENT_ID_OPTION */
00666     if (libdhcpv6_message_option_discover(ptr, data_length, type, &option_msg) != 0) {
00667         return -1;
00668     }
00669 
00670     if (option_msg.len < 5) {
00671         return -1;
00672     }
00673 
00674     uint8_t *t_ptr = option_msg.msg_ptr;
00675     params->type = common_read_16_bit(t_ptr);
00676     t_ptr += 2;
00677     params->duid = t_ptr;
00678     params->duid_length = option_msg.len - 2;
00679     //Validate types and lengths
00680     if (!libdhcpv6_duid_length_validate(params->type, params->duid_length)) {
00681         return -1;
00682     }
00683 
00684     return 0;
00685 }
00686 
00687 int libdhcpv6_get_link_address_from_duid(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_link_options_params_t *params)
00688 {
00689 
00690     if ((type != DHCPV6_DUID_LINK_LAYER_TYPE && type != DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE) || data_length < 8) {
00691         return -1;
00692     }
00693 
00694     params->link_type = common_read_16_bit(ptr);
00695     ptr += 2;
00696     data_length -= 2;
00697     if (type == DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE) {
00698         params->link_time = common_read_32_bit(ptr);
00699         ptr += 4;
00700         data_length -= 4;
00701     } else {
00702         params->link_time = 0;
00703     }
00704     if (libdhcpv6_duid_linktype_size(params->link_type) > data_length) {
00705         return -1;
00706     }
00707 
00708     params->link_id = ptr;
00709     return 0;
00710 }
00711 
00712 
00713 int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params)
00714 {
00715     dhcp_options_msg_t option_msg;
00716     uint16_t status_code = 0;
00717 
00718     if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
00719         if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
00720             status_code = common_read_16_bit(option_msg.msg_ptr);
00721             if (status_code == DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE) {
00722                 return -1;
00723             }
00724         }
00725     }
00726 
00727     if (libdhcpv6_message_option_discover(ptr, data_length, DHCPV6_IDENTITY_ASSOCIATION_OPTION, &option_msg) == 0) {
00728         if (option_msg.len < DHCPV6_IDENTITY_ASSOCIATION_OPTION_MIN_LEN) {
00729             return -1;
00730         }
00731         uint8_t *t_ptr;
00732         uint16_t length;
00733         t_ptr = option_msg.msg_ptr;
00734         length = (option_msg.len - 12);
00735         params->iaId = common_read_32_bit(t_ptr);
00736         t_ptr += 4;
00737         params->T0 = common_read_32_bit(t_ptr);
00738         t_ptr += 4;
00739         params->T1 = common_read_32_bit(t_ptr);
00740         t_ptr += 4;
00741 
00742         if (length > 4) {
00743             if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_STATUS_CODE_OPTION, &option_msg) == 0) {
00744                 if (option_msg.len >= DHCPV6_STATUS_CODE_OPTION_LEN) {
00745                     status_code = common_read_16_bit(option_msg.msg_ptr);
00746                     if (status_code != 0) {
00747                         return -1;
00748                     }
00749                 }
00750             }
00751 
00752             if (libdhcpv6_message_option_discover(t_ptr, length, DHCPV6_IA_ADDRESS_OPTION, &option_msg) == 0) {
00753                 if (option_msg.len >= DHCPV6_IA_ADDRESS_OPTION_LEN) {
00754                     t_ptr = option_msg.msg_ptr;
00755                     params->nonTemporalAddress = t_ptr;
00756                     t_ptr += 16;
00757                     params->preferredValidLifeTime = common_read_32_bit(t_ptr);
00758                     t_ptr += 4;
00759                     params->validLifeTime = common_read_32_bit(t_ptr);
00760                     return 0;
00761                 }
00762             }
00763         } else if (length == 0) {
00764             params->nonTemporalAddress = NULL;
00765             params->preferredValidLifeTime = 0;
00766             params->validLifeTime = 0;
00767             return 0;
00768         }
00769     }
00770     return -1;
00771 }
00772 
00773 uint16_t libdhcpv6_address_request_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint8_t requstOptionCnt, bool add_address)
00774 {
00775     uint16_t length = 0;
00776     length += libdhcpv6_header_size();
00777     length += libdhcpv6_elapsed_time_option_size();
00778     length += libdhcpv6_duid_option_size(clientDUIDLength);
00779     length += libdhcpv6_duid_option_size(serverDUIDLength);
00780     length += libdhcvp6_request_option_size(requstOptionCnt);
00781     length += libdhcpv6_rapid_commit_option_size();
00782     length += libdhcpv6_non_temporal_address_size(add_address);
00783     return length;
00784 }
00785 #ifdef HAVE_DHCPV6_SERVER
00786 uint16_t libdhcpv6_address_reply_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint16_t vendorDataLen, bool rapidCommon, bool status)
00787 {
00788     uint16_t length = 0;
00789 
00790     length += libdhcpv6_header_size();
00791     length += libdhcpv6_duid_option_size(clientDUIDLength);
00792     length += libdhcpv6_duid_option_size(serverDUIDLength);
00793     if (rapidCommon) {
00794         length += libdhcpv6_rapid_commit_option_size();
00795     }
00796 
00797     if (vendorDataLen) {
00798         length += (vendorDataLen + 4);
00799     }
00800 
00801     if (status) {
00802         length += libdhcpv6_non_temporal_address_size(true);
00803     } else {
00804         length += libdhcpv6_non_temporal_address_size(false);
00805         length += libdhcpv6_status_option_size();
00806     }
00807 
00808     return length;
00809 }
00810 #endif
00811 
00812 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_duid_options_params_t *serverLink)
00813 {
00814     bool add_address = false;
00815     if (nonTemporalAddress) {
00816         add_address = true;
00817     }
00818     //Start Build Packet
00819     ptr = libdhcpv6_header_write(ptr, packet->messageType, packet->transActionId);
00820     //Elapsed time
00821     ptr = libdhcpv6_elapsed_time_option_write(ptr, 0);
00822     //Client Identifier
00823     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &packet->clientDUID); //16
00824     //SET Server ID if It is defined
00825     if (serverLink) {
00826         ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, serverLink);
00827     }
00828 
00829     //SET Server ID
00830     ptr = libdhcpv6_rapid_commit_option_write(ptr);
00831     //Request Option
00832     ptr = libdhcvp6_request_option_write(ptr, packet->requestedOptionCnt, packet->requestedOptionList);
00833     //CLient Identity Association
00834 
00835     ptr = libdhcpv6_identity_association_option_write(ptr, packet->iaID, packet->timerT0, packet->timerT1, add_address);
00836     if (add_address) {
00837         ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
00838     }
00839 
00840     return ptr;
00841 }
00842 
00843 
00844 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)
00845 {
00846     ptr = libdhcpv6_header_write(ptr, DHCPV6_REPLY_TYPE, replyPacket->transaction_ID);
00847     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, &replyPacket->serverDUID); //16
00848     ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &replyPacket->clientDUID); //16
00849 
00850     if (nonTemporalAddress) {
00851         ptr = libdhcpv6_identity_association_option_write(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, true);
00852         ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime);
00853     } else {
00854         ptr = libdhcpv6_identity_association_option_write_with_status(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE);
00855     }
00856 
00857     if (vendorData) {
00858         ptr = libdhcvp6_vendor_specific_option_write(ptr, vendorData->vendorData, vendorData->vendorDataLength);
00859     }
00860 
00861     if (replyPacket->rapidCommit) {
00862         ptr = libdhcpv6_rapid_commit_option_write(ptr);
00863     }
00864 
00865     return ptr;
00866 }
00867 
00868 uint16_t libdhcpv6_solication_message_length(uint16_t clientDUIDLength, bool addressDefined, uint8_t requestOptionCount)
00869 {
00870     uint16_t length = 0;
00871     length += libdhcpv6_header_size();
00872     length += libdhcpv6_elapsed_time_option_size();
00873     length += libdhcpv6_rapid_commit_option_size();
00874     length += libdhcpv6_duid_option_size(clientDUIDLength);
00875     length += libdhcpv6_non_temporal_address_size(addressDefined);
00876     length += libdhcvp6_request_option_size(requestOptionCount);
00877     return length;
00878 }
00879 
00880 
00881 uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_limit,  uint8_t *peer_addres, uint8_t *link_address)
00882 {
00883     *ptr++ = type;
00884     *ptr++ = hop_limit;
00885     memcpy(ptr, link_address, 16);
00886     ptr += 16;
00887     memcpy(ptr, peer_addres, 16);
00888     ptr += 16;
00889     return ptr;
00890 }
00891 
00892 uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length)
00893 {
00894     ptr = common_write_16_bit(DHCPV6_OPTION_RELAY, ptr);
00895     ptr = common_write_16_bit(length, ptr);
00896     return ptr;
00897 }
00898 
00899 bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t *relay_msg)
00900 {
00901     if (length < DHCPV6_RELAY_LENGTH + 4) {
00902         return false;
00903     }
00904     // Relay message base first
00905     relay_msg->type = *ptr++;
00906     relay_msg->hop_limit = *ptr++;
00907     relay_msg->link_address = ptr;
00908     relay_msg->peer_address = ptr + 16;
00909     ptr += 32;
00910     //Discover
00911     if (libdhcpv6_message_option_discover(ptr, length - 34, DHCPV6_OPTION_RELAY, &relay_msg->relay_options) != 0) {
00912         return false;
00913     }
00914 
00915 
00916     return true;
00917 }
00918 
00919 #endif