Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_dhcpv6_client.c Source File

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