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.
thread_dhcpv6_client.c
00001 /* 00002 * Copyright (c) 2013-2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: BSD-3-Clause 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holder nor the 00014 * names of its contributors may be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "nsconfig.h" 00031 #ifdef HAVE_THREAD 00032 #include <string.h> 00033 #include <ns_types.h> 00034 #include <ns_trace.h> 00035 #include "nsdynmemLIB.h" 00036 #include "ns_list.h" 00037 #include "common_functions.h" 00038 00039 00040 #include "dhcp_service_api.h" 00041 #include "thread_dhcpv6_client.h" 00042 #include "libDHCPv6/libDHCPv6.h" 00043 #include "NWK_INTERFACE/Include/protocol.h" 00044 #include "6LoWPAN/Thread/thread_common.h" 00045 #include "6LoWPAN/Thread/thread_bootstrap.h" 00046 00047 #define TRACE_GROUP "TDHP" 00048 00049 typedef struct { 00050 thread_dhcp_client_global_adress_cb *global_address_cb; 00051 uint16_t service_instance; 00052 uint8_t libDhcp_instance; 00053 int8_t interface; 00054 } thread_dhcp_client_class_t; 00055 00056 thread_dhcp_client_class_t dhcp_client; 00057 00058 void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr); 00059 00060 00061 void thread_dhcp_client_init(int8_t interface) 00062 { 00063 // No support for multible thread instances yet. 00064 dhcp_client.service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL); 00065 dhcp_client.interface = interface; 00066 dhcp_client.libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id(); 00067 00068 return; 00069 } 00070 00071 void thread_dhcp_client_delete(int8_t interface) 00072 { 00073 protocol_interface_info_entry_t *cur = NULL; 00074 dhcpv6_client_server_data_t *srv_data_ptr; 00075 00076 dhcp_service_delete(dhcp_client.service_instance); 00077 00078 00079 cur = protocol_stack_interface_info_get_by_id(interface); 00080 00081 if (!cur) { 00082 return; 00083 } 00084 00085 do { 00086 srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance); 00087 if (srv_data_ptr != NULL) { 00088 tr_debug("Free DHCPv6 Client\n"); 00089 dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions 00090 addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); 00091 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00092 } 00093 } while (srv_data_ptr != NULL); 00094 dhcp_client.service_instance = 0; 00095 return; 00096 } 00097 00098 00099 void thread_dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr) 00100 { 00101 if (srv_data_ptr != NULL) { 00102 00103 // error for Global address 00104 if (dhcp_client.global_address_cb != NULL) { 00105 dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, false); 00106 } 00107 } 00108 } 00109 00110 00111 /* solication responce received for either global address or routter id assignment */ 00112 int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uint8_t *msg_ptr, uint16_t msg_len) 00113 { 00114 dhcp_ia_non_temporal_params_t dhcp_ia_non_temporal_params; 00115 dhcp_link_options_params_t clientId; 00116 dhcp_link_options_params_t serverId; 00117 dhcp_link_options_params_t interfaceId; 00118 dhcpv6_client_server_data_t *srv_data_ptr = NULL; 00119 (void)instance_id; 00120 00121 srv_data_ptr = ptr; 00122 00123 if (srv_data_ptr == NULL) { 00124 tr_error("server data not found"); 00125 goto error_exit; 00126 } 00127 00128 // Validate message 00129 if (msg_name != DHCPV6_REPLY_TYPE) { 00130 tr_error("invalid response"); 00131 goto error_exit; 00132 } 00133 00134 if (libdhcpv6_reply_message_option_validate(&clientId, &serverId, &dhcp_ia_non_temporal_params, msg_ptr, msg_len) != 0) { 00135 tr_error("Sol Not include all Options"); 00136 goto error_exit; 00137 } 00138 00139 if (libdhcpv6_nonTemporal_entry_get_by_iaid(dhcp_ia_non_temporal_params.iaId) != srv_data_ptr) { 00140 /* Validate server data availability */ 00141 tr_error("Valid instance not found"); 00142 goto error_exit; 00143 } 00144 00145 if (srv_data_ptr->IAID != dhcp_ia_non_temporal_params.iaId) { 00146 tr_error("Wrong IAID"); 00147 goto error_exit; 00148 } 00149 00150 interfaceId.linkID = srv_data_ptr->clientId; 00151 interfaceId.linkType = srv_data_ptr->clientLinkIdType; 00152 if (libdhcpv6_compare_DUID(&interfaceId, &clientId) != 0) { 00153 tr_error("Not Valid Client Id"); 00154 goto error_exit; 00155 } 00156 00157 memcpy(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16); 00158 srv_data_ptr->iaNontemporalAddress.preferredTime = dhcp_ia_non_temporal_params.preferredValidLifeTime; 00159 srv_data_ptr->iaNontemporalAddress.validLifetime = dhcp_ia_non_temporal_params.validLifeTime; 00160 memcpy(srv_data_ptr->serverLinkId, serverId.linkID, 8); 00161 srv_data_ptr->serverLinkType = serverId.linkType; 00162 srv_data_ptr->serverLinkType = serverId.linkType; 00163 srv_data_ptr->T0 = dhcp_ia_non_temporal_params.T0; 00164 srv_data_ptr->T1 = dhcp_ia_non_temporal_params.T1; 00165 srv_data_ptr->iaNonTemporalStructValid = true; 00166 00167 thread_dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr); 00168 00169 00170 if (dhcp_client.global_address_cb) { 00171 dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, true); 00172 } 00173 return RET_MSG_ACCEPTED; 00174 error_exit: 00175 thread_dhcpv6_client_send_error_cb(srv_data_ptr); 00176 return RET_MSG_ACCEPTED; 00177 } 00178 00179 int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], thread_dhcp_client_global_adress_cb *error_cb) 00180 { 00181 dhcpv6_solication_base_packet_s solPacket = {0}; 00182 dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; 00183 uint8_t *payload_ptr; 00184 uint32_t payload_len; 00185 dhcpv6_client_server_data_t *srv_data_ptr; 00186 00187 if (mac64 == NULL || prefix == NULL || dhcp_addr == NULL) { 00188 tr_error("Invalid parameters"); 00189 return -1; 00190 } 00191 00192 srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, DHCPV6_DUID_HARDWARE_EUI64_TYPE, prefix, dhcp_addr); 00193 00194 payload_len = libdhcpv6_solication_message_length(DHCPV6_DUID_HARDWARE_EUI64_TYPE, true, 0); 00195 payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); 00196 00197 if (payload_ptr == NULL || srv_data_ptr == NULL) { 00198 ns_dyn_mem_free(payload_ptr); 00199 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00200 tr_error("Out of memory"); 00201 return -1; 00202 } 00203 dhcp_client.global_address_cb = error_cb; //TODO Only supporting one instance globaly if we need more for different instances needs code. 00204 srv_data_ptr->GlobalAddress = true; 00205 // Build solicit 00206 solPacket.clientDUID.linkID = mac64; 00207 solPacket.clientDUID.linkType = DHCPV6_DUID_HARDWARE_EUI64_TYPE; 00208 solPacket.iaID = srv_data_ptr->IAID; 00209 solPacket.messageType = DHCPV6_SOLICATION_TYPE; 00210 solPacket.transActionId = libdhcpv6_txid_get(); 00211 /*Non Temporal Address */ 00212 nonTemporalAddress.requestedAddress = prefix; 00213 libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL); 00214 00215 // send solicit 00216 srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr , dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb); 00217 return srv_data_ptr->transActionId ? 0 : -1; 00218 } 00219 00220 void thread_dhcp_client_global_address_renew(int8_t interface) 00221 { 00222 // only prepared for changes in thread specifications 00223 (void)interface; 00224 return; 00225 } 00226 00227 void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]) 00228 { 00229 protocol_interface_info_entry_t *cur; 00230 dhcpv6_client_server_data_t *srv_data_ptr; 00231 (void) dhcp_addr; 00232 00233 srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix); 00234 cur = protocol_stack_interface_info_get_by_id(interface); 00235 00236 do { 00237 if (cur == NULL || srv_data_ptr == NULL) { 00238 return; 00239 } 00240 dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions 00241 tr_debug("Deleting address: %s", trace_ipv6(srv_data_ptr->iaNontemporalAddress.addressPrefix)); 00242 00243 addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); 00244 00245 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00246 srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix); 00247 } while (srv_data_ptr); 00248 00249 return; 00250 } 00251 00252 void thread_dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason) 00253 { 00254 dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; 00255 dhcp_link_options_params_t serverLink; 00256 uint8_t *payload_ptr; 00257 uint32_t payload_len; 00258 dhcpv6_client_server_data_t *srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address); 00259 00260 if (srv_data_ptr == NULL) { 00261 tr_warn("Dhcp address lost"); 00262 return ; 00263 } 00264 if (reason == ADDR_CALLBACK_INVALIDATED) { 00265 dhcp_service_req_remove(srv_data_ptr->transActionId);//stop retransmissions of renew 00266 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00267 tr_warn("Dhcp address lost"); 00268 return; 00269 } 00270 00271 if (reason != ADDR_CALLBACK_TIMER) { 00272 return; 00273 } 00274 00275 payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0); 00276 payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); 00277 if (payload_ptr == NULL) { 00278 addr->state_timer = 200;//Retry after? should there be maximum 20 second retry 00279 tr_error("Out of memory"); 00280 return ; 00281 } 00282 dhcpv6_solication_base_packet_s packetReq = { 00283 .messageType = DHCPV6_RENEW_TYPE, 00284 .clientDUID.linkID = srv_data_ptr->clientId, 00285 .clientDUID.linkType = srv_data_ptr->clientLinkIdType, 00286 .requestedOptionCnt = 0, 00287 .iaID = srv_data_ptr->IAID, 00288 .timerT0 = srv_data_ptr->T0, 00289 .timerT1 = srv_data_ptr->T1, 00290 .requestedOptionList = NULL, 00291 }; 00292 00293 // Set Address information 00294 nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix; 00295 nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime; 00296 nonTemporalAddress.validLifeTime = srv_data_ptr->iaNontemporalAddress.validLifetime; 00297 serverLink.linkID = srv_data_ptr->serverLinkId; 00298 serverLink.linkType = srv_data_ptr->serverLinkType; 00299 libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink); 00300 // send solicit 00301 srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, srv_data_ptr->server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb); 00302 } 00303 00304 void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) 00305 { 00306 protocol_interface_info_entry_t *cur = NULL; 00307 if_address_entry_t *address_entry = NULL; 00308 uint32_t renewTimer; 00309 00310 cur = protocol_stack_interface_info_get_by_id(interface_id); 00311 if (!cur) { 00312 return; 00313 } 00314 renewTimer = libdhcpv6_renew_time_define(srv_data_ptr); 00315 00316 address_entry = addr_get_entry(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); 00317 if (address_entry == NULL) { 00318 // create new 00319 address_entry = addr_add(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix, 64, ADDR_SOURCE_DHCP, srv_data_ptr->iaNontemporalAddress.validLifetime, srv_data_ptr->iaNontemporalAddress.preferredTime, false); 00320 } else { 00321 addr_set_valid_lifetime(cur, address_entry, srv_data_ptr->iaNontemporalAddress.validLifetime); 00322 addr_set_preferred_lifetime(cur, address_entry, srv_data_ptr->iaNontemporalAddress.preferredTime); 00323 } 00324 00325 if (address_entry == NULL) { 00326 tr_error("Address add failed"); 00327 return; 00328 } 00329 if (renewTimer) { 00330 // translate seconds to 100ms ticks 00331 if (renewTimer < 0xffffffff / 10) { 00332 renewTimer *= 10; 00333 } else { 00334 renewTimer = 0xfffffffe; 00335 } 00336 } 00337 address_entry->state_timer = renewTimer; 00338 address_entry->cb = thread_dhcpv6_renew; 00339 } 00340 #endif
Generated on Tue Jul 12 2022 12:45:57 by
