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