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_mdns.c
00001 /* 00002 * Copyright (c) 2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: BSD-3-Clause 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holder nor the 00014 * names of its contributors may be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "nsconfig.h" 00031 00032 #ifdef HAVE_THREAD_BORDER_ROUTER 00033 00034 #include <string.h> 00035 #include "ns_types.h" 00036 #include <nsdynmemLIB.h> 00037 #include "ns_trace.h" 00038 #include "common_functions.h" 00039 #include "6LoWPAN/Thread/thread_config.h" 00040 #include "6LoWPAN/Thread/thread_common.h" 00041 #include "6LoWPAN/Thread/thread_joiner_application.h" 00042 #include "ns_sha256.h" 00043 #include "ns_mdns_api.h" 00044 #include "Service_Libs/utils/ns_crc.h" 00045 00046 #define TRACE_GROUP "tmDNS" 00047 00048 /* 00049 * mDNS data structure 00050 * 00051 */ 00052 typedef struct { 00053 ns_mdns_t server_instance; 00054 ns_mdns_service_t service_instance; 00055 ns_mdns_service_param_t service_params; 00056 uint8_t *txt_record_buffer; 00057 uint16_t txt_value_crc; 00058 uint8_t txt_record_buffer_len; 00059 int8_t interface_id; 00060 int8_t interface_id_mdns; 00061 } thread_mdns_t; 00062 00063 static thread_mdns_t thread_mdns = { 00064 .server_instance = NULL, 00065 .service_instance = NULL, 00066 .txt_record_buffer = NULL, 00067 .txt_value_crc = 0, 00068 .txt_record_buffer_len = 0, 00069 .interface_id = -1, 00070 .interface_id_mdns = -1, 00071 }; 00072 00073 static thread_mdns_t *thread_mdns_ptr = &thread_mdns; 00074 00075 /* mDNS constants */ 00076 #define THREAD_MDNS_TIME_TO_LIVE 4500 /* Time to Live in seconds */ 00077 #define THREAD_MDNS_TIME_TO_LIVE_HOP_COUNT 120 /* Time to Live in hops */ 00078 00079 /* mDNS TXT record State Bitmap */ 00080 #define THREAD_MDNS_TXT_SB_CONNECTION_MODE_BM 0x07 /* Mask 0000 0111 */ 00081 #define THREAD_MDNS_TXT_SB_INTERFACE_STATUS_BM 0x18 /* Mask 0001 1000 */ 00082 #define THREAD_MDNS_TXT_SB_AVAILABILITY_HIGH 0x20 /* Value 0010 0000 */ 00083 00084 static uint8_t *thread_mdns_txt_record_sb_get(int interface_id, uint8_t *buf, uint32_t *state_bm) 00085 { 00086 uint32_t state_bitmap = 0; 00087 uint8_t *ptr = buf; 00088 00089 const uint8_t sb_string[] = {7, 's', 'b', '='}; 00090 link_configuration_s *link_configuration = thread_management_configuration_get(interface_id); 00091 00092 if (link_configuration) { 00093 if (link_configuration->securityPolicy & SECURITY_POLICY_EXTERNAL_COMMISSIONER_ALLOWED) { 00094 /* connection mode: 00095 * 1: DTLS connection to Border Agent allowed with a user chosen network Commissioner Credential and shared PSKc for the active Thread Network Partition 00096 * 2, DTLS connection to Border Agent allowed using the Border Agent Device Passphrase (PSKd) as the Commissioner Credential 00097 * */ 00098 state_bitmap = 0x01; 00099 } 00100 00101 /* Thread Interface Status 00102 * 2, Thread interface is initialized with a set of valid operational parameters and is actively part of a Thread Network Partition 00103 * */ 00104 state_bitmap |= 0x02<<3; 00105 00106 /* Availability 00107 * 1: High availability – The Border Agent device and its Thread interface are part of stable, always-on network infrastructure 00108 * */ 00109 state_bitmap |= THREAD_MDNS_TXT_SB_AVAILABILITY_HIGH; 00110 } else { 00111 /* connection mode: 00112 * -bits 0-2: 0=DTLS connection to Border Agent is not allowed 00113 * 00114 * Thread Interface Status 00115 * -bits 3-4: 0=Thread interface is not active and is not initialized with a set of valid operational network parameters 00116 * 00117 * Availability 00118 * -bits 5-6: 0= Infrequent availability - Thread interface may become inactive when the Border Agent device is not in use 00119 * */ 00120 state_bitmap = 0x00; 00121 } 00122 00123 *state_bm = state_bitmap; 00124 00125 memcpy(ptr, sb_string, sizeof(sb_string)); 00126 ptr += sizeof(sb_string); 00127 00128 ptr = common_write_32_bit(state_bitmap, ptr); 00129 00130 return ptr; 00131 } 00132 00133 static uint8_t *thread_mdns_txt_record_nn_key_fill(int8_t interface_id, uint8_t *buf, uint32_t state_bitmap) 00134 { 00135 uint8_t *ptr = buf; 00136 int i; 00137 uint8_t length; 00138 const char nn_string[4] = "nn="; 00139 00140 if (! (state_bitmap & THREAD_MDNS_TXT_SB_CONNECTION_MODE_BM)) { 00141 // if connection mode is not allowed, elide nn-key 00142 return ptr; 00143 } 00144 00145 ptr++; /* make room for length */ 00146 length = sizeof(nn_string) - 1; 00147 memcpy(ptr, nn_string, length); 00148 ptr += length; 00149 00150 if (state_bitmap & THREAD_MDNS_TXT_SB_AVAILABILITY_HIGH) { 00151 link_configuration_s *link_configuration = thread_management_configuration_get(interface_id); 00152 if (!link_configuration) { 00153 return ptr; 00154 } 00155 00156 for (i = 0; i < 16 && link_configuration->name[i] != 0; i++) { 00157 *ptr++ = link_configuration->name[i]; 00158 } 00159 00160 length += i; /* update length */ 00161 } else { 00162 // Thread interface seldomly available, use border agent product or model name 00163 memcpy(ptr, THREAD_VENDOR_MODEL, sizeof(THREAD_VENDOR_MODEL) - 1); 00164 ptr += sizeof(THREAD_VENDOR_MODEL) - 1; 00165 length += sizeof(THREAD_VENDOR_MODEL) - 1; 00166 } 00167 00168 *buf = length; // update length 00169 00170 return ptr; 00171 } 00172 00173 static uint8_t *thread_mdns_txt_record_xp_key_fill(int8_t interface_id, uint8_t *buf, uint32_t state_bitmap) 00174 { 00175 uint8_t *ptr = buf; 00176 int length; 00177 const uint8_t xp_string[4] = { 11, 'x', 'p', '=' }; 00178 00179 if (! (state_bitmap & THREAD_MDNS_TXT_SB_CONNECTION_MODE_BM)) { 00180 // if connection mode not allowed, skip xb-key 00181 return ptr; 00182 } 00183 00184 length = sizeof xp_string; 00185 memcpy(ptr, xp_string, length); 00186 ptr += length; 00187 00188 if(state_bitmap & THREAD_MDNS_TXT_SB_INTERFACE_STATUS_BM) { 00189 link_configuration_s *link_configuration = thread_management_configuration_get(interface_id); 00190 if (!link_configuration) { 00191 tr_error("Failed to read link configuration"); 00192 return ptr; 00193 } 00194 memcpy(ptr, link_configuration->extented_pan_id, 8); 00195 } else { 00196 device_configuration_s *device_configuration = thread_management_device_configuration_get(interface_id); 00197 if (!device_configuration) { 00198 tr_error("Failed to read device configuration"); 00199 return ptr; 00200 } 00201 ns_sha256_nbits(device_configuration->eui64, 8, ptr, 64); 00202 } 00203 00204 ptr += 8; 00205 00206 return ptr; 00207 } 00208 00209 static uint8_t *thread_mdns_txt_record_fill(int8_t interface_id, uint8_t *buf) 00210 { 00211 static const char mDNS_thread_version[9] = "tv=1.1.1"; 00212 uint8_t *ptr = buf; 00213 uint32_t state_bitmap; 00214 00215 /* rv */ 00216 *ptr++ = 0x04; /* rv length */ 00217 memcpy(ptr, "rv=1", 4); 00218 ptr += 4; 00219 00220 /* tv */ 00221 *ptr++ = sizeof(mDNS_thread_version) - 1; /* tv length */ 00222 memcpy(ptr, mDNS_thread_version, sizeof(mDNS_thread_version)- 1); 00223 ptr += sizeof(mDNS_thread_version) - 1; 00224 00225 /* state bitmap */ 00226 ptr = thread_mdns_txt_record_sb_get(interface_id, ptr, &state_bitmap); 00227 00228 tr_debug("state_bitmap %"PRIx32, state_bitmap); 00229 00230 /* nn-key */ 00231 ptr = thread_mdns_txt_record_nn_key_fill(interface_id, ptr, state_bitmap); 00232 00233 /* xp-key */ 00234 ptr = thread_mdns_txt_record_xp_key_fill(interface_id, ptr, state_bitmap); 00235 00236 *ptr++ = 0; 00237 00238 return ptr; 00239 } 00240 00241 /* callback from mDNS to fill TXT record */ 00242 static const uint8_t *thread_mdns_txt_record_callback(void) 00243 { 00244 uint8_t buffer[200]; /* 200 bytes enough space for TXT record */ 00245 uint8_t *ptr; 00246 size_t new_record_length; 00247 00248 ptr = thread_mdns_txt_record_fill(thread_mdns_ptr->interface_id, buffer); 00249 00250 new_record_length = ptr - buffer; 00251 00252 if (thread_mdns_ptr->txt_record_buffer_len < new_record_length) { 00253 // not enough space in current buffer 00254 ns_dyn_mem_free(thread_mdns_ptr->txt_record_buffer); 00255 thread_mdns_ptr->txt_record_buffer = NULL; 00256 } 00257 00258 if (thread_mdns_ptr->txt_record_buffer == NULL) { 00259 thread_mdns_ptr->txt_record_buffer = ns_dyn_mem_alloc(new_record_length); 00260 } 00261 00262 if (!thread_mdns_ptr->txt_record_buffer) { 00263 tr_error("mDNS record not allocated"); 00264 return (uint8_t*)'\0'; 00265 } 00266 00267 memcpy(thread_mdns_ptr->txt_record_buffer, buffer, new_record_length); 00268 thread_mdns_ptr->txt_record_buffer_len = new_record_length; 00269 00270 tr_debug("mDNS TXT record created, %d bytes", thread_mdns_ptr->txt_record_buffer_len); 00271 00272 return thread_mdns_ptr->txt_record_buffer; 00273 } 00274 00275 static uint16_t thread_mdns_txt_values_crc_get(void) 00276 { 00277 link_configuration_s *link_configuration; 00278 uint16_t txt_values_crc = 0; 00279 00280 if (!thread_mdns_ptr->server_instance) { 00281 // mdns not active 00282 return txt_values_crc; 00283 } 00284 00285 link_configuration = thread_joiner_application_get_config(thread_mdns_ptr->interface_id); 00286 if (link_configuration) { 00287 // calculate CRC for values in mDNS TXT record that may change 00288 txt_values_crc = crc16_ccitt(link_configuration->name, 16); 00289 txt_values_crc |= crc16_ccitt(link_configuration->extented_pan_id, 8); 00290 txt_values_crc |= crc16_ccitt(&link_configuration->securityPolicy, 1); 00291 } 00292 00293 return txt_values_crc; 00294 } 00295 00296 int thread_mdns_stop(void) 00297 { 00298 if (thread_mdns_ptr->server_instance == NULL) { 00299 return -1; 00300 } 00301 00302 ns_mdns_server_stop(thread_mdns_ptr->server_instance); 00303 00304 thread_mdns_ptr->server_instance = NULL; 00305 ns_dyn_mem_free(thread_mdns_ptr->txt_record_buffer); 00306 thread_mdns_ptr->txt_record_buffer = NULL; 00307 thread_mdns_ptr->txt_record_buffer_len = 0; 00308 00309 return 0; 00310 } 00311 00312 int thread_mdns_start(int8_t interface_id, int8_t interface_id_mdns, const char *service_name) 00313 { 00314 static const char *mDNS_service_type = "_meshcop._udp"; 00315 00316 if (thread_mdns_ptr->server_instance != NULL) { 00317 return -1; 00318 } 00319 00320 thread_mdns_ptr->server_instance = ns_mdns_server_start(service_name, THREAD_MDNS_TIME_TO_LIVE, THREAD_MDNS_TIME_TO_LIVE_HOP_COUNT, interface_id_mdns); 00321 if (thread_mdns_ptr->server_instance == NULL) { 00322 tr_error("mDNS server initialization failed"); 00323 return -2; 00324 } 00325 00326 thread_mdns_ptr->interface_id = interface_id; 00327 thread_mdns_ptr->interface_id_mdns = interface_id_mdns; 00328 thread_mdns_ptr->service_params.service_type = mDNS_service_type; 00329 thread_mdns_ptr->service_params.service_port = THREAD_COMMISSIONING_PORT; 00330 thread_mdns_ptr->service_params.service_get_txt = thread_mdns_txt_record_callback; 00331 thread_mdns_ptr->service_instance = ns_mdns_service_register(thread_mdns_ptr->server_instance, &thread_mdns_ptr->service_params); 00332 thread_mdns_ptr->txt_value_crc = thread_mdns_txt_values_crc_get(); 00333 00334 if (thread_mdns_ptr->service_instance == NULL) { 00335 tr_error("mDNS service init failed"); 00336 thread_mdns_stop(); 00337 return -3; 00338 } 00339 00340 return 0; 00341 } 00342 00343 #endif //HAVE_THREAD_BORDER_ROUTER 00344 00345 void thread_mdns_network_data_update_notify(void) 00346 { 00347 #ifdef HAVE_THREAD_BORDER_ROUTER 00348 uint16_t txt_value_crc; 00349 txt_value_crc = thread_mdns_txt_values_crc_get(); 00350 if (txt_value_crc != thread_mdns_ptr->txt_value_crc) { 00351 // Values for TXT-record have changed, send mDNS announcement 00352 thread_mdns_ptr->txt_value_crc = txt_value_crc; 00353 ns_mdns_announcement_send(thread_mdns_ptr->server_instance); 00354 } 00355 #endif //HAVE_THREAD_BORDER_ROUTER 00356 } 00357
Generated on Tue Jul 12 2022 14:24:54 by
