Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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