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 if (srv_data_ptr->IAID != dhcp_ia_non_temporal_params.iaId) { 00139 tr_error("Wrong IAID"); 00140 goto error_exit; 00141 } 00142 00143 interfaceId.linkID = srv_data_ptr->clientId; 00144 interfaceId.linkType = srv_data_ptr->clientLinkIdType; 00145 if (libdhcpv6_compare_DUID(&interfaceId, &clientId) != 0) { 00146 tr_error("Not Valid Client Id"); 00147 goto error_exit; 00148 } 00149 00150 memcpy(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16); 00151 srv_data_ptr->iaNontemporalAddress.preferredTime = dhcp_ia_non_temporal_params.preferredValidLifeTime; 00152 srv_data_ptr->iaNontemporalAddress.validLifetime = dhcp_ia_non_temporal_params.validLifeTime; 00153 memcpy(srv_data_ptr->serverLinkId, serverId.linkID, 8); 00154 srv_data_ptr->serverLinkType = serverId.linkType; 00155 srv_data_ptr->serverLinkType = serverId.linkType; 00156 srv_data_ptr->T0 = dhcp_ia_non_temporal_params.T0; 00157 srv_data_ptr->T1 = dhcp_ia_non_temporal_params.T1; 00158 srv_data_ptr->iaNonTemporalStructValid = true; 00159 00160 thread_dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr); 00161 00162 00163 if (dhcp_client.global_address_cb) { 00164 dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, true); 00165 } 00166 return RET_MSG_ACCEPTED; 00167 error_exit: 00168 thread_dhcpv6_client_send_error_cb(srv_data_ptr); 00169 return RET_MSG_ACCEPTED; 00170 } 00171 00172 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) 00173 { 00174 dhcpv6_solication_base_packet_s solPacket = {0}; 00175 dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; 00176 uint8_t *payload_ptr; 00177 uint32_t payload_len; 00178 dhcpv6_client_server_data_t *srv_data_ptr; 00179 00180 if (mac64 == NULL || prefix == NULL || dhcp_addr == NULL) { 00181 tr_error("Invalid parameters"); 00182 return -1; 00183 } 00184 srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, DHCPV6_DUID_HARDWARE_EUI64_TYPE, prefix, dhcp_addr); 00185 payload_len = libdhcpv6_solication_message_length(DHCPV6_DUID_HARDWARE_EUI64_TYPE, true, 0); 00186 payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); 00187 00188 if (payload_ptr == NULL || srv_data_ptr == NULL) { 00189 ns_dyn_mem_free(payload_ptr); 00190 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00191 tr_error("Out of memory"); 00192 return -1; 00193 } 00194 dhcp_client.global_address_cb = error_cb; //TODO Only supporting one instance globaly if we need more for different instances needs code. 00195 srv_data_ptr->GlobalAddress = true; 00196 // Build solicit 00197 solPacket.clientDUID.linkID = mac64; 00198 solPacket.clientDUID.linkType = DHCPV6_DUID_HARDWARE_EUI64_TYPE; 00199 solPacket.iaID = srv_data_ptr->IAID; 00200 solPacket.messageType = DHCPV6_SOLICATION_TYPE; 00201 solPacket.transActionId = libdhcpv6_txid_get(); 00202 /*Non Temporal Address */ 00203 nonTemporalAddress.requestedAddress = prefix; 00204 libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL); 00205 00206 // send solicit 00207 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); 00208 return srv_data_ptr->transActionId ? 0 : -1; 00209 } 00210 void thread_dhcp_client_global_address_renew(int8_t interface) 00211 { 00212 // only prepared for changes in thread specifications 00213 (void)interface; 00214 return; 00215 } 00216 00217 void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]) 00218 { 00219 protocol_interface_info_entry_t *cur; 00220 dhcpv6_client_server_data_t *srv_data_ptr; 00221 (void) dhcp_addr; 00222 srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix); 00223 cur = protocol_stack_interface_info_get_by_id(interface); 00224 if (cur == NULL || srv_data_ptr == NULL) { 00225 tr_error("Not valid prefix"); 00226 return; 00227 } 00228 dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions 00229 addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); 00230 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00231 return; 00232 } 00233 00234 void thread_dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason) 00235 { 00236 dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; 00237 dhcp_link_options_params_t serverLink; 00238 uint8_t *payload_ptr; 00239 uint32_t payload_len; 00240 dhcpv6_client_server_data_t *srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address); 00241 00242 if (srv_data_ptr == NULL) { 00243 tr_warn("Dhcp address lost"); 00244 return ; 00245 } 00246 if (reason == ADDR_CALLBACK_INVALIDATED) { 00247 dhcp_service_req_remove(srv_data_ptr->transActionId);//stop retransmissions of renew 00248 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); 00249 tr_warn("Dhcp address lost"); 00250 return; 00251 } 00252 00253 if (reason != ADDR_CALLBACK_TIMER) { 00254 return; 00255 } 00256 00257 payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0); 00258 payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); 00259 if (payload_ptr == NULL) { 00260 addr->state_timer = 200;//Retry after? should there be maximum 20 second retry 00261 tr_error("Out of memory"); 00262 return ; 00263 } 00264 dhcpv6_solication_base_packet_s packetReq = { 00265 .messageType = DHCPV6_RENEW_TYPE, 00266 .clientDUID.linkID = srv_data_ptr->clientId, 00267 .clientDUID.linkType = srv_data_ptr->clientLinkIdType, 00268 .requestedOptionCnt = 0, 00269 .iaID = srv_data_ptr->IAID, 00270 .timerT0 = srv_data_ptr->T0, 00271 .timerT1 = srv_data_ptr->T1, 00272 .requestedOptionList = NULL, 00273 }; 00274 00275 // Set Address information 00276 nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix; 00277 nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime; 00278 nonTemporalAddress.validLifeTime = srv_data_ptr->iaNontemporalAddress.validLifetime; 00279 serverLink.linkID = srv_data_ptr->serverLinkId; 00280 serverLink.linkType = srv_data_ptr->serverLinkType; 00281 libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink); 00282 // send solicit 00283 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); 00284 } 00285 00286 void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) 00287 { 00288 protocol_interface_info_entry_t *cur = NULL; 00289 if_address_entry_t *address_entry = NULL; 00290 uint32_t renewTimer; 00291 00292 cur = protocol_stack_interface_info_get_by_id(interface_id); 00293 if (!cur) { 00294 return; 00295 } 00296 renewTimer = libdhcpv6_renew_time_define(srv_data_ptr); 00297 00298 address_entry = addr_get_entry(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); 00299 if (address_entry == NULL) { 00300 // create new 00301 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); 00302 } else { 00303 addr_set_valid_lifetime(cur, address_entry, srv_data_ptr->iaNontemporalAddress.validLifetime); 00304 addr_set_preferred_lifetime(cur, address_entry, srv_data_ptr->iaNontemporalAddress.preferredTime); 00305 } 00306 00307 if (address_entry == NULL) { 00308 tr_error("Address add failed"); 00309 return ; 00310 } 00311 if (renewTimer) { 00312 // translate seconds to 100ms ticks 00313 if (renewTimer < 0xffffffff / 10) { 00314 renewTimer *= 10; 00315 } else { 00316 renewTimer = 0xfffffffe; 00317 } 00318 } 00319 tr_debug("Added new address"); 00320 address_entry->state_timer = renewTimer; 00321 address_entry->cb = thread_dhcpv6_renew; 00322 } 00323 #endif
Generated on Tue Jul 12 2022 18:18:53 by
