Knight KE / Mbed OS Game_Master
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 
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