Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
thread_border_router_api.c
00001 /* 00002 * Copyright (c) 2014-2018, 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(protocol_interface_info_entry_t *cur, uint16_t child_id) 00301 { 00302 uint8_t addr16_buf[2]; 00303 00304 common_write_16_bit(child_id, addr16_buf); 00305 if (mac_neighbor_table_address_discover(mac_neighbor_info(cur), 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(cur->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, 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, 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, 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 service.P_res1 = prefix_info_ptr->P_res1; 00630 00631 return thread_local_server_list_add_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv, &service); 00632 #else 00633 (void) interface_id; 00634 (void) prefix_ptr; 00635 (void) prefix_len; 00636 (void) prefix_info_ptr; 00637 return -1; 00638 #endif 00639 } 00640 00641 int thread_border_router_prefix_delete(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len) 00642 { 00643 #ifdef HAVE_THREAD_ROUTER 00644 protocol_interface_info_entry_t *cur; 00645 thread_prefix_tlv_t prefixTlv; 00646 cur = protocol_stack_interface_info_get_by_id(interface_id); 00647 if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) { 00648 return -1; 00649 } 00650 00651 if (!prefix_ptr) { 00652 return -2; 00653 } 00654 prefixTlv.domainId = 0; 00655 prefixTlv.Prefix = prefix_ptr; 00656 prefixTlv.PrefixLen = prefix_len; 00657 00658 return thread_local_server_list_del_on_mesh_server(&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 int thread_border_router_route_add(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len, bool stable, int8_t prf) 00668 { 00669 #ifdef HAVE_THREAD_ROUTER 00670 thread_prefix_tlv_t prefixTlv; 00671 thread_border_router_tlv_entry_t route; 00672 protocol_interface_info_entry_t *cur; 00673 00674 cur = protocol_stack_interface_info_get_by_id(interface_id); 00675 if (!cur) { 00676 return -1; 00677 } 00678 00679 if (!cur->thread_info || thread_attach_ready(cur) != 0) { 00680 return -2; 00681 } 00682 prefixTlv.domainId = 0; 00683 prefixTlv.Prefix = prefix_ptr; 00684 prefixTlv.PrefixLen = prefix_len; 00685 00686 memset(&route, 0, sizeof(thread_border_router_tlv_entry_t)); 00687 route.Prf = prf; 00688 route.stableData = stable; 00689 00690 return thread_local_server_add_route(&cur->thread_info->localServerDataBase, &prefixTlv, &route); 00691 #else 00692 (void) interface_id; 00693 (void) prefix_ptr; 00694 (void) prefix_len; 00695 (void) stable; 00696 (void) prf; 00697 return -1; 00698 #endif 00699 } 00700 00701 int thread_border_router_route_delete(int8_t interface_id, uint8_t *prefix_ptr, uint8_t prefix_len) 00702 { 00703 #ifdef HAVE_THREAD_ROUTER 00704 thread_prefix_tlv_t prefixTlv; 00705 protocol_interface_info_entry_t *cur; 00706 00707 cur = protocol_stack_interface_info_get_by_id(interface_id); 00708 if (!cur) { 00709 return -1; 00710 } 00711 00712 if (!cur->thread_info || thread_attach_ready(cur) != 0) { 00713 return -1; 00714 } 00715 00716 prefixTlv.domainId = 0; 00717 prefixTlv.Prefix = prefix_ptr; 00718 prefixTlv.PrefixLen = prefix_len; 00719 00720 return thread_local_server_del_route(&cur->thread_info->localServerDataBase, &prefixTlv); 00721 #else 00722 (void) interface_id; 00723 (void) prefix_ptr; 00724 (void) prefix_len; 00725 return -1; 00726 #endif 00727 00728 } 00729 00730 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) 00731 { 00732 #ifdef HAVE_THREAD_ROUTER 00733 protocol_interface_info_entry_t *cur; 00734 cur = protocol_stack_interface_info_get_by_id(interface_id); 00735 00736 if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) { 00737 return -1; 00738 } 00739 00740 if (!service_data || !service_len) { 00741 return -2; 00742 } 00743 00744 thread_network_data_service_entry_t service = { 00745 .T = false, 00746 .S_id = sid, 00747 .S_enterprise_number = enterprise_number, 00748 .S_service_data = service_data, 00749 .S_service_data_length = service_len, 00750 .S_server_data = server_data, 00751 .S_server_data_length = server_data_len, 00752 .S_stable = stable, 00753 }; 00754 00755 if (enterprise_number == THREAD_ENTERPRISE_NUMBER) { 00756 service.T = true; 00757 } 00758 00759 return thread_local_service_list_add(&cur->thread_info->localServerDataBase, &service); 00760 #else 00761 (void)interface_id; 00762 (void)service_data; 00763 (void)service_len; 00764 (void)sid; 00765 (void)enterprise_number; 00766 (void)server_data; 00767 (void)server_data_len; 00768 (void)stable; 00769 return -1; 00770 #endif 00771 } 00772 00773 int thread_border_router_service_delete(int8_t interface_id, uint8_t *service_data, uint8_t service_len, uint32_t enterprise_number) 00774 { 00775 #ifdef HAVE_THREAD_ROUTER 00776 protocol_interface_info_entry_t *cur; 00777 cur = protocol_stack_interface_info_get_by_id(interface_id); 00778 00779 if (!cur || !cur->thread_info || thread_attach_ready(cur) != 0) { 00780 return -1; 00781 } 00782 00783 if (!service_data || !service_len) { 00784 return -2; 00785 } 00786 00787 thread_network_data_service_entry_t service = { 00788 .S_enterprise_number = enterprise_number, 00789 .S_service_data = service_data, 00790 .S_service_data_length = service_len, 00791 }; 00792 00793 return thread_local_service_list_del(&cur->thread_info->localServerDataBase, &service); 00794 #else 00795 (void) interface_id; 00796 (void) service_data; 00797 (void) service_len; 00798 (void) enterprise_number; 00799 return -1; 00800 #endif 00801 } 00802 00803 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) 00804 { 00805 #ifdef HAVE_THREAD_BORDER_ROUTER 00806 return thread_border_router_recursive_dns_server_option_store(interface_id, recursive_dns_server_option, recursive_dns_server_option_len); 00807 #else 00808 (void)interface_id; 00809 (void)recursive_dns_server_option; 00810 (void)recursive_dns_server_option_len; 00811 return -1; 00812 #endif 00813 } 00814 00815 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) 00816 { 00817 #ifdef HAVE_THREAD_BORDER_ROUTER 00818 return thread_border_router_dns_search_list_option_store(interface_id, dns_search_list_option, search_list_option_len); 00819 #else 00820 (void)interface_id; 00821 (void)dns_search_list_option; 00822 (void)search_list_option_len; 00823 return -1; 00824 #endif 00825 } 00826 00827 /** Network data set response callback. 00828 * 00829 * callback to inform if network data was set to leader. 00830 * 00831 * /param status status of operation 0 success, -1 failure from leader received 00832 * /param data_ptr pointer to network data TLV that leader accepted. 00833 * /param data_len length of network data. 00834 * 00835 */ 00836 #ifdef HAVE_THREAD_ROUTER 00837 static void thread_tmf_client_network_data_set_cb(int8_t interface_id, int8_t status, uint8_t *data_ptr, uint16_t data_len) 00838 { 00839 protocol_interface_info_entry_t *cur; 00840 (void) status; 00841 (void) data_len; 00842 (void) data_ptr; 00843 00844 cur = protocol_stack_interface_info_get_by_id(interface_id); 00845 if (!cur) { 00846 return; 00847 } 00848 00849 cur->thread_info->localServerDataBase.publish_active = false; 00850 00851 tr_debug("BR a/sd response status: %s, addr: %x",status?"Fail":"OK", cur->thread_info->localServerDataBase.registered_rloc16); 00852 00853 if (cur->thread_info->localServerDataBase.publish_pending) { 00854 cur->thread_info->localServerDataBase.publish_pending = false; 00855 thread_border_router_publish(cur->id); 00856 } 00857 00858 // always update RLOC to new one. If COAP response fails then resubmit timer will trigger new a/sd 00859 cur->thread_info->localServerDataBase.registered_rloc16 = mac_helper_mac16_address_get(cur); 00860 cur->thread_info->localServerDataBase.release_old_address = false; 00861 } 00862 #endif 00863 00864 int thread_border_router_publish(int8_t interface_id) 00865 { 00866 #ifdef HAVE_THREAD_ROUTER 00867 uint16_t network_data_len; 00868 uint8_t *payload_ptr; 00869 uint8_t *ptr; 00870 uint16_t rloc16; 00871 int ret_val; 00872 protocol_interface_info_entry_t *cur; 00873 00874 tr_debug("Border router Publish Local Services"); 00875 cur = protocol_stack_interface_info_get_by_id(interface_id); 00876 if (!cur) { 00877 return -1; 00878 } 00879 00880 if (!cur->thread_info || thread_attach_ready(cur) != 0) { 00881 return -2; 00882 } 00883 00884 rloc16 = mac_helper_mac16_address_get(cur); 00885 tr_debug("Border router old: %x, new: %x", cur->thread_info->localServerDataBase.registered_rloc16, rloc16); 00886 00887 if (cur->thread_info->localServerDataBase.publish_active) { 00888 if (rloc16 != cur->thread_info->localServerDataBase.registered_rloc16) { 00889 /* 00890 * Device short address has changed, cancel previous a/sd and a/as requests 00891 * and start resubmit timer 00892 * */ 00893 tr_debug("address changed, kill pending reuqests"); 00894 thread_management_client_pending_coap_request_kill(cur->id); 00895 thread_border_router_resubmit_timer_set(interface_id, 5); 00896 return 0; 00897 } else { 00898 cur->thread_info->localServerDataBase.publish_pending = true; 00899 tr_debug("Activate pending status for publish"); 00900 return 0; 00901 } 00902 } 00903 00904 //Allocate Memory for Data 00905 network_data_len = thread_nd_own_service_list_data_size(&cur->thread_info->localServerDataBase); 00906 00907 // Room for RLOC16 Room for Network data TLV 00908 ptr = payload_ptr = ns_dyn_mem_temporary_alloc(network_data_len + 4 + 5); 00909 if (!ptr) { 00910 return -3; 00911 } 00912 00913 ptr = thread_tmfcop_tlv_data_write_header(ptr, TMFCOP_TLV_NETWORK_DATA, network_data_len); 00914 ptr = thread_nd_own_service_list_data_write(&cur->thread_info->localServerDataBase, ptr, rloc16); 00915 00916 if (cur->thread_info->localServerDataBase.registered_rloc16 != 0xffff && 00917 cur->thread_info->localServerDataBase.release_old_address && 00918 cur->thread_info->localServerDataBase.registered_rloc16 != rloc16) { 00919 // Our address has changed so we must register our network with new address and remove the old address 00920 tr_debug("BR address changed - remove old %x", cur->thread_info->localServerDataBase.registered_rloc16); 00921 ptr = thread_tmfcop_tlv_data_write_uint16(ptr,TMFCOP_TLV_RLOC16,cur->thread_info->localServerDataBase.registered_rloc16); 00922 } 00923 00924 cur->thread_info->localServerDataBase.registered_rloc16 = rloc16; 00925 ret_val = thread_management_client_network_data_register(cur->id, payload_ptr, ptr - payload_ptr, thread_tmf_client_network_data_set_cb); 00926 if (payload_ptr) { 00927 ns_dyn_mem_free(payload_ptr); 00928 } 00929 if (ret_val == 0) { 00930 cur->thread_info->localServerDataBase.publish_active = true; 00931 } 00932 00933 thread_border_router_resubmit_timer_set(interface_id, -1); 00934 00935 return ret_val; 00936 #else 00937 (void) interface_id; 00938 return -1; 00939 #endif 00940 } 00941 00942 int thread_border_router_delete_all(int8_t interface_id) 00943 { 00944 #ifdef HAVE_THREAD_ROUTER 00945 protocol_interface_info_entry_t *cur; 00946 tr_debug("Border router Delete Local Service"); 00947 cur = protocol_stack_interface_info_get_by_id(interface_id); 00948 if (!cur) { 00949 return -1; 00950 } 00951 00952 if (!cur->thread_info || thread_attach_ready(cur) != 0) { 00953 return -2; 00954 } 00955 00956 //Delete first Local List 00957 thread_network_local_data_free_and_clean(&cur->thread_info->localServerDataBase, interface_id); 00958 00959 return 0; 00960 #else 00961 (void) interface_id; 00962 return -1; 00963 #endif 00964 } 00965 00966 int thread_border_router_network_data_callback_register(int8_t interface_id, thread_network_data_tlv_cb* nwk_data_cb) 00967 { 00968 #ifdef HAVE_THREAD 00969 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00970 if (!cur) { 00971 return -1; 00972 } 00973 00974 if (!cur->thread_info || thread_attach_ready(cur) != 0) { 00975 return -2; 00976 } 00977 00978 cur->thread_info->network_data_tlv_cb = nwk_data_cb; 00979 00980 thread_border_router_network_data_appl_callback(cur); 00981 00982 return 0; 00983 #else 00984 (void)interface_id; 00985 (void)nwk_data_cb; 00986 return -1; 00987 #endif 00988 } 00989 00990 int thread_border_router_prefix_tlv_find(uint8_t* network_data_tlv, uint16_t network_data_tlv_length, uint8_t** prefix_tlv, bool *stable) 00991 { 00992 #ifdef HAVE_THREAD 00993 uint16_t tlv_length; 00994 if (!network_data_tlv || !network_data_tlv_length || !prefix_tlv) { 00995 return -1; 00996 } 00997 //tr_debug("thread_tlv_lib_prefix_find() len=%d, tlv=%s", network_data_tlv_length, trace_array(network_data_tlv, network_data_tlv_length)); 00998 *stable = true; 00999 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); 01000 if (tlv_length == 0) { 01001 tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_PREFIX, prefix_tlv); 01002 *stable = false; 01003 } 01004 return tlv_length; 01005 #else 01006 (void)network_data_tlv; 01007 (void)network_data_tlv_length; 01008 (void)prefix_tlv; 01009 (void)stable; 01010 return -1; 01011 #endif 01012 } 01013 01014 int thread_border_router_tlv_find(uint8_t* prefix_tlv, uint16_t prefix_tlv_length, uint8_t** border_router_tlv, bool *stable) 01015 { 01016 #ifdef HAVE_THREAD 01017 uint16_t tlv_length; 01018 if (!prefix_tlv || !prefix_tlv_length || !border_router_tlv) { 01019 return -1; 01020 } 01021 01022 //tr_debug("thread_tlv_lib_border_router_find() len=%d, tlv=%s", prefix_tlv_length, trace_array(prefix_tlv, prefix_tlv_length)); 01023 uint8_t prefix_length = prefix_tlv[1]; 01024 uint8_t prefix_byte_len = prefixBits_to_bytes(prefix_length); 01025 prefix_tlv = prefix_tlv + 2 + prefix_byte_len; //2 = domain ID + prefix length 01026 prefix_tlv_length = prefix_tlv_length - prefix_byte_len - 2; 01027 01028 // find stable prefix first and if not found return unstable data 01029 *stable = true; 01030 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); 01031 if (tlv_length == 0) { 01032 tlv_length = thread_meshcop_tlv_find_next(prefix_tlv, prefix_tlv_length, THREAD_NWK_DATA_TYPE_BORDER_ROUTER, border_router_tlv); 01033 *stable = false; 01034 } 01035 return tlv_length; 01036 #else 01037 (void)prefix_tlv; 01038 (void)prefix_tlv_length; 01039 (void)border_router_tlv; 01040 (void)stable; 01041 return -1; 01042 #endif 01043 } 01044 01045 int thread_border_router_prefix_context_id(uint8_t *prefix_tlv, uint16_t prefix_tlv_length) 01046 { 01047 #ifdef HAVE_THREAD 01048 if (!prefix_tlv || !prefix_tlv_length) { 01049 return -1; 01050 } 01051 01052 uint16_t data_length = prefix_tlv_length; 01053 01054 while (data_length) { 01055 uint8_t type = *prefix_tlv++; 01056 uint16_t len = *prefix_tlv++; 01057 data_length -= 2; 01058 01059 type &= THREAD_NWK_DATA_TYPE_MASK; 01060 01061 if (type == THREAD_NWK_DATA_TYPE_6LOWPAN_ID) { 01062 return (*prefix_tlv & 0x0f); 01063 } 01064 01065 data_length -= len; 01066 prefix_tlv += len; 01067 } 01068 01069 return -2; 01070 #else 01071 (void)prefix_tlv; 01072 (void)prefix_tlv_length; 01073 return -1; 01074 #endif 01075 } 01076 01077 int thread_border_router_service_tlv_find(uint8_t* network_data_tlv, uint16_t network_data_tlv_length, uint8_t** service_tlv, bool* stable) 01078 { 01079 #ifdef HAVE_THREAD 01080 uint16_t tlv_length; 01081 if (!network_data_tlv || !network_data_tlv_length || !service_tlv) { 01082 return -1; 01083 } 01084 01085 *stable = true; 01086 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); 01087 if (tlv_length == 0) { 01088 tlv_length = thread_meshcop_tlv_find_next(network_data_tlv, network_data_tlv_length, THREAD_NWK_DATA_TYPE_SERVICE_DATA, service_tlv); 01089 *stable = false; 01090 } 01091 return tlv_length; 01092 #else 01093 (void)network_data_tlv; 01094 (void)network_data_tlv_length; 01095 (void)service_tlv; 01096 (void)stable; 01097 return -1; 01098 #endif 01099 } 01100 01101 int thread_border_router_server_tlv_find(uint8_t* service_tlv, uint16_t service_tlv_length, uint8_t** server_tlv, bool* stable) 01102 { 01103 #ifdef HAVE_THREAD 01104 uint16_t tlv_length; 01105 if (!service_tlv || !service_tlv_length || !server_tlv) { 01106 return -1; 01107 } 01108 01109 uint8_t t_flag = service_tlv[0] >> 7; 01110 service_tlv += 1; 01111 01112 if (!t_flag) { 01113 service_tlv_length -= 4; 01114 service_tlv += 4; 01115 } 01116 01117 uint8_t service_data_len = *service_tlv; 01118 service_tlv += 1 + service_data_len; 01119 service_tlv_length = service_tlv_length - service_data_len - 2; 01120 01121 *stable = true; 01122 tlv_length = thread_meshcop_tlv_find_next(service_tlv, service_tlv_length, THREAD_NWK_DATA_TYPE_SERVER_DATA|THREAD_NWK_STABLE_DATA, server_tlv); 01123 if (tlv_length == 0) { 01124 tlv_length = thread_meshcop_tlv_find_next(service_tlv, service_tlv_length, THREAD_NWK_DATA_TYPE_SERVER_DATA, server_tlv); 01125 *stable = false; 01126 } 01127 return tlv_length; 01128 #else 01129 (void)service_tlv; 01130 (void)service_tlv_length; 01131 (void)server_tlv; 01132 (void)stable; 01133 return -1; 01134 #endif 01135 } 01136 01137 int thread_border_router_mdns_responder_start(int8_t interface_id, int8_t interface_id_mdns, const char *service_name) 01138 { 01139 #ifdef HAVE_THREAD_BORDER_ROUTER 01140 return thread_mdns_start(interface_id, interface_id_mdns, service_name); 01141 #else 01142 (void)interface_id; 01143 (void)interface_id_mdns; 01144 (void)service_name; 01145 return -1; 01146 #endif 01147 } 01148 01149 int thread_border_router_mdns_responder_stop(void) 01150 { 01151 #ifdef HAVE_THREAD_BORDER_ROUTER 01152 return thread_mdns_stop(); 01153 #else 01154 return -1; 01155 #endif 01156 } 01157
Generated on Tue Aug 9 2022 00:37:22 by
1.7.2