Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_mdns.c Source File

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