Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:26 by
