EL4121 Embedded System / mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_border_router_api.c Source File

thread_border_router_api.c

00001 /*
00002  * Copyright (c) 2014-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 #include "nsconfig.h"
00030 
00031 #include <string.h>
00032 #include "ns_types.h"
00033 #include <nsdynmemLIB.h>
00034 #include "eventOS_event.h"
00035 #include <ns_list.h>
00036 #include "ns_trace.h"
00037 #include "Core/include/ns_buffer.h"
00038 #include "common_functions.h"
00039 #include "randLIB.h"
00040 #include "thread_border_router_api.h"
00041 #include "thread_management_if.h"
00042 #include "NWK_INTERFACE/Include/protocol.h"
00043 #include "6LoWPAN/Thread/thread_config.h"
00044 #include "6LoWPAN/Thread/thread_common.h"
00045 #include "6LoWPAN/Thread/thread_network_data_lib.h"
00046 #include "6LoWPAN/Thread/thread_network_data_storage.h"
00047 #include "6LoWPAN/Thread/thread_management_client.h"
00048 #include "6LoWPAN/Thread/thread_joiner_application.h"
00049 #include "6LoWPAN/Thread/thread_tmfcop_lib.h"
00050 #include "6LoWPAN/Thread/thread_border_router_api_internal.h"
00051 #include "6LoWPAN/Thread/thread_mdns.h"
00052 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00053 #include "6LoWPAN/MAC/mac_helper.h"
00054 #include "MLE/mle.h"
00055 #include "thread_meshcop_lib.h"
00056 #include "thread_network_data_lib.h"
00057 #include "coap_service_api.h"
00058 
00059 #define TRACE_GROUP "tBRa"
00060 
00061 #ifdef HAVE_THREAD_ROUTER
00062 /*
00063  * Structure containing IPv6 Router advertisement options for DNS configuration.
00064  */
00065 typedef struct {
00066     uint16_t option_length;
00067     uint8_t *option_data;
00068 } dns_option_t;
00069 
00070 /*
00071  * Border router instance data.
00072  */
00073 typedef struct {
00074     dns_option_t *dns_search_list_option; /* option_data encoded according to RFC6106, DNSSL */
00075     dns_option_t *recursive_dns_server_option;  /* option_data encoded according to RFC6106, RDNSS */
00076     uint16_t nwk_data_resubmit_timer; /* network data resubmit timeout */
00077     int8_t interface_id;
00078     int8_t coap_service_id;
00079     ns_list_link_t link;
00080 } thread_border_router_t;
00081 
00082 /* Neighbor discovery options according to RFC6106 (rfc4861) */
00083 #define RFC6106_RECURSIVE_DNS_SERVER_OPTION     25
00084 #define RFC6106_DNS_SEARCH_LIST_OPTION          31
00085 static NS_LIST_DEFINE(border_router_instance_list, thread_border_router_t, link);
00086 
00087 
00088 static thread_border_router_t *thread_border_router_find_by_interface(int8_t interface_id)
00089 {
00090     thread_border_router_t *this = NULL;
00091     ns_list_foreach(thread_border_router_t, cur_br, &border_router_instance_list) {
00092         if (cur_br->interface_id == interface_id) {
00093             this = cur_br;
00094             break;
00095         }
00096     }
00097     return this;
00098 }
00099 
00100 static thread_border_router_t *thread_border_router_find_by_service(int8_t service_id)
00101 {
00102     thread_border_router_t *this = NULL;
00103     ns_list_foreach(thread_border_router_t, cur_br, &border_router_instance_list) {
00104         if (cur_br->coap_service_id == service_id) {
00105             this = cur_br;
00106             break;
00107         }
00108     }
00109     return this;
00110 }
00111 
00112 /*
00113  * Read Border Router TLV: DNS search list option.
00114  * DNSSL option data will be fetched from:
00115  * 1. User has provided static configuration by using method thread_border_router_dns_search_list_option_set.
00116  * 2. ICMP RA messages (if service is enabled and running in background).
00117  */
00118 static uint8_t *thread_management_server_border_router_nd_dnssl_option_read(thread_border_router_t *this, uint16_t *resp_len)
00119 {
00120     if (this->dns_search_list_option) {
00121         *resp_len = this->dns_search_list_option->option_length;
00122         return (uint8_t*)&this->dns_search_list_option->option_data;
00123     } else {
00124         // TODO: Read DNSSL from stored ICMP RA messages.
00125         *resp_len = 0;
00126         return NULL;
00127     }
00128 }
00129 
00130 /*
00131  * Read Border Router TLV: Recursive DNS Server option.
00132  * RDNSS option data will be fetched from:
00133  * 1. User has provided static configuration by using method thread_border_router_recursive_dns_server_option_set.
00134  * 2. ICMP RA messages (if service is enabled and running in background).
00135  */
00136 static uint8_t *thread_management_server_border_router_nd_rdnss_option_read(thread_border_router_t *this, uint16_t *resp_len)
00137 {
00138     if (this->recursive_dns_server_option) {
00139         *resp_len = this->recursive_dns_server_option->option_length;
00140         return (uint8_t*)&this->recursive_dns_server_option->option_data;
00141     } else {
00142         // TODO: Read RDNSS from stored ICMP RA messages.
00143         *resp_len = 0;
00144         return NULL;
00145     }
00146 }
00147 
00148 /**
00149  * Thread Neighbor discovery data request handler
00150  */
00151 static int thread_border_router_neighbor_discovery_data_req_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00152 {
00153     thread_border_router_t *this = thread_border_router_find_by_service(service_id);
00154     uint8_t *request_tlv_ptr;
00155     uint8_t *resp_payload_ptr;
00156     uint16_t options_len, rdnss_option_len, dnssl_option_len, payload_len;
00157     uint8_t options_data[4];
00158     uint8_t *dns_server_tlv_ptr = NULL;
00159     uint8_t *dns_search_list_tlv_ptr = NULL;
00160     uint8_t *ptr;
00161     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_CHANGED;
00162     (void) source_port;
00163     (void) source_address;
00164 
00165     tr_debug("neighbor data request");
00166 
00167     if (!this) {
00168         return -1;
00169     }
00170 
00171     request_tlv_ptr = options_data;
00172     rdnss_option_len = dnssl_option_len = 0;
00173 
00174     options_len = thread_tmfcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_ND_OPTION, &request_tlv_ptr);
00175 
00176     while (options_len > 0) {
00177         switch (*request_tlv_ptr) {
00178             case RFC6106_RECURSIVE_DNS_SERVER_OPTION:
00179                 dns_server_tlv_ptr = thread_management_server_border_router_nd_rdnss_option_read(this, &rdnss_option_len);
00180                 break;
00181             case RFC6106_DNS_SEARCH_LIST_OPTION:
00182                 dns_search_list_tlv_ptr = thread_management_server_border_router_nd_dnssl_option_read(this, &dnssl_option_len);
00183                 break;
00184         }
00185         request_tlv_ptr++;
00186         options_len--;
00187     }
00188 
00189     payload_len = rdnss_option_len + dnssl_option_len;
00190 
00191     resp_payload_ptr = ptr = ns_dyn_mem_alloc(payload_len + 4); //reserve space also for type/length
00192     if (!resp_payload_ptr) {
00193         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00194         goto send_response;
00195     }
00196 
00197     *ptr++ = TMFCOP_TLV_ND_DATA;
00198     if (payload_len > 255) {
00199         *ptr++ = 0xff;
00200         ptr = common_write_16_bit(payload_len, ptr);
00201     } else {
00202         *ptr++ = payload_len;
00203     }
00204 
00205     if (dns_server_tlv_ptr) {
00206         memcpy(ptr, dns_server_tlv_ptr, rdnss_option_len);
00207         ptr += rdnss_option_len;
00208     }
00209 
00210     if (dns_search_list_tlv_ptr) {
00211         memcpy(ptr, dns_search_list_tlv_ptr, dnssl_option_len);
00212         ptr += dnssl_option_len;
00213     }
00214 
00215 send_response:
00216     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_OCTET_STREAM, resp_payload_ptr, ptr-resp_payload_ptr);
00217     ns_dyn_mem_free(resp_payload_ptr);
00218     return 0;
00219 }
00220 /*
00221  * Check that local prefix is available in received network data
00222  */
00223 static bool thread_border_router_network_data_prefix_match(thread_network_data_cache_entry_t *network_data_ptr, thread_network_local_data_entry_t *local_prefix, uint16_t router_id)
00224 {
00225     ns_list_foreach(thread_network_data_prefix_cache_entry_t, nwk_prefix, &network_data_ptr->localPrefixList ) {
00226         if (nwk_prefix->servicesPrefixLen != local_prefix->servicesPrefixLen) {
00227             continue;
00228         }
00229 
00230         if (!bitsequal(nwk_prefix->servicesPrefix, local_prefix->servicesPrefix, local_prefix->servicesPrefixLen)) {
00231             continue;
00232         }
00233 
00234         // check that prefix is hosted by this router
00235         if (!thread_nd_hosted_by_this_routerid(router_id, &nwk_prefix->routeList) &&
00236             !thread_nd_hosted_by_this_routerid(router_id, &nwk_prefix->borderRouterList)) {
00237             return false;
00238         }
00239 
00240         return true;
00241     }
00242 
00243     return false;
00244 }
00245 
00246 /*
00247  * Check that local service is available in network data
00248  */
00249 static bool thread_border_router_network_data_service_match(thread_network_data_cache_entry_t *network_data_ptr, thread_network_data_service_entry_t *local_service, uint16_t router_id)
00250 {
00251     thread_network_data_service_cache_entry_t *service_cache_entry = thread_network_data_service_entry_find(&network_data_ptr->service_list, local_service);
00252 
00253     if (service_cache_entry) {
00254         return thread_network_data_service_hosted_by_this_router_id(service_cache_entry, router_id);
00255     }
00256 
00257     return false;
00258 }
00259 
00260 static bool thread_border_router_local_network_data_prefix_match(thread_network_local_data_cache_entry_t *local_data, thread_network_data_prefix_cache_entry_t *prefix, uint16_t router_id)
00261 {
00262     bool instance_found = false;
00263 
00264     if (thread_nd_hosted_by_this_routerid(router_id, &prefix->routeList)) {
00265         instance_found = true;
00266     }
00267 
00268     if (thread_nd_hosted_by_this_routerid(router_id, &prefix->borderRouterList)) {
00269         instance_found = true;
00270     }
00271 
00272     if (!instance_found) {
00273         /* Router ID not in propagated network data; skip */
00274         return true;
00275     }
00276 
00277     instance_found = false;
00278 
00279     ns_list_foreach(thread_network_local_data_entry_t, localPrefix, &local_data->prefix_list) {
00280         if (prefix->servicesPrefixLen  != localPrefix->servicesPrefixLen) {
00281             continue;
00282         }
00283 
00284         if (bitsequal(prefix->servicesPrefix , localPrefix->servicesPrefix, localPrefix->servicesPrefixLen)) {
00285             /* Prefix exists in local data; return true */
00286             instance_found = true;
00287             break;
00288         }
00289     }
00290 
00291     if (!instance_found) {
00292         tr_debug("Found missing prefix: %s", trace_array(prefix->servicesPrefix , 8));
00293         return false;
00294     }
00295 
00296     return true;
00297 }
00298 
00299 static bool thread_border_router_local_network_data_service_match(thread_network_local_data_cache_entry_t *local_data, thread_network_data_service_cache_entry_t *service, uint16_t router_id)
00300 {
00301     bool instance_found = false;
00302 
00303     ns_list_foreach(thread_network_data_service_server_entry_t, server, &service->server_list) {
00304         if (server->router_id == router_id) {
00305             instance_found = true;
00306             break;
00307         }
00308     }
00309 
00310     if (!instance_found) {
00311         /* Router ID not in propagated network data; skip */
00312         return true;
00313     }
00314 
00315     ns_list_foreach(thread_network_data_service_entry_t, local_service, &local_data->service_list) {
00316         if (local_service->S_service_data_length != service->S_service_data_length) {
00317             continue;
00318         }
00319 
00320         if (memcmp(local_service->S_service_data, service->S_service_data, local_service->S_service_data_length) != 0) {
00321             continue;
00322         }
00323 
00324         if (local_service->S_enterprise_number != service->S_enterprise_number) {
00325             continue;
00326         }
00327 
00328         /* Service exists in local data; return true */
00329         return true;
00330     }
00331 
00332     tr_debug("Found missing service: %s", trace_array(service->S_service_data, service->S_service_data_length));
00333     return false;
00334 }
00335 
00336 /*
00337  * Check that local server data is available in network data
00338  */
00339 static bool thread_border_router_local_srv_data_in_network_data_check(protocol_interface_info_entry_t *cur)
00340 {
00341     thread_network_data_cache_entry_t *network_data;
00342     thread_network_local_data_cache_entry_t *local_data;
00343     uint16_t router_id = cur->mac_parameters->mac_short_address;
00344 
00345     network_data = &cur->thread_info->networkDataStorage;
00346     local_data = &cur->thread_info->localServerDataBase;
00347 
00348     ns_list_foreach(thread_network_local_data_entry_t, localPrefix, &local_data->prefix_list) {
00349         // find matching prefix from network data
00350         if (thread_border_router_network_data_prefix_match(network_data, localPrefix, router_id) == false) {
00351             return false;
00352         }
00353     }
00354 
00355     ns_list_foreach(thread_network_data_service_entry_t, localService, &local_data->service_list) {
00356         // find matching service from network data
00357         if (thread_border_router_network_data_service_match(network_data, localService, router_id) == false) {
00358             return false;
00359         }
00360     }
00361 
00362     ns_list_foreach(thread_network_data_prefix_cache_entry_t, prefix, &network_data->localPrefixList ) {
00363         if (thread_border_router_local_network_data_prefix_match(local_data, prefix, router_id) == false) {
00364             return false;
00365         }
00366     }
00367 
00368     ns_list_foreach(thread_network_data_service_cache_entry_t, service, &network_data->service_list) {
00369         if (thread_border_router_local_network_data_service_match(local_data, service, router_id) == false) {
00370             return false;
00371         }
00372     }
00373 
00374     return true;
00375 }
00376 
00377 static int thread_border_router_recursive_dns_server_option_store(int8_t interface_id, uint8_t *recursive_dns_server_option, uint16_t recursive_dns_server_option_len)
00378 {
00379     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00380     if (!this) {
00381         return -1;
00382     }
00383 
00384     ns_dyn_mem_free(this->recursive_dns_server_option);
00385 
00386     if (recursive_dns_server_option) {
00387         this->recursive_dns_server_option = ns_dyn_mem_alloc(sizeof(dns_option_t) + recursive_dns_server_option_len);
00388         if (!this->recursive_dns_server_option) {
00389             return -2;
00390         }
00391         memcpy(&this->recursive_dns_server_option->option_data, recursive_dns_server_option, recursive_dns_server_option_len);
00392         this->recursive_dns_server_option->option_length = recursive_dns_server_option_len;
00393     }
00394     return 0;
00395 }
00396 
00397 static int thread_border_router_dns_search_list_option_store(int8_t interface_id, uint8_t *dns_search_list_option, uint16_t search_list_option_len)
00398 {
00399     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00400     if (!this) {
00401         return -1;
00402     }
00403 
00404     ns_dyn_mem_free(this->dns_search_list_option);
00405     if (dns_search_list_option) {
00406         this->dns_search_list_option = ns_dyn_mem_alloc(sizeof(dns_option_t) + search_list_option_len);
00407         if (!this->dns_search_list_option) {
00408             return -2;
00409         }
00410         memcpy(&this->dns_search_list_option->option_data, dns_search_list_option, search_list_option_len);
00411         this->dns_search_list_option->option_length = search_list_option_len;
00412     }
00413     return 0;
00414 }
00415 
00416 int8_t thread_border_router_init(int8_t interface_id)
00417 {
00418     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00419     if (this) {
00420         return 0;
00421     }
00422 
00423     tr_debug("thread_border_router_init if=%d", interface_id);
00424 
00425     this = ns_dyn_mem_alloc(sizeof(thread_border_router_t));
00426     if (!this) {
00427         return -2;
00428     }
00429     this->dns_search_list_option = NULL;
00430     this->recursive_dns_server_option = NULL;
00431     this->interface_id = interface_id;
00432     this->nwk_data_resubmit_timer = 0;
00433     this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL);
00434     if (this->coap_service_id < 0) {
00435         tr_warn("Thread border router coap init failed");
00436         ns_dyn_mem_free(this);
00437         return -3;
00438     }
00439     // Register to Mesh CoAP URIs
00440     coap_service_register_uri(this->coap_service_id, THREAD_URI_NEIGHBOR_DISCOVERY_DATA_REQ, COAP_SERVICE_ACCESS_GET_ALLOWED, thread_border_router_neighbor_discovery_data_req_cb);
00441 
00442     ns_list_add_to_start(&border_router_instance_list, this);
00443     return 0;
00444 }
00445 
00446 void thread_border_router_delete(int8_t interface_id)
00447 {
00448     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00449     if (!this) {
00450         return;
00451     }
00452 
00453     coap_service_delete(this->coap_service_id);
00454 
00455     ns_list_remove(&border_router_instance_list, this);
00456     ns_dyn_mem_free(this->dns_search_list_option);
00457     ns_dyn_mem_free(this->recursive_dns_server_option);
00458     ns_dyn_mem_free(this);
00459 }
00460 void thread_border_router_seconds_timer(int8_t interface_id, uint32_t seconds)
00461 {
00462     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00463     if (!this) {
00464         return;
00465     }
00466 
00467     if (this->nwk_data_resubmit_timer) {
00468         if (this->nwk_data_resubmit_timer > seconds) {
00469             this->nwk_data_resubmit_timer -= seconds;
00470         } else {
00471              protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00472              this->nwk_data_resubmit_timer = 0;
00473              if (cur) {
00474                  if (!thread_border_router_local_srv_data_in_network_data_check(cur)) {
00475                      tr_info("nwk data mismatch - resubmit");
00476                      thread_border_router_publish(cur->id);
00477                  }
00478              }
00479         }
00480     }
00481 }
00482 
00483 void thread_border_router_resubmit_timer_set(int8_t interface_id, int16_t seconds)
00484 {
00485     thread_border_router_t *this = thread_border_router_find_by_interface(interface_id);
00486 
00487     if (!this) {
00488         return;
00489     }
00490 
00491     if (seconds >= 0) {
00492         this->nwk_data_resubmit_timer = seconds;
00493     } else {
00494         // re-init network data resubmit timer to default value
00495         this->nwk_data_resubmit_timer = THREAD_DATA_RESUBMIT_DELAY + randLIB_get_random_in_range(0, THREAD_DATA_RESUBMIT_DELAY/10);
00496     }
00497 }
00498 
00499 void thread_border_router_network_data_appl_callback(protocol_interface_info_entry_t *cur)
00500 {
00501     if (cur->thread_info->network_data_tlv_cb) {
00502         uint16_t payload_len = thread_network_data_tlv_size(cur, true);
00503         uint8_t *payload_ptr = ns_dyn_mem_alloc(payload_len + 3); /* 3 => room is also needed for TLV ID and length */
00504         if (payload_ptr) {
00505             thread_network_data_tlv_write(cur, payload_ptr, true);
00506             // Send Network data TLV to application without TLV ID and length
00507             cur->thread_info->network_data_tlv_cb(cur->thread_info->interface_id, payload_ptr + 2, payload_len);
00508             ns_dyn_mem_free(payload_ptr);
00509         }
00510     }
00511 }
00512 
00513 void thread_border_router_network_data_update_notify(protocol_interface_info_entry_t *cur)
00514 {
00515     thread_border_router_t *this = thread_border_router_find_by_interface(cur->thread_info->interface_id);
00516 
00517     if (!this) {
00518         return;
00519     }
00520     if (!thread_border_router_local_srv_data_in_network_data_check(cur)) {
00521         if (this->nwk_data_resubmit_timer == 0) {
00522             this->nwk_data_resubmit_timer = 5;
00523             tr_debug("Resubmitted timer trig");
00524         }
00525 
00526     } else {
00527         tr_debug("All data registered");
00528         this->nwk_data_resubmit_timer = 0;
00529     }
00530 
00531     thread_border_router_network_data_appl_callback(cur);
00532 }
00533 #endif // HAVE_THREAD_ROUTER
00534 
00535 /*External APIs*/
00536 
00537 int thread_border_router_prefix_add(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len, thread_border_router_info_t *prefix_info_ptr)
00538 {
00539 #ifdef HAVE_THREAD_ROUTER
00540     protocol_interface_info_entry_t *cur;
00541     thread_prefix_tlv_t prefixTlv;
00542     thread_border_router_tlv_entry_t service;
00543     cur = protocol_stack_interface_info_get_by_id(interface_id);
00544     if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) {
00545         return -1;
00546     }
00547 
00548     if (!prefix_info_ptr || !prefix_ptr) {
00549         return -2;
00550     }
00551     if(prefix_info_ptr->P_dhcp == true && prefix_info_ptr->P_slaac == true) {
00552         return -3;// Can not configure both services on
00553     }
00554 
00555     prefixTlv.domainId = 0;
00556     prefixTlv.Prefix = prefix_ptr;
00557     prefixTlv.PrefixLen = prefix_len;
00558 
00559     service.P_configure = prefix_info_ptr->P_configure;
00560     service.P_default_route = prefix_info_ptr->P_default_route;
00561     service.P_dhcp = prefix_info_ptr->P_dhcp;
00562     service.P_preferred = prefix_info_ptr->P_preferred;
00563     service.P_slaac = prefix_info_ptr->P_slaac;
00564     service.Prf = prefix_info_ptr->Prf;
00565     service.stableData = prefix_info_ptr->stableData;
00566     service.P_on_mesh = prefix_info_ptr->P_on_mesh;
00567     service.P_nd_dns = prefix_info_ptr->P_nd_dns;
00568 
00569     return thread_local_server_list_add_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv, &service);
00570 #else
00571     (void) interface_id;
00572     (void) prefix_ptr;
00573     (void) prefix_len;
00574     (void) prefix_info_ptr;
00575     return -1;
00576 #endif
00577 }
00578 
00579 int thread_border_router_prefix_delete(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len)
00580 {
00581 #ifdef HAVE_THREAD_ROUTER
00582     protocol_interface_info_entry_t *cur;
00583     thread_prefix_tlv_t prefixTlv;
00584     cur = protocol_stack_interface_info_get_by_id(interface_id);
00585     if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) {
00586         return -1;
00587     }
00588 
00589     if (!prefix_ptr) {
00590         return -2;
00591     }
00592     prefixTlv.domainId = 0;
00593     prefixTlv.Prefix = prefix_ptr;
00594     prefixTlv.PrefixLen = prefix_len;
00595 
00596     return thread_local_server_list_del_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv);
00597 #else
00598     (void) interface_id;
00599     (void) prefix_ptr;
00600     (void) prefix_len;
00601     return -1;
00602 #endif
00603 }
00604 
00605 int thread_border_router_route_add(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len, bool stable, int8_t prf)
00606 {
00607 #ifdef HAVE_THREAD_ROUTER
00608     thread_prefix_tlv_t prefixTlv;
00609     thread_border_router_tlv_entry_t route;
00610     protocol_interface_info_entry_t *cur;
00611 
00612     cur = protocol_stack_interface_info_get_by_id(interface_id);
00613     if (!cur) {
00614         return -1;
00615     }
00616 
00617     if (!cur->thread_info || thread_attach_ready(cur) != 0) {
00618         return -2;
00619     }
00620     prefixTlv.domainId = 0;
00621     prefixTlv.Prefix = prefix_ptr;
00622     prefixTlv.PrefixLen = prefix_len;
00623 
00624     memset(&route, 0, sizeof(thread_border_router_tlv_entry_t));
00625     route.Prf = prf;
00626     route.stableData = stable;
00627 
00628     return thread_local_server_add_route(&cur->thread_info->localServerDataBase, &prefixTlv, &route);
00629 #else
00630     (void) interface_id;
00631     (void) prefix_ptr;
00632     (void) prefix_len;
00633     (void) stable;
00634     (void) prf;
00635     return -1;
00636 #endif
00637 }
00638 
00639 int thread_border_router_route_delete(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len)
00640 {
00641 #ifdef HAVE_THREAD_ROUTER
00642     thread_prefix_tlv_t prefixTlv;
00643     protocol_interface_info_entry_t *cur;
00644 
00645     cur = protocol_stack_interface_info_get_by_id(interface_id);
00646     if (!cur) {
00647         return -1;
00648     }
00649 
00650     if (!cur->thread_info || thread_attach_ready(cur) != 0) {
00651         return -1;
00652     }
00653 
00654     prefixTlv.domainId = 0;
00655     prefixTlv.Prefix = prefix_ptr;
00656     prefixTlv.PrefixLen = prefix_len;
00657 
00658     return thread_local_server_del_route(&cur->thread_info->localServerDataBase, &prefixTlv);
00659 #else
00660     (void) interface_id;
00661     (void) prefix_ptr;
00662     (void) prefix_len;
00663     return -1;
00664 #endif
00665 
00666 }
00667 
00668 int thread_border_router_service_add(int8_t interface_id, uint8_t *service_data, uint8_t service_len, uint8_t sid, uint32_t enterprise_number, uint8_t *server_data, uint8_t server_data_len, bool stable)
00669 {
00670 #ifdef HAVE_THREAD_ROUTER
00671     protocol_interface_info_entry_t *cur;
00672     cur = protocol_stack_interface_info_get_by_id(interface_id);
00673 
00674     if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) {
00675         return -1;
00676     }
00677 
00678     if (!service_data || !service_len) {
00679         return -2;
00680     }
00681 
00682     thread_network_data_service_entry_t service = {
00683         .T = false,
00684         .S_id = sid,
00685         .S_enterprise_number = enterprise_number,
00686         .S_service_data = service_data,
00687         .S_service_data_length = service_len,
00688         .S_server_data = server_data,
00689         .S_server_data_length = server_data_len,
00690         .S_stable = stable,
00691     };
00692 
00693     if (enterprise_number == THREAD_ENTERPRISE_NUMBER) {
00694         service.T = true;
00695     }
00696 
00697     return thread_local_service_list_add(&cur->thread_info->localServerDataBase, &service);
00698 #else
00699     (void)interface_id;
00700     (void)service_data;
00701     (void)service_len;
00702     (void)sid;
00703     (void)enterprise_number;
00704     (void)server_data;
00705     (void)server_data_len;
00706     (void)stable;
00707     return -1;
00708 #endif
00709 }
00710 
00711 int thread_border_router_service_delete(int8_t interface_id, uint8_t *service_data, uint8_t service_len, uint32_t enterprise_number)
00712 {
00713 #ifdef HAVE_THREAD_ROUTER
00714     protocol_interface_info_entry_t *cur;
00715     cur = protocol_stack_interface_info_get_by_id(interface_id);
00716 
00717     if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) {
00718         return -1;
00719     }
00720 
00721     if (!service_data || !service_len) {
00722         return -2;
00723     }
00724 
00725     thread_network_data_service_entry_t service = {
00726         .S_enterprise_number = enterprise_number,
00727         .S_service_data = service_data,
00728         .S_service_data_length = service_len,
00729     };
00730 
00731     return thread_local_service_list_del(&cur->thread_info->localServerDataBase, &service);
00732 #else
00733     (void) interface_id;
00734     (void) service_data;
00735     (void) service_len;
00736     (void) enterprise_number;
00737     return -1;
00738 #endif
00739 }
00740 
00741 int thread_border_router_recursive_dns_server_option_set(int8_t interface_id, uint8_t *recursive_dns_server_option, uint16_t recursive_dns_server_option_len)
00742 {
00743 #ifdef HAVE_THREAD_BORDER_ROUTER
00744     return thread_border_router_recursive_dns_server_option_store(interface_id, recursive_dns_server_option, recursive_dns_server_option_len);
00745 #else
00746     (void)interface_id;
00747     (void)recursive_dns_server_option;
00748     (void)recursive_dns_server_option_len;
00749     return -1;
00750 #endif
00751 }
00752 
00753 int thread_border_router_dns_search_list_option_set(int8_t interface_id, uint8_t *dns_search_list_option, uint16_t search_list_option_len)
00754 {
00755 #ifdef HAVE_THREAD_BORDER_ROUTER
00756     return thread_border_router_dns_search_list_option_store(interface_id, dns_search_list_option, search_list_option_len);
00757 #else
00758     (void)interface_id;
00759     (void)dns_search_list_option;
00760     (void)search_list_option_len;
00761     return -1;
00762 #endif
00763 }
00764 
00765 /** Network data set response callback.
00766  *
00767  * callback to inform if network data was set to leader.
00768  *
00769  * /param status status of operation 0 success, -1 failure from leader received
00770  * /param data_ptr pointer to network data TLV that leader accepted.
00771  * /param data_len length of network data.
00772  *
00773  */
00774 #ifdef HAVE_THREAD_ROUTER
00775 static void thread_tmf_client_network_data_set_cb(int8_t interface_id, int8_t status, uint8_t *data_ptr, uint16_t data_len)
00776 {
00777     protocol_interface_info_entry_t *cur;
00778     (void) status;
00779     (void) data_len;
00780     (void) data_ptr;
00781 
00782     cur = protocol_stack_interface_info_get_by_id(interface_id);
00783     if (!cur) {
00784         return;
00785     }
00786     // Save the old address
00787     cur->thread_info->localServerDataBase.registered_rloc16 = mac_helper_mac16_address_get(cur);
00788     cur->thread_info->localServerDataBase.release_old_address = false;
00789     cur->thread_info->localServerDataBase.publish_active = false;
00790 
00791     tr_debug("border router status %s, addr: %x",status?"Fail":"Ok", cur->thread_info->localServerDataBase.registered_rloc16);
00792 
00793     if (cur->thread_info->localServerDataBase.publish_pending) {
00794         cur->thread_info->localServerDataBase.publish_pending = false;
00795         thread_border_router_publish(cur->id);
00796     }
00797 }
00798 #endif
00799 
00800 int thread_border_router_publish(int8_t interface_id)
00801 {
00802 #ifdef HAVE_THREAD_ROUTER
00803     uint16_t network_data_len;
00804     uint8_t *payload_ptr;
00805     uint8_t *ptr;
00806     uint16_t rloc16;
00807     int ret_val;
00808     protocol_interface_info_entry_t *cur;
00809 
00810     tr_debug("Border router Publish Local Services");
00811     cur = protocol_stack_interface_info_get_by_id(interface_id);
00812     if (!cur) {
00813         return -1;
00814     }
00815 
00816     if (!cur->thread_info || thread_attach_ready(cur) != 0) {
00817         return -2;
00818     }
00819 
00820     if (cur->thread_info->localServerDataBase.publish_active) {
00821         cur->thread_info->localServerDataBase.publish_pending = true;
00822         tr_debug("Activate pending status for publish");
00823         return 0;
00824     }
00825 
00826     //Allocate Memory for Data
00827     network_data_len = thread_nd_own_service_list_data_size(&cur->thread_info->localServerDataBase);
00828 
00829     // Room for RLOC16  Room for Network data TLV
00830     ptr = payload_ptr = ns_dyn_mem_temporary_alloc(network_data_len + 4 + 5);
00831     if (!ptr) {
00832         return -3;
00833     }
00834     rloc16 = mac_helper_mac16_address_get(cur);
00835 
00836     ptr = thread_tmfcop_tlv_data_write_header(ptr, TMFCOP_TLV_NETWORK_DATA, network_data_len);
00837     ptr = thread_nd_own_service_list_data_write(&cur->thread_info->localServerDataBase, ptr, rloc16);
00838 
00839     tr_debug("Border router old: %x, new: %x", cur->thread_info->localServerDataBase.registered_rloc16, rloc16);
00840 
00841     if (cur->thread_info->localServerDataBase.registered_rloc16 != 0xffff &&
00842             cur->thread_info->localServerDataBase.release_old_address &&
00843             cur->thread_info->localServerDataBase.registered_rloc16 != rloc16) {
00844         // Our address has changed so we must register our network with new address and remove the old address
00845         tr_debug("Border router Address changed remove old");
00846         ptr = thread_tmfcop_tlv_data_write_uint16(ptr,TMFCOP_TLV_RLOC16,cur->thread_info->localServerDataBase.registered_rloc16);
00847     }
00848     cur->thread_info->localServerDataBase.registered_rloc16 = rloc16;
00849     ret_val = thread_management_client_network_data_register(cur->id, payload_ptr, ptr - payload_ptr, thread_tmf_client_network_data_set_cb);
00850     if (payload_ptr) {
00851         ns_dyn_mem_free(payload_ptr);
00852     }
00853     if (ret_val == 0) {
00854         cur->thread_info->localServerDataBase.publish_active = true;
00855     }
00856 
00857     thread_border_router_resubmit_timer_set(interface_id, -1);
00858 
00859     return ret_val;
00860 #else
00861     (void) interface_id;
00862     return -1;
00863 #endif
00864 }
00865 
00866 int thread_border_router_delete_all(int8_t interface_id)
00867 {
00868 #ifdef HAVE_THREAD_ROUTER
00869     protocol_interface_info_entry_t *cur;
00870     tr_debug("Border router Delete Local Service");
00871     cur = protocol_stack_interface_info_get_by_id(interface_id);
00872     if (!cur) {
00873         return -1;
00874     }
00875 
00876     if (!cur->thread_info || thread_attach_ready(cur) != 0) {
00877         return -2;
00878     }
00879 
00880     //Delete first Local List
00881     thread_network_local_data_free_and_clean(&cur->thread_info->localServerDataBase, interface_id);
00882 
00883     return 0;
00884 #else
00885     (void) interface_id;
00886     return -1;
00887 #endif
00888 }
00889 
00890 int thread_border_router_network_data_callback_register(int8_t interface_id, thread_network_data_tlv_cb* nwk_data_cb)
00891 {
00892 #ifdef HAVE_THREAD
00893     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00894     if (!cur) {
00895         return -1;
00896     }
00897 
00898     if (!cur->thread_info || thread_attach_ready(cur) != 0) {
00899         return -2;
00900     }
00901 
00902     cur->thread_info->network_data_tlv_cb = nwk_data_cb;
00903 
00904     thread_border_router_network_data_appl_callback(cur);
00905 
00906     return 0;
00907 #else
00908     (void)interface_id;
00909     (void)nwk_data_cb;
00910     return -1;
00911 #endif
00912 }
00913 
00914 int thread_border_router_prefix_tlv_find(uint8_t* network_data_tlv, uint16_t network_data_tlv_length, uint8_t** prefix_tlv, bool *stable)
00915 {
00916 #ifdef HAVE_THREAD
00917     uint16_t tlv_length;
00918     if (!network_data_tlv || !network_data_tlv_length || !prefix_tlv) {
00919         return -1;
00920     }
00921     //tr_debug("thread_tlv_lib_prefix_find() len=%d, tlv=%s", network_data_tlv_length, trace_array(network_data_tlv, network_data_tlv_length));
00922     *stable = true;
00923     tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_PREFIX|THREAD_NWK_STABLE_DATA, prefix_tlv);
00924     if (tlv_length == 0) {
00925         tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_PREFIX, prefix_tlv);
00926         *stable = false;
00927     }
00928     return tlv_length;
00929 #else
00930     (void)network_data_tlv;
00931     (void)network_data_tlv_length;
00932     (void)prefix_tlv;
00933     (void)stable;
00934     return -1;
00935 #endif
00936 }
00937 
00938 int thread_border_router_tlv_find(uint8_t* prefix_tlv, uint16_t prefix_tlv_length, uint8_t** border_router_tlv, bool *stable)
00939 {
00940 #ifdef HAVE_THREAD
00941     uint16_t tlv_length;
00942     if (!prefix_tlv || !prefix_tlv_length || !border_router_tlv) {
00943         return -1;
00944     }
00945 
00946     //tr_debug("thread_tlv_lib_border_router_find() len=%d, tlv=%s", prefix_tlv_length, trace_array(prefix_tlv, prefix_tlv_length));
00947     uint8_t prefix_length = prefix_tlv[1];
00948     uint8_t prefix_byte_len = prefixBits_to_bytes(prefix_length);
00949     prefix_tlv = prefix_tlv + 2 + prefix_byte_len; //2 = domain ID + prefix length
00950     prefix_tlv_length = prefix_tlv_length - prefix_byte_len - 2;
00951 
00952     // find stable prefix first and if not found return unstable data
00953     *stable = true;
00954     tlv_length = thread_meshcop_tlv_find_next(prefix_tlv, prefix_tlv_length, THREAD_NWK_DATA_TYPE_BORDER_ROUTER|THREAD_NWK_STABLE_DATA, border_router_tlv);
00955     if (tlv_length == 0) {
00956         tlv_length = thread_meshcop_tlv_find_next(prefix_tlv, prefix_tlv_length, THREAD_NWK_DATA_TYPE_BORDER_ROUTER, border_router_tlv);
00957         *stable = false;
00958     }
00959     return tlv_length;
00960 #else
00961     (void)prefix_tlv;
00962     (void)prefix_tlv_length;
00963     (void)border_router_tlv;
00964     (void)stable;
00965     return -1;
00966 #endif
00967 }
00968 
00969 int thread_border_router_prefix_context_id(uint8_t *prefix_tlv, uint16_t prefix_tlv_length)
00970 {
00971 #ifdef HAVE_THREAD
00972     if (!prefix_tlv || !prefix_tlv_length) {
00973         return -1;
00974     }
00975 
00976     uint16_t data_length = prefix_tlv_length;
00977 
00978     while (data_length) {
00979         uint8_t type = *prefix_tlv++;
00980         uint16_t len = *prefix_tlv++;
00981         data_length -= 2;
00982 
00983         type &= THREAD_NWK_DATA_TYPE_MASK;
00984 
00985         if (type == THREAD_NWK_DATA_TYPE_6LOWPAN_ID) {
00986             return (*prefix_tlv & 0x0f);
00987         }
00988 
00989         data_length -= len;
00990         prefix_tlv += len;
00991     }
00992 
00993     return -2;
00994 #else
00995     (void)prefix_tlv;
00996     (void)prefix_tlv_length;
00997     return -1;
00998 #endif
00999 }
01000 
01001 int thread_border_router_service_tlv_find(uint8_t* network_data_tlv, uint16_t network_data_tlv_length, uint8_t** service_tlv, bool* stable)
01002 {
01003 #ifdef HAVE_THREAD
01004     uint16_t tlv_length;
01005     if (!network_data_tlv || !network_data_tlv_length || !service_tlv) {
01006         return -1;
01007     }
01008 
01009     *stable = true;
01010     tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_SERVICE_DATA|THREAD_NWK_STABLE_DATA, service_tlv);
01011     if (tlv_length == 0) {
01012         tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_SERVICE_DATA, service_tlv);
01013         *stable = false;
01014     }
01015     return tlv_length;
01016 #else
01017     (void)network_data_tlv;
01018     (void)network_data_tlv_length;
01019     (void)service_tlv;
01020     (void)stable;
01021     return -1;
01022 #endif
01023 }
01024 
01025 int thread_border_router_server_tlv_find(uint8_t* service_tlv, uint16_t service_tlv_length, uint8_t** server_tlv, bool* stable)
01026 {
01027 #ifdef HAVE_THREAD
01028     uint16_t tlv_length;
01029     if (!service_tlv || !service_tlv_length || !server_tlv) {
01030         return -1;
01031     }
01032 
01033     uint8_t t_flag = service_tlv[0] >> 7;
01034     service_tlv += 1;
01035 
01036     if (!t_flag) {
01037         service_tlv_length -= 4;
01038         service_tlv += 4;
01039     }
01040 
01041     uint8_t service_data_len = *service_tlv;
01042     service_tlv += 1 + service_data_len;
01043     service_tlv_length = service_tlv_length - service_data_len - 2;
01044 
01045     *stable = true;
01046     tlv_length = thread_meshcop_tlv_find_next(service_tlv, service_tlv_length, THREAD_NWK_DATA_TYPE_SERVER_DATA|THREAD_NWK_STABLE_DATA, server_tlv);
01047     if (tlv_length == 0) {
01048         tlv_length = thread_meshcop_tlv_find_next(service_tlv, service_tlv_length, THREAD_NWK_DATA_TYPE_SERVER_DATA, server_tlv);
01049         *stable = false;
01050     }
01051     return tlv_length;
01052 #else
01053     (void)service_tlv;
01054     (void)service_tlv_length;
01055     (void)server_tlv;
01056     (void)stable;
01057     return -1;
01058 #endif
01059 }
01060 
01061 int thread_border_router_mdns_responder_start(int8_t interface_id, int8_t interface_id_mdns, const char *service_name)
01062 {
01063 #ifdef HAVE_THREAD_BORDER_ROUTER
01064     return thread_mdns_start(interface_id, interface_id_mdns, service_name);
01065 #else
01066     (void)interface_id;
01067     (void)interface_id_mdns;
01068     (void)service_name;
01069     return -1;
01070 #endif
01071 }
01072 
01073 int thread_border_router_mdns_responder_stop(void)
01074 {
01075 #ifdef HAVE_THREAD_BORDER_ROUTER
01076     return thread_mdns_stop();
01077 #else
01078     return -1;
01079 #endif
01080 }
01081