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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
thread_joiner_application.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 00030 00031 #include "nsconfig.h" 00032 #ifdef HAVE_THREAD 00033 #include <ns_types.h> 00034 #include "ns_list.h" 00035 #include "ns_trace.h" 00036 #include "nsdynmemLIB.h" 00037 #include "ns_nvm_helper.h" 00038 #include "randLIB.h" 00039 #include "common_functions.h" 00040 #include "thread_tmfcop_lib.h" 00041 #include "ns_sha256.h" 00042 00043 #include "NWK_INTERFACE/Include/protocol.h" 00044 #include "Service_Libs/blacklist/blacklist.h" 00045 00046 #include "coap_service_api.h" 00047 00048 #include "eventOS_event_timer.h" 00049 #include "thread_discovery.h" 00050 #include "thread_beacon.h" 00051 #include "thread_config.h" 00052 #include "thread_meshcop_lib.h" 00053 #include "thread_commissioning_if.h" 00054 #include "thread_management_if.h" 00055 #include "thread_common.h" 00056 #include "thread_bootstrap.h" 00057 #include "thread_router_bootstrap.h" 00058 #include "thread_network_synch.h" 00059 #include "thread_network_data_lib.h" 00060 #include "thread_joiner_application.h" 00061 #include "6LoWPAN/Thread/thread_ccm.h" 00062 #include "mac_api.h" 00063 #include "6LoWPAN/MAC/mac_helper.h" 00064 #include "thread_nvm_store.h" 00065 #include "thread_management_internal.h" 00066 00067 #define TRACE_GROUP TRACE_GROUP_THREAD_JOINER_APPLICATION 00068 00069 /* List of active/pending configuration dataset TLVs*/ 00070 const uint8_t mle_pending_configuration_dataset_tlvs[] = { 00071 MESHCOP_TLV_ACTIVE_TIME_STAMP, 00072 MESHCOP_TLV_NETWORK_NAME, 00073 MESHCOP_TLV_PANID, 00074 MESHCOP_TLV_CHANNEL, 00075 MESHCOP_TLV_CHANNEL_MASK, 00076 MESHCOP_TLV_XPANID, 00077 MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 00078 MESHCOP_TLV_NETWORK_MASTER_KEY, 00079 MESHCOP_TLV_PSKC, 00080 MESHCOP_TLV_SECURITY_POLICY 00081 }; 00082 00083 const uint8_t pending_configuration_dataset_tlvs[] = { 00084 MESHCOP_TLV_PENDING_TIMESTAMP, 00085 MESHCOP_TLV_ACTIVE_TIME_STAMP, 00086 MESHCOP_TLV_NETWORK_NAME, 00087 MESHCOP_TLV_PANID, 00088 MESHCOP_TLV_CHANNEL, 00089 MESHCOP_TLV_CHANNEL_MASK, 00090 MESHCOP_TLV_XPANID, 00091 MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 00092 MESHCOP_TLV_NETWORK_MASTER_KEY, 00093 MESHCOP_TLV_PSKC, 00094 MESHCOP_TLV_SECURITY_POLICY 00095 }; 00096 00097 const uint8_t active_configuration_dataset_tlvs[] = { 00098 MESHCOP_TLV_ACTIVE_TIME_STAMP, 00099 MESHCOP_TLV_NETWORK_NAME, 00100 MESHCOP_TLV_PANID, 00101 MESHCOP_TLV_CHANNEL, 00102 MESHCOP_TLV_CHANNEL_MASK, 00103 MESHCOP_TLV_XPANID, 00104 MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 00105 MESHCOP_TLV_NETWORK_MASTER_KEY, 00106 MESHCOP_TLV_PSKC, 00107 MESHCOP_TLV_SECURITY_POLICY 00108 }; 00109 00110 const uint8_t mle_active_configuration_dataset_tlvs[] = { 00111 MESHCOP_TLV_NETWORK_NAME, 00112 MESHCOP_TLV_PANID, 00113 MESHCOP_TLV_CHANNEL, 00114 MESHCOP_TLV_CHANNEL_MASK, 00115 MESHCOP_TLV_XPANID, 00116 MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 00117 MESHCOP_TLV_NETWORK_MASTER_KEY, 00118 MESHCOP_TLV_PSKC, 00119 MESHCOP_TLV_SECURITY_POLICY 00120 }; 00121 00122 const uint8_t entrust_dataset_tlvs[] = { 00123 MESHCOP_TLV_ACTIVE_TIME_STAMP, 00124 MESHCOP_TLV_NETWORK_NAME, 00125 MESHCOP_TLV_CHANNEL_MASK,// Missing specification 00126 MESHCOP_TLV_XPANID, 00127 MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 00128 MESHCOP_TLV_NETWORK_MASTER_KEY, 00129 MESHCOP_TLV_PSKC, 00130 MESHCOP_TLV_SECURITY_POLICY, 00131 MESHCOP_TLV_NETWORK_KEY_SEQUENCE 00132 }; 00133 00134 const uint8_t meshcop_pending_set_ignore[] = { 00135 MESHCOP_TLV_BORDER_ROUTER_LOCATOR, 00136 MESHCOP_TLV_COMMISSIONER_SESSION_ID, 00137 MESHCOP_TLV_PENDING_TIMESTAMP, 00138 MESHCOP_TLV_COMMISSIONER_ID, 00139 MESHCOP_TLV_STEERING_DATA, 00140 MESHCOP_TLV_DELAY_TIMER, 00141 MESHCOP_TLV_GET, 00142 MESHCOP_TLV_COMMISSIONER_UDP_PORT, 00143 MESHCOP_TLV_JOINER_UDP_PORT, 00144 MESHCOP_TLV_STATE, 00145 MESHCOP_TLV_NETWORK_KEY_SEQUENCE 00146 }; 00147 00148 const uint8_t meshcop_active_set_ignore[] = { 00149 MESHCOP_TLV_PENDING_TIMESTAMP, 00150 MESHCOP_TLV_COMMISSIONER_SESSION_ID, 00151 MESHCOP_TLV_COMMISSIONER_ID, 00152 MESHCOP_TLV_STEERING_DATA, 00153 MESHCOP_TLV_DELAY_TIMER, 00154 MESHCOP_TLV_NETWORK_KEY_SEQUENCE 00155 }; 00156 00157 const uint8_t mle_active_configuration_dataset_ignore_tlvs[] = { 00158 MESHCOP_TLV_ACTIVE_TIME_STAMP 00159 }; 00160 00161 const uint8_t mle_pending_configuration_dataset_ignore_tlvs[] = { 00162 MESHCOP_TLV_PENDING_TIMESTAMP 00163 }; 00164 00165 uint8_t mle_active_configuration_dataset_tlvs_size(void) 00166 { 00167 return sizeof(mle_active_configuration_dataset_tlvs); 00168 } 00169 00170 uint8_t active_configuration_dataset_tlvs_size(void) 00171 { 00172 return sizeof(active_configuration_dataset_tlvs); 00173 } 00174 00175 uint8_t mle_active_configuration_dataset_ignore_tlvs_size(void) 00176 { 00177 return sizeof(mle_active_configuration_dataset_ignore_tlvs); 00178 } 00179 00180 uint8_t mle_pending_configuration_dataset_ignore_tlvs_size(void) 00181 { 00182 return sizeof(mle_pending_configuration_dataset_ignore_tlvs); 00183 } 00184 00185 uint8_t mle_pending_configuration_dataset_tlvs_size(void) 00186 { 00187 return sizeof(mle_pending_configuration_dataset_tlvs); 00188 } 00189 uint8_t pending_configuration_dataset_tlvs_size(void) 00190 { 00191 return sizeof(pending_configuration_dataset_tlvs); 00192 } 00193 uint8_t entrust_dataset_tlvs_size(void) 00194 { 00195 return sizeof(entrust_dataset_tlvs); 00196 } 00197 #define MAX_OPERATIONAL_DATASET_SIZE 254 00198 00199 typedef struct { 00200 uint32_t timeout_in_ms; 00201 uint64_t timestamp; 00202 uint16_t length; 00203 uint8_t data[MAX_OPERATIONAL_DATASET_SIZE]; 00204 } configuration_set_t; 00205 00206 typedef struct { 00207 link_configuration_s *configuration_ptr; 00208 configuration_set_t *active_configuration_ptr; 00209 configuration_set_t *pending_configuration_ptr; 00210 configuration_set_t *old_active_configuration_ptr; 00211 configuration_set_t *next_active_configuration_ptr; 00212 configuration_set_t *next_pending_configuration_ptr; 00213 device_configuration_s *device_configuration_ptr; 00214 uint8_t parent_address[16]; 00215 uint16_t parent_port; 00216 thread_commission_done_cb *done_cb; 00217 timeout_t *attach_timeout; 00218 timeout_t *entrust_timeout; 00219 uint32_t provisioning_timeout; 00220 thread_provisioning_status_e provisioning_done; 00221 bool configuration_valid: 1; //TODO this should???? be put in link configuration 00222 bool finalisation_done: 1; 00223 bool nvm_link_configuration_load: 1; // load link configuration settings from NVM in restart 00224 int8_t interface_id; 00225 int8_t coap_service_id; 00226 int8_t secure_coap_service_id; 00227 bool pending_set_in_sync: 1; 00228 ns_list_link_t link; 00229 } thread_joiner_t; 00230 00231 00232 static NS_LIST_DEFINE(instance_list, thread_joiner_t, link); 00233 00234 static int thread_joiner_application_nvm_link_config_read(thread_joiner_t *this); 00235 static bool thread_joiner_application_validate_settings(thread_joiner_t *this); 00236 static uint8_t *thread_joiner_application_write_channel(uint8_t *ptr, uint16_t data); 00237 00238 static int stringlen(const char *s, int n) 00239 { 00240 char *end = memchr(s, 0, n); 00241 return end ? end - s : n; 00242 } 00243 00244 static char *str_dub(char *str) 00245 { 00246 char *result_ptr = NULL; 00247 if (str) { 00248 result_ptr = ns_dyn_mem_alloc(strlen(str) + 1); 00249 if (result_ptr) { 00250 strcpy(result_ptr, str); 00251 } 00252 } 00253 return result_ptr; 00254 } 00255 00256 static thread_joiner_t *thread_joiner_find(int8_t interface_id) 00257 { 00258 thread_joiner_t *this = NULL; 00259 ns_list_foreach(thread_joiner_t, cur_ptr, &instance_list) { 00260 if (cur_ptr->interface_id == interface_id) { 00261 this = cur_ptr; 00262 break; 00263 } 00264 } 00265 return this; 00266 } 00267 00268 static thread_joiner_t *thread_joiner_find_by_service(int8_t service_id) 00269 { 00270 thread_joiner_t *this = NULL; 00271 ns_list_foreach(thread_joiner_t, cur_ptr, &instance_list) { 00272 if (cur_ptr->coap_service_id == service_id || cur_ptr->secure_coap_service_id == service_id) { 00273 this = cur_ptr; 00274 break; 00275 } 00276 } 00277 return this; 00278 } 00279 00280 static thread_joiner_t *thread_joiner_get(int8_t interface_id) 00281 { 00282 thread_joiner_t *this = thread_joiner_find(interface_id); 00283 if (!this) { 00284 this = ns_dyn_mem_alloc(sizeof(thread_joiner_t)); 00285 if (this) { 00286 memset(this, 0, sizeof(thread_joiner_t)); 00287 ns_list_add_to_start(&instance_list, this); 00288 this->interface_id = interface_id; 00289 this->provisioning_done = PROVISIONING_STATUS_DONE; // Default value for provisioning is done 00290 } 00291 } 00292 return this; 00293 } 00294 00295 static void thread_joiner_application_commission_clean(thread_joiner_t *this) 00296 { 00297 thread_commissioning_if_pairwise_key_delete_all(this->interface_id); 00298 memset(this->parent_address, 0, 16); 00299 this->parent_port = 0; 00300 coap_service_delete(this->secure_coap_service_id); 00301 coap_service_delete(this->coap_service_id); 00302 this->secure_coap_service_id = 0; 00303 this->coap_service_id = 0; 00304 eventOS_timeout_cancel(this->attach_timeout); 00305 eventOS_timeout_cancel(this->entrust_timeout); 00306 this->attach_timeout = NULL; 00307 this->entrust_timeout = NULL; 00308 } 00309 00310 //@TODO wrong place move these 00311 //@TODO Steering data is wrongly made it is not part of static configuration 00312 //@TODO PSKc is static data and should always be present not dynamic. 00313 static link_configuration_s *link_configuration_create(void) 00314 { 00315 link_configuration_s *this = ns_dyn_mem_alloc(sizeof(link_configuration_s)); 00316 if (!this) { 00317 return NULL; 00318 } 00319 memset(this, 0, sizeof(link_configuration_s)); 00320 this->securityPolicy = SECURITY_POLICY_ALL_SECURITY; // Set all default values ('1') for security policy flags 00321 this->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY; // Set all default values 00322 return this; 00323 } 00324 00325 static void link_configuration_delete(link_configuration_s *this) 00326 { 00327 if (!this) { 00328 return; 00329 } 00330 ns_dyn_mem_free(this); 00331 } 00332 00333 static void link_configuration_copy(link_configuration_s *this, link_configuration_s *configuration_ptr) 00334 { 00335 if (!this || !configuration_ptr) { 00336 return; 00337 } 00338 memcpy(this->name, configuration_ptr->name, 16); 00339 memcpy(this->PSKc, configuration_ptr->PSKc, 16); 00340 memcpy(this->master_key, configuration_ptr->master_key, 16); 00341 memcpy(this->mesh_local_ula_prefix, configuration_ptr->mesh_local_ula_prefix, 8); 00342 memcpy(this->extented_pan_id, configuration_ptr->extented_pan_id, 8); 00343 memcpy(this->channel_mask, configuration_ptr->channel_mask, 5); 00344 this->key_rotation = configuration_ptr->key_rotation; 00345 this->key_sequence = configuration_ptr->key_sequence; 00346 this->panId = configuration_ptr->panId; 00347 this->rfChannel = configuration_ptr->rfChannel; 00348 this->securityPolicy = configuration_ptr->securityPolicy; 00349 this->securityPolicyExt = configuration_ptr->securityPolicyExt; 00350 this->timestamp = configuration_ptr->timestamp; 00351 return; 00352 } 00353 static int link_configuration_update(link_configuration_s *link_configuration, uint8_t *msg_ptr, uint16_t msg_len) 00354 { 00355 uint8_t *ptr; 00356 uint16_t len; 00357 00358 if (!msg_ptr || !link_configuration) { 00359 return -1; 00360 } 00361 len = thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_NETWORK_NAME, &ptr); 00362 if (len > 0) { 00363 memset(link_configuration->name, 0, 16); 00364 memcpy(link_configuration->name, ptr, (len > 16) ? 16 : len); 00365 } 00366 00367 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_CHANNEL, &ptr) >= 3) { 00368 //channel_page = channel_ptr[0]; 00369 link_configuration->rfChannel = common_read_16_bit(&ptr[1]); 00370 } 00371 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_CHANNEL_MASK, &ptr) > 5) { 00372 //channel_page = channel_ptr[0]; 00373 if (ptr[0] == 0 && ptr[1] == 4) { 00374 link_configuration->channel_page = ptr[0]; 00375 memcpy(link_configuration->channel_mask, &ptr[2], 4); 00376 } else { 00377 tr_warn("Invalid channel mask"); 00378 } 00379 } 00380 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_XPANID, &ptr) >= 8) { 00381 memcpy(link_configuration->extented_pan_id, ptr, 8); 00382 } 00383 00384 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, &ptr) >= 8) { 00385 memcpy(link_configuration->mesh_local_ula_prefix, ptr, 8); 00386 } 00387 00388 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_NETWORK_MASTER_KEY, &ptr) >= 16) { 00389 memcpy(link_configuration->master_key, ptr, 16); 00390 } 00391 00392 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &ptr) >= 8) { 00393 link_configuration->timestamp = common_read_64_bit(ptr); 00394 } 00395 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_PANID, &ptr) >= 2) { 00396 link_configuration->panId = common_read_16_bit(ptr); 00397 } 00398 if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_PSKC, &ptr) >= 16) { 00399 memcpy(link_configuration->PSKc, ptr, 16); 00400 } 00401 uint16_t tlv_len = thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_SECURITY_POLICY, &ptr); 00402 if (tlv_len >= 3) { 00403 link_configuration->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY; 00404 link_configuration->securityPolicy = ptr[2]; 00405 link_configuration->key_rotation = common_read_16_bit(ptr); 00406 if (tlv_len > 3) { 00407 link_configuration->securityPolicyExt = ptr[3]; 00408 } 00409 } 00410 00411 return 0; 00412 } 00413 00414 static void link_configuration_trace(link_configuration_s *this) 00415 { 00416 if (!this) { 00417 return; 00418 } 00419 tr_debug("NwkName: %s", trace_array(this->name, 16)); 00420 tr_debug("Mesh ula: %s", trace_array(this->mesh_local_ula_prefix, 8)); 00421 tr_debug("Extendend PanId: %s", trace_array(this->extented_pan_id, 8)); 00422 tr_debug("panid: %"PRIu16", Channel:%"PRIu16", keyRot:%"PRIu16", keySeq:%"PRIu32, this->panId, this->rfChannel, this->key_rotation, this->key_sequence); 00423 return; 00424 } 00425 00426 static device_configuration_s *device_configuration_create(void) 00427 { 00428 device_configuration_s *this = ns_dyn_mem_alloc(sizeof(device_configuration_s)); 00429 if (!this) { 00430 return NULL; 00431 } 00432 memset(this, 0, sizeof(device_configuration_s)); 00433 return this; 00434 } 00435 00436 static void device_configuration_delete(device_configuration_s *this) 00437 { 00438 if (!this) { 00439 return; 00440 } 00441 ns_dyn_mem_free(this->PSKd_ptr); 00442 ns_dyn_mem_free(this->provisioning_uri_ptr); 00443 ns_dyn_mem_free(this->vendor_name_ptr); 00444 ns_dyn_mem_free(this->vendor_model_ptr); 00445 ns_dyn_mem_free(this->vendor_sw_version_ptr); 00446 ns_dyn_mem_free(this->vendor_data_ptr); 00447 ns_dyn_mem_free(this); 00448 } 00449 static void device_configuration_copy(device_configuration_s *this, device_configuration_s *configuration_ptr) 00450 { 00451 if (!this || !configuration_ptr) { 00452 return; 00453 } 00454 memcpy(this->eui64, configuration_ptr->eui64, 8); 00455 memcpy(this->extended_random_mac, configuration_ptr->extended_random_mac, 8); 00456 memcpy(this->mesh_local_eid, configuration_ptr->mesh_local_eid, 8); 00457 memcpy(this->vendor_stack_version, configuration_ptr->vendor_stack_version, 6); 00458 //TODO: count PSKc instead and use that 00459 if (configuration_ptr->PSKd_ptr && configuration_ptr->PSKd_len > 0) { 00460 this->PSKd_ptr = ns_dyn_mem_alloc(configuration_ptr->PSKd_len); 00461 if (this->PSKd_ptr) { 00462 memcpy(this->PSKd_ptr, configuration_ptr->PSKd_ptr, configuration_ptr->PSKd_len); 00463 this->PSKd_len = configuration_ptr->PSKd_len; 00464 } else { 00465 this->PSKd_len = 0; 00466 } 00467 } 00468 00469 this->provisioning_uri_ptr = str_dub(configuration_ptr->provisioning_uri_ptr); 00470 this->vendor_name_ptr = str_dub(configuration_ptr->vendor_name_ptr); 00471 this->vendor_model_ptr = str_dub(configuration_ptr->vendor_model_ptr); 00472 this->vendor_sw_version_ptr = str_dub(configuration_ptr->vendor_sw_version_ptr); 00473 00474 uint16_t vendor_data_len = configuration_ptr->vendor_data_len; 00475 00476 if (vendor_data_len) { 00477 if (vendor_data_len > 64) { 00478 vendor_data_len = 64; 00479 } 00480 this->vendor_data_ptr = ns_dyn_mem_alloc(vendor_data_len); 00481 if (this->vendor_data_ptr) { 00482 memcpy(this->vendor_data_ptr, configuration_ptr->vendor_data_ptr, vendor_data_len); 00483 this->vendor_data_len = vendor_data_len; 00484 } 00485 } 00486 return; 00487 } 00488 static void device_configuration_trace(device_configuration_s *this) 00489 { 00490 if (!this) { 00491 return; 00492 } 00493 tr_debug("Mesh local eid: %s", trace_array(this->mesh_local_eid, 8)); 00494 tr_debug("extended random: %s", trace_array(this->extended_random_mac, 8)); 00495 tr_debug("uri: %s", this->provisioning_uri_ptr ? this->provisioning_uri_ptr : "(none)"); 00496 tr_debug("name: %s", this->vendor_name_ptr); 00497 tr_debug("mode: %s", this->vendor_model_ptr); 00498 tr_debug("version: %s", this->vendor_sw_version_ptr); 00499 tr_debug("vendor data: %s", trace_array(this->vendor_data_ptr, this->vendor_data_len)); 00500 return; 00501 } 00502 00503 static void device_configuration_validate(device_configuration_s *this) 00504 { 00505 // Set defaults if not overridden by client 00506 if (!this->vendor_model_ptr) { 00507 this->vendor_model_ptr = str_dub(THREAD_VENDOR_MODEL); 00508 } 00509 if (!this->vendor_name_ptr) { 00510 this->vendor_name_ptr = str_dub(THREAD_VENDOR_NAME); 00511 } 00512 if (!this->vendor_sw_version_ptr) { 00513 this->vendor_sw_version_ptr = str_dub(THREAD_SW_VERSION); 00514 } 00515 if (memcmp(this->vendor_stack_version, "\0\0\0\0\0\0", 6) == 0) { 00516 // Empty lets set defaults 00517 this->vendor_stack_version[0] = (uint8_t)(THREAD_ARM_OUI >> 16); 00518 this->vendor_stack_version[1] = (uint8_t)(THREAD_ARM_OUI >> 8); 00519 this->vendor_stack_version[2] = (uint8_t)(THREAD_ARM_OUI); 00520 this->vendor_stack_version[3] = (uint8_t)(THREAD_BUILD_NUMBER >> 4); 00521 this->vendor_stack_version[4] = (uint8_t)(((THREAD_BUILD_NUMBER & 0x0f) << 4) | THREAD_REVISION_NUMBER); 00522 this->vendor_stack_version[5] = (uint8_t)((THREAD_VERSION_MIN << 4) | THREAD_VERSION_MAJ); 00523 } 00524 } 00525 00526 static configuration_set_t *configuration_set_copy(configuration_set_t *source_ptr) 00527 { 00528 configuration_set_t *result_ptr; 00529 if (!source_ptr) { 00530 return NULL; 00531 } 00532 result_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t)); 00533 if (!result_ptr) { 00534 return NULL; 00535 } 00536 memcpy(result_ptr->data, source_ptr->data, source_ptr->length); 00537 result_ptr->length = source_ptr->length; 00538 result_ptr->timeout_in_ms = source_ptr->timeout_in_ms; 00539 result_ptr->timestamp = source_ptr->timestamp; 00540 return result_ptr; 00541 } 00542 00543 static bool configuration_set_tlv_required(uint8_t tlv_id, const uint8_t *tlv_ptr, uint8_t tlv_len) 00544 { 00545 while (tlv_len) { 00546 if (tlv_ptr[tlv_len-- -1] == tlv_id) { 00547 return true; 00548 } 00549 } 00550 return false; 00551 } 00552 00553 static uint16_t configuration_set_length(configuration_set_t *config_ptr, const uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 00554 { 00555 const uint8_t *tlv_ptr; 00556 uint16_t tlv_len; 00557 int16_t result_len = 0; 00558 tlv_len = config_ptr->length; 00559 tlv_ptr = config_ptr->data; 00560 00561 while (tlv_ptr && tlv_len) { 00562 if ((!req_tlv_ptr || req_tlv_len == 0 || configuration_set_tlv_required(*tlv_ptr, req_tlv_ptr, req_tlv_len)) && 00563 !configuration_set_tlv_required(*tlv_ptr, ignored_tlv_ptr, ignored_tlv_len)) { 00564 int16_t required_len = thread_meshcop_tlv_length_required(tlv_ptr, tlv_len); 00565 if (required_len < 0) { 00566 return 0; 00567 } 00568 result_len += required_len; 00569 } 00570 tlv_ptr = thread_meshcop_tlv_get_next(tlv_ptr, &tlv_len); 00571 } 00572 00573 return result_len; 00574 } 00575 00576 static uint8_t *configuration_set_write(configuration_set_t *config_ptr, uint8_t *ptr, const uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 00577 { 00578 const uint8_t *tlv_ptr; 00579 uint16_t tlv_len; 00580 tlv_len = config_ptr->length; 00581 tlv_ptr = config_ptr->data; 00582 while (tlv_ptr && tlv_len) { 00583 if ((!req_tlv_ptr || req_tlv_len == 0 || configuration_set_tlv_required(*tlv_ptr, req_tlv_ptr, req_tlv_len)) && 00584 !configuration_set_tlv_required(*tlv_ptr, ignored_tlv_ptr, ignored_tlv_len)) { 00585 int16_t required_len = thread_meshcop_tlv_length_required(tlv_ptr, tlv_len); 00586 if (required_len < 0 || config_ptr->length + required_len > MAX_OPERATIONAL_DATASET_SIZE) { 00587 // Source configuration is corrupted or length exceeded 00588 return ptr; 00589 } 00590 memcpy(ptr, tlv_ptr, required_len); 00591 ptr += required_len; 00592 } 00593 tlv_ptr = thread_meshcop_tlv_get_next(tlv_ptr, &tlv_len); 00594 } 00595 return ptr; 00596 } 00597 00598 static uint8_t *configuration_set_add_fields(configuration_set_t *destination_ptr, const uint8_t *source_ptr, uint16_t source_len, const uint8_t *required_tlv_ptr, uint8_t required_tlv_len) 00599 { 00600 uint8_t *ptr; 00601 ptr = destination_ptr->data + destination_ptr->length; 00602 while (source_ptr && source_len) { 00603 if (configuration_set_tlv_required(*source_ptr, required_tlv_ptr, required_tlv_len)) { 00604 int16_t required_len = thread_meshcop_tlv_length_required(source_ptr, source_len); 00605 if (required_len < 0 || destination_ptr->length + required_len > MAX_OPERATIONAL_DATASET_SIZE) { 00606 // Source configuration is corrupted or length exceeded 00607 return ptr; 00608 } 00609 memcpy(ptr, source_ptr, required_len); 00610 destination_ptr->length += required_len; 00611 ptr += required_len; 00612 } 00613 source_ptr = thread_meshcop_tlv_get_next(source_ptr, &source_len); 00614 } 00615 return ptr; 00616 } 00617 static uint8_t *configuration_set_add_all_fields(configuration_set_t *destination_ptr, const uint8_t *source_ptr, uint16_t source_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 00618 { 00619 uint8_t *ptr; 00620 ptr = destination_ptr->data + destination_ptr->length; 00621 while (source_ptr && source_len) { 00622 if (!configuration_set_tlv_required(*source_ptr, ignored_tlv_ptr, ignored_tlv_len)) { 00623 int16_t required_len = thread_meshcop_tlv_length_required(source_ptr, source_len); 00624 if (required_len < 0 || destination_ptr->length + required_len > MAX_OPERATIONAL_DATASET_SIZE) { 00625 // Source configuration is corrupted or length exceeded 00626 return ptr; 00627 } 00628 memcpy(ptr, source_ptr, required_len); 00629 destination_ptr->length += required_len; 00630 ptr += required_len; 00631 } 00632 source_ptr = thread_meshcop_tlv_get_next(source_ptr, &source_len); 00633 } 00634 return ptr; 00635 } 00636 static void configuration_set_copy_missing(configuration_set_t *destination_ptr, configuration_set_t *source_ptr) 00637 { 00638 uint8_t *tlv_list_ptr; 00639 uint16_t tlv_list_len = 0; 00640 if (!source_ptr || !destination_ptr) { 00641 return; 00642 } 00643 thread_meshcop_tlv_list_generate(source_ptr->data, source_ptr->length, NULL, &tlv_list_len); 00644 if (tlv_list_len == 0) { 00645 return; 00646 } 00647 tlv_list_ptr = ns_dyn_mem_temporary_alloc(tlv_list_len); 00648 if (!tlv_list_ptr) { 00649 return; 00650 } 00651 thread_meshcop_tlv_list_generate(source_ptr->data, source_ptr->length, tlv_list_ptr, &tlv_list_len); 00652 tr_debug("list in source: %s", trace_array(tlv_list_ptr, tlv_list_len)); 00653 00654 for (uint8_t n = 0; n < tlv_list_len; n++) { 00655 if (thread_meshcop_tlv_exist(destination_ptr->data, destination_ptr->length, tlv_list_ptr[n])) { 00656 // Depending specification 0 length TLVs from source should be also removed 00657 tlv_list_len = thread_meshcop_tlv_list_remove(tlv_list_ptr, tlv_list_len, tlv_list_ptr[n]); 00658 n--; // When we remove item from list we stay put 00659 } 00660 } 00661 if (tlv_list_len == 0) { 00662 // All mandatory TLVs present 00663 ns_dyn_mem_free(tlv_list_ptr); 00664 return; 00665 } 00666 tr_debug("mandatory TLVs needed: %s", trace_array(tlv_list_ptr, tlv_list_len)); 00667 configuration_set_add_fields(destination_ptr, source_ptr->data, source_ptr->length, tlv_list_ptr, tlv_list_len); 00668 ns_dyn_mem_free(tlv_list_ptr); 00669 } 00670 static void configuration_set_remove_null_tlv(configuration_set_t *configuration_ptr) 00671 { 00672 uint8_t *ptr; 00673 uint8_t *next_ptr; 00674 uint16_t length; 00675 if (!configuration_ptr) { 00676 return; 00677 } 00678 length = configuration_ptr->length; 00679 ptr = configuration_ptr->data; 00680 00681 do { 00682 if (thread_meshcop_tlv_length(ptr, length) == 0) { 00683 // remove this TLV 00684 configuration_ptr->length -= thread_meshcop_tlv_length_required(ptr, length); 00685 next_ptr = (uint8_t *)thread_meshcop_tlv_get_next(ptr, &length); 00686 if (next_ptr) { 00687 memmove(ptr, next_ptr, length); 00688 } 00689 } else { 00690 ptr = (uint8_t *)thread_meshcop_tlv_get_next(ptr, &length); 00691 } 00692 00693 } while (ptr && length); 00694 return; 00695 } 00696 00697 static void configuration_set_copy_mandatory(configuration_set_t *destination_ptr, configuration_set_t *source_ptr) 00698 { 00699 uint8_t tlv_list[sizeof(active_configuration_dataset_tlvs)]; 00700 uint16_t tlv_list_len = sizeof(active_configuration_dataset_tlvs); 00701 if (!source_ptr || !destination_ptr) { 00702 return; 00703 } 00704 memcpy(tlv_list, active_configuration_dataset_tlvs, sizeof(active_configuration_dataset_tlvs)); 00705 00706 for (uint8_t n = 0; n < sizeof(active_configuration_dataset_tlvs); n++) { 00707 if (0 < thread_meshcop_tlv_find(destination_ptr->data, destination_ptr->length, active_configuration_dataset_tlvs[n], NULL)) { 00708 // Depending specification 0 length TLVs from source should be also removed 00709 tlv_list_len = thread_meshcop_tlv_list_remove(tlv_list, tlv_list_len, active_configuration_dataset_tlvs[n]); 00710 } 00711 } 00712 if (tlv_list_len == 0) { 00713 // All mandatory TLVs present 00714 return; 00715 } 00716 tr_debug("mandatory TLVs needed: %s", trace_array(tlv_list, tlv_list_len)); 00717 configuration_set_add_fields(destination_ptr, source_ptr->data, source_ptr->length, tlv_list, tlv_list_len); 00718 } 00719 static void configuration_set_generate(int8_t interface_id, configuration_set_t *destination_ptr, link_configuration_s *configuration_ptr) 00720 { 00721 uint8_t *response_ptr; 00722 00723 if (!destination_ptr || !configuration_ptr) { 00724 return; 00725 } 00726 response_ptr = destination_ptr->data; 00727 00728 response_ptr = thread_joiner_application_write_channel(response_ptr, configuration_ptr->rfChannel); 00729 *response_ptr++ = MESHCOP_TLV_CHANNEL_MASK; // type 00730 *response_ptr++ = 6; // length 00731 *response_ptr++ = configuration_ptr->channel_page; // channel page 00732 *response_ptr++ = 4; // channel mask length 00733 memcpy(response_ptr, configuration_ptr->channel_mask, 4); 00734 response_ptr += 4; 00735 response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_XPANID, 8, configuration_ptr->extented_pan_id); 00736 response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, 8, configuration_ptr->mesh_local_ula_prefix); 00737 response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_NETWORK_MASTER_KEY, 16, configuration_ptr->master_key); 00738 response_ptr = thread_tmfcop_tlv_data_write_uint16(response_ptr, MESHCOP_TLV_PANID, configuration_ptr->panId); 00739 response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_PSKC, 16, configuration_ptr->PSKc); 00740 response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_NETWORK_NAME, stringlen((char *)&configuration_ptr->name, 16), configuration_ptr->name); 00741 *response_ptr++ = MESHCOP_TLV_SECURITY_POLICY; // type 00742 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00743 if (thread_info(cur)->version >= THREAD_VERSION_1_2) { 00744 *response_ptr++ = 4; // length 00745 response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr); 00746 *response_ptr++ = configuration_ptr->securityPolicy; 00747 *response_ptr++ = configuration_ptr->securityPolicyExt; 00748 } else { 00749 *response_ptr++ = 3; // length 00750 response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr); 00751 *response_ptr++ = configuration_ptr->securityPolicy; 00752 } 00753 response_ptr = thread_tmfcop_tlv_data_write_uint64(response_ptr, MESHCOP_TLV_ACTIVE_TIME_STAMP, configuration_ptr->timestamp); 00754 destination_ptr->length = response_ptr - destination_ptr->data; 00755 } 00756 00757 static bool configuration_set_validate(uint8_t *configuration_set, uint16_t configuration_set_len, bool make_full_validation) 00758 { 00759 if (thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_NETWORK_MASTER_KEY, NULL) < 16 || 00760 thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, NULL) < 8 || 00761 thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_XPANID, NULL) < 8 || 00762 thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_NETWORK_NAME, NULL) == 0 || 00763 thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_PSKC, NULL) < 16) { 00764 // Absolutely minimum we must have is master secret to attach. 00765 // If commissioner wants to be connected we must have PSKc,Name,Xpanid 00766 // If there is some fields missing we could attach, but timestamp must be set to 0 which will then cause synchronization 00767 tr_debug("Not all TLv's included"); 00768 return false; 00769 } 00770 00771 if (make_full_validation) { 00772 if ((thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_CHANNEL, NULL) == 0) || 00773 (thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_PANID, NULL) == 0) || 00774 (thread_meshcop_tlv_find(configuration_set, configuration_set_len, MESHCOP_TLV_XPANID, NULL) == 0)) { 00775 tr_debug("Not all TLv's included"); 00776 return false; 00777 } 00778 } 00779 return true; 00780 } 00781 00782 static bool thread_joiner_application_validate_settings(thread_joiner_t *this) 00783 { 00784 bool new_value_generated = 0; 00785 if (memcmp(this->device_configuration_ptr->extended_random_mac, ADDR_UNSPECIFIED, 8) == 0) { 00786 randLIB_get_n_bytes_random(this->device_configuration_ptr->extended_random_mac, 8); 00787 this->device_configuration_ptr->extended_random_mac[0] |= 2; //Set Local Bit 00788 this->device_configuration_ptr->extended_random_mac[0] &= ~1; //Clear multicast bit 00789 new_value_generated = 1; 00790 tr_info("Generating Random MAC"); 00791 } 00792 while (addr_iid_reserved(this->device_configuration_ptr->mesh_local_eid) || 00793 memcmp(this->device_configuration_ptr->mesh_local_eid, ADDR_SHORT_ADR_SUFFIC, 6) == 0) { 00794 // addr_iid_reserved checks the all zeroes case. 00795 randLIB_get_n_bytes_random(this->device_configuration_ptr->mesh_local_eid, 8); 00796 new_value_generated = 1; 00797 tr_info("Generating Random ML-EID"); 00798 } 00799 if (this->configuration_ptr->key_rotation < 1) { 00800 this->configuration_ptr->key_rotation = 1; 00801 } 00802 return new_value_generated; 00803 } 00804 00805 int thread_joiner_application_init(int8_t interface_id, device_configuration_s *device_configuration_ptr, link_configuration_s *default_configuration_ptr) 00806 { 00807 thread_joiner_t *this; 00808 uint8_t pskd_len; 00809 00810 if (!device_configuration_ptr) { 00811 return -1; 00812 } 00813 pskd_len = device_configuration_ptr->PSKd_len; 00814 00815 if (pskd_len > 32 || pskd_len < 6) { 00816 return -2; 00817 } 00818 00819 this = thread_joiner_get(interface_id); 00820 if (!this) { 00821 return -3; 00822 } 00823 00824 if (!this->device_configuration_ptr) { 00825 this->device_configuration_ptr = device_configuration_create(); 00826 } 00827 if (!this->device_configuration_ptr) { 00828 tr_error("Joiner Device creation failed"); 00829 return -4; 00830 } 00831 device_configuration_copy(this->device_configuration_ptr, device_configuration_ptr); 00832 device_configuration_validate(this->device_configuration_ptr); // Set defaults if missing 00833 device_configuration_trace(this->device_configuration_ptr); 00834 if (memcmp(this->device_configuration_ptr->eui64, "\0\0\0\0\0\0\0\0", 8) == 0) { 00835 //EUI64 is not set we then read that from Radio 00836 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00837 00838 if (cur && cur->mac_api) { 00839 cur->mac_api->mac64_get(cur->mac_api, MAC_EXTENDED_READ_ONLY, this->device_configuration_ptr->eui64); 00840 } 00841 } 00842 // Adding entropy for our random seed 00843 randLIB_add_seed(common_read_64_bit(this->device_configuration_ptr->eui64)); 00844 00845 // create link configuration, could be replaced by configuration settings read from NVM 00846 if (!this->configuration_ptr) { 00847 this->configuration_ptr = link_configuration_create(); 00848 } 00849 this->configuration_valid = false; 00850 00851 if (!this->configuration_ptr) { 00852 tr_error("Joiner creation failed"); 00853 device_configuration_delete(this->device_configuration_ptr); 00854 return -4; 00855 } 00856 if (!this->active_configuration_ptr) { 00857 this->active_configuration_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t)); 00858 } 00859 if (!this->active_configuration_ptr) { 00860 tr_error("Active configuration creation failed"); 00861 device_configuration_delete(this->device_configuration_ptr); 00862 link_configuration_delete(this->configuration_ptr); 00863 return -5; 00864 } 00865 memset(this->active_configuration_ptr, 0, sizeof(configuration_set_t)); 00866 00867 if (default_configuration_ptr) { 00868 link_configuration_copy(this->configuration_ptr, default_configuration_ptr); 00869 thread_joiner_application_validate_settings(this);// Generate all random information 00870 if (memcmp(this->configuration_ptr->master_key, ADDR_UNSPECIFIED, 16) != 0 || 00871 memcmp(this->configuration_ptr->PSKc, ADDR_UNSPECIFIED, 16) != 0) { 00872 //If no master key or PSKc set we assume not valid configuration for thread network others may be possible to be 0 00873 //This allows some configurations to be set statically for testing purposes 00874 this->configuration_valid = true; 00875 configuration_set_generate(this->interface_id, this->active_configuration_ptr, this->configuration_ptr); 00876 } 00877 } 00878 // Always load link configuration from bootstrap state machine. NVM overrides Static configuration 00879 this->nvm_link_configuration_load = true; 00880 00881 link_configuration_trace(this->configuration_ptr); 00882 00883 return 0; 00884 } 00885 00886 int thread_joiner_application_form_network(int8_t interface_id, uint8_t *commissioning_credentials_ptr, char *name_ptr) 00887 { 00888 thread_joiner_t *this = thread_joiner_find(interface_id); 00889 (void)commissioning_credentials_ptr; 00890 (void)name_ptr; 00891 tr_debug("Joiner form random network"); 00892 if (!this) { 00893 return -1; 00894 } 00895 /* 00896 * TODO generate random network parameter and enable commissioner to join the network 00897 */ 00898 00899 return 0; 00900 } 00901 00902 void thread_joiner_application_deinit(int8_t interface_id) 00903 { 00904 thread_joiner_t *this = thread_joiner_find(interface_id); 00905 if (this) { 00906 ns_list_remove(&instance_list, this); 00907 link_configuration_delete(this->configuration_ptr); 00908 device_configuration_delete(this->device_configuration_ptr); 00909 if (this->pending_configuration_ptr) { 00910 ns_dyn_mem_free(this->pending_configuration_ptr); 00911 } 00912 if (this->next_pending_configuration_ptr) { 00913 ns_dyn_mem_free(this->next_pending_configuration_ptr); 00914 } 00915 if (this->active_configuration_ptr) { 00916 ns_dyn_mem_free(this->active_configuration_ptr); 00917 } 00918 if (this->old_active_configuration_ptr) { 00919 ns_dyn_mem_free(this->old_active_configuration_ptr); 00920 } 00921 ns_dyn_mem_free(this); 00922 } 00923 } 00924 00925 link_configuration_s *thread_joiner_application_get_config(int8_t interface_id) 00926 { 00927 thread_joiner_t *this = thread_joiner_find(interface_id); 00928 if (!this) { 00929 return NULL; 00930 } 00931 00932 if (this->configuration_valid == false) { 00933 return NULL; 00934 } 00935 return this->configuration_ptr; 00936 } 00937 00938 uint8_t *thread_joiner_application_network_name_get(int8_t interface_id) 00939 { 00940 thread_joiner_t *this = thread_joiner_find(interface_id); 00941 if (!this) { 00942 return NULL; 00943 } 00944 return this->configuration_ptr->name; 00945 } 00946 00947 static int thread_joiner_application_nvm_link_config_read(thread_joiner_t *this) 00948 { 00949 00950 // read config from NVM, in case of failure current settings are unchanged. 00951 int nvm_read_status = thread_nvm_store_active_configuration_read(this->active_configuration_ptr, sizeof(configuration_set_t)); 00952 tr_debug("active conf read %d", nvm_read_status); 00953 // validate that active configuration settings are valid, even if we couldn't read from nvm. 00954 if (!configuration_set_validate(this->active_configuration_ptr->data, this->active_configuration_ptr->length, true)) { 00955 tr_debug("No active configuration avail"); 00956 return -1; 00957 } 00958 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 00959 00960 thread_nvm_fast_data_t fast_data; 00961 memset(&fast_data, 0, sizeof(thread_nvm_fast_data_t)); 00962 int fast_data_read_ret = thread_nvm_store_fast_data_read(&fast_data); 00963 tr_info("From NVM %d", fast_data_read_ret); 00964 tr_info("mac-counter %"PRIu32, fast_data.mac_frame_counter); 00965 tr_info("mle-counter %"PRIu32, fast_data.mle_frame_counter); 00966 tr_info("seq-counter %"PRIu32, fast_data.seq_counter); 00967 00968 if (THREAD_NVM_FILE_SUCCESS == fast_data_read_ret) { 00969 if (this->configuration_ptr->key_sequence < fast_data.seq_counter) { 00970 this->configuration_ptr->key_sequence = fast_data.seq_counter; 00971 } 00972 } 00973 00974 fast_data.mac_frame_counter += MAC_FRAME_COUNTER_LIMIT; 00975 fast_data.mle_frame_counter += MLE_FRAME_COUNTER_LIMIT; 00976 thread_nvm_store_fast_data_write(&fast_data); 00977 00978 thread_nvm_store_device_configuration_read(this->device_configuration_ptr->extended_random_mac, this->device_configuration_ptr->mesh_local_eid); 00979 thread_nvm_store_link_info_read(); 00980 // Generate all random information, if device configuration read failed then the random mac and eid are created. 00981 bool new_value_generated = thread_joiner_application_validate_settings(this); 00982 if (new_value_generated) { 00983 thread_nvm_store_device_configuration_write(this->device_configuration_ptr->extended_random_mac, this->device_configuration_ptr->mesh_local_eid); 00984 } 00985 00986 this->configuration_valid = true; 00987 link_configuration_trace(this->configuration_ptr); 00988 00989 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id); 00990 //Add Security to MLE service 00991 thread_security_prev_key_generate(cur, this->configuration_ptr->master_key, this->configuration_ptr->key_sequence); 00992 thread_security_key_generate(cur, this->configuration_ptr->master_key, this->configuration_ptr->key_sequence); 00993 thread_security_next_key_generate(cur, this->configuration_ptr->master_key, this->configuration_ptr->key_sequence); 00994 00995 // update counters 00996 mle_service_security_set_frame_counter(this->interface_id, fast_data.mle_frame_counter); 00997 mac_helper_link_frame_counter_set(this->interface_id, fast_data.mac_frame_counter); 00998 00999 // this saves all configurations 01000 if (THREAD_NVM_FILE_SUCCESS != nvm_read_status) { 01001 thread_joiner_application_configuration_nvm_save(this->interface_id); 01002 } else { 01003 tr_info("Reading pending set"); 01004 configuration_set_t *pend_conf_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t)); 01005 if (pend_conf_ptr) { 01006 memset(pend_conf_ptr, 0, sizeof(configuration_set_t)); 01007 int pending_ret = thread_nvm_store_pending_configuration_read(pend_conf_ptr, sizeof(configuration_set_t)); 01008 if (THREAD_NVM_FILE_SUCCESS == pending_ret) { 01009 if (this->pending_configuration_ptr) { 01010 ns_dyn_mem_free(this->pending_configuration_ptr); 01011 } 01012 this->pending_configuration_ptr = pend_conf_ptr; 01013 this->pending_configuration_ptr->timeout_in_ms = 0; 01014 this->pending_set_in_sync = false; 01015 } else { 01016 tr_info("Reading pending from NVM error:%d", pending_ret); 01017 ns_dyn_mem_free(pend_conf_ptr); 01018 } 01019 } 01020 } 01021 this->nvm_link_configuration_load = false; 01022 return 0; 01023 } 01024 01025 static int thread_joiner_application_nvm_link_config_delete(thread_joiner_t *this) 01026 { 01027 if (!this) { 01028 return -1; 01029 } 01030 int ret = thread_nvm_store_pending_configuration_remove(); 01031 01032 if (ret != THREAD_NVM_FILE_SUCCESS) { 01033 tr_error("Pending configuration delete error: %d", ret); 01034 } 01035 01036 ret = thread_nvm_store_active_configuration_remove(); 01037 01038 if (ret != THREAD_NVM_FILE_SUCCESS) { 01039 tr_error("Active configuration delete error: %d", ret); 01040 } 01041 01042 // delete link configuration from cache, device will be restarted after settings are deleted 01043 this->configuration_valid = false; 01044 return 0; 01045 } 01046 01047 uint64_t thread_joiner_application_active_timestamp_get(int8_t interface_id) 01048 { 01049 thread_joiner_t *this = thread_joiner_find(interface_id); 01050 if (!this) { 01051 return 0; 01052 } 01053 01054 return this->configuration_ptr->timestamp; 01055 } 01056 01057 uint8_t thread_joiner_application_security_policy_get(int8_t interface_id) 01058 { 01059 thread_joiner_t *this = thread_joiner_find(interface_id); 01060 if (!this) { 01061 return 0; 01062 } 01063 01064 return this->configuration_ptr->securityPolicy; 01065 } 01066 01067 uint8_t *thread_joiner_application_random_mac_get(int8_t interface_id) 01068 { 01069 thread_joiner_t *this = thread_joiner_find(interface_id); 01070 if (!this || !this->device_configuration_ptr) { 01071 tr_error("thread_joiner_application_random_mac_get NULL parameter "); 01072 return (uint8_t *)ADDR_UNSPECIFIED; 01073 } 01074 return this->device_configuration_ptr->extended_random_mac; 01075 } 01076 uint8_t *thread_joiner_application_ml_eid_get(int8_t interface_id) 01077 { 01078 thread_joiner_t *this = thread_joiner_find(interface_id); 01079 if (!this || !this->device_configuration_ptr) { 01080 tr_error("thread_joiner_application_ml_eid_get parameter NULL"); 01081 return (uint8_t *)ADDR_UNSPECIFIED; 01082 } 01083 return this->device_configuration_ptr->mesh_local_eid; 01084 } 01085 void thread_joiner_application_active_timestamp_set(int8_t interface_id, uint64_t timestamp) 01086 { 01087 thread_joiner_t *this = thread_joiner_find(interface_id); 01088 uint8_t *timestamp_ptr = NULL; 01089 if (!this) { 01090 return; 01091 } 01092 01093 thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, ×tamp_ptr); 01094 if (timestamp_ptr) { 01095 common_write_64_bit(timestamp, timestamp_ptr); 01096 } 01097 01098 //update timestamps in active configuration and link configuration 01099 this->active_configuration_ptr->timestamp = timestamp; 01100 this->configuration_ptr->timestamp = timestamp; 01101 return; 01102 } 01103 01104 void thread_joiner_pending_config_activate(int8_t interface_id) 01105 { 01106 thread_joiner_t *this = thread_joiner_find(interface_id); 01107 01108 if (!this || !this->pending_configuration_ptr) { 01109 tr_error("No pending configuration or joiner!"); 01110 return; 01111 } 01112 01113 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id); 01114 01115 if (!cur) { 01116 tr_error("No interface information!"); 01117 return; 01118 } 01119 01120 /* 01121 * If pending configuration active timestamp is lower than current active timestamp allow pending configuration activation only 01122 * if master key is changed by the pending set 01123 */ 01124 link_configuration_s *link_configuration = thread_joiner_application_get_config(interface_id); 01125 01126 if (!link_configuration) { 01127 return; 01128 } 01129 01130 // Validate new link configuration 01131 uint8_t *master_key_ptr = NULL; 01132 uint64_t pending_active_timestamp = 0; 01133 thread_meshcop_tlv_data_get_uint64(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, &pending_active_timestamp); 01134 thread_meshcop_tlv_find(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, MESHCOP_TLV_NETWORK_MASTER_KEY, &master_key_ptr); 01135 01136 if ((pending_active_timestamp < thread_joiner_application_active_timestamp_get(interface_id))) { 01137 // If new active timestamp is older than current master key must be changed. 01138 if (!master_key_ptr || 01139 memcmp(master_key_ptr, link_configuration->master_key, 16) == 0) { 01140 tr_info("*** Pending set activation aborted - device has newer active timestamp"); 01141 thread_joiner_application_pending_config_delete(interface_id); 01142 return; 01143 } 01144 } 01145 01146 if (master_key_ptr && memcmp(master_key_ptr, link_configuration->master_key, 16) != 0) { 01147 this->configuration_ptr->key_sequence = 0; 01148 // if write fails, keep going... 01149 (void)thread_nvm_store_seq_counter_write(this->configuration_ptr->key_sequence); 01150 } 01151 01152 tr_info("*** Activating pending configuration."); 01153 01154 ns_dyn_mem_free(this->old_active_configuration_ptr); 01155 this->old_active_configuration_ptr = this->active_configuration_ptr; 01156 this->active_configuration_ptr = this->pending_configuration_ptr; 01157 this->active_configuration_ptr->timestamp = pending_active_timestamp; 01158 // All information is copied from old configuration so if configuration is corrupt we dont change anything. 01159 this->pending_configuration_ptr = NULL; 01160 thread_nvm_store_pending_configuration_remove(); 01161 configuration_set_copy_mandatory(this->active_configuration_ptr, this->old_active_configuration_ptr); 01162 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 01163 link_configuration_trace(this->configuration_ptr); 01164 01165 thread_joiner_application_configuration_nvm_save(this->interface_id); 01166 01167 01168 if (thread_link_configuration_activate(cur, this->configuration_ptr) != 0) { 01169 tr_error("Activating pending configuration failed."); 01170 } 01171 01172 tr_info("*** Activating pending configuration done."); 01173 } 01174 01175 01176 void thread_joiner_application_seconds_timer(int8_t interface_id, uint32_t seconds) 01177 { 01178 thread_joiner_t *this = thread_joiner_find(interface_id); 01179 //tr_debug("seconds tick for joiner pending timeout in %d",this->pending_timeout_in_ms); 01180 if (!this) { 01181 return; 01182 } 01183 if (this->provisioning_timeout) { 01184 if (this->provisioning_timeout < seconds) { 01185 this->provisioning_done = PROVISIONING_STATUS_NOT_DONE; 01186 } 01187 this->provisioning_timeout -= seconds; 01188 } 01189 if (!this->pending_configuration_ptr || this->pending_configuration_ptr->timeout_in_ms == 0) { 01190 return; 01191 } 01192 if (this->pending_configuration_ptr->timeout_in_ms > seconds * 1000) { 01193 this->pending_configuration_ptr->timeout_in_ms -= seconds * 1000; 01194 return; 01195 } 01196 // Activate the pending config 01197 thread_joiner_pending_config_activate(interface_id); 01198 } 01199 01200 int thread_joiner_application_pending_config_create(int8_t interface_id, uint8_t *data_ptr, uint16_t data_len) 01201 { 01202 thread_joiner_t *this = thread_joiner_find(interface_id); 01203 if (!this || data_len > MAX_OPERATIONAL_DATASET_SIZE) { 01204 return -1; 01205 } 01206 if (!this->pending_configuration_ptr) { 01207 this->pending_configuration_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t)); 01208 } 01209 if (!this->pending_configuration_ptr) { 01210 tr_error("pending configuration creation failed"); 01211 return -2; 01212 } 01213 memset(this->pending_configuration_ptr, 0, sizeof(configuration_set_t)); 01214 configuration_set_add_all_fields(this->pending_configuration_ptr, data_ptr, data_len, meshcop_pending_set_ignore, sizeof(meshcop_pending_set_ignore)); 01215 return 0; 01216 } 01217 01218 bool thread_joiner_application_pending_config_exists(int8_t interface_id) 01219 { 01220 thread_joiner_t *this = thread_joiner_find(interface_id); 01221 if (!this || !this->pending_configuration_ptr) { 01222 return false; 01223 } 01224 return true; 01225 } 01226 01227 bool thread_joiner_application_pending_delay_timer_in_sync(int8_t interface_id) 01228 { 01229 thread_joiner_t *this = thread_joiner_find(interface_id); 01230 if (!this || !this->pending_configuration_ptr) { 01231 return false; 01232 } 01233 return this->pending_set_in_sync; 01234 } 01235 01236 uint64_t thread_joiner_application_pending_config_timestamp_get(int8_t interface_id) 01237 { 01238 thread_joiner_t *this = thread_joiner_find(interface_id); 01239 if (!this || !this->pending_configuration_ptr || !this->pending_set_in_sync) { 01240 return 0; 01241 } 01242 return this->pending_configuration_ptr->timestamp; 01243 } 01244 01245 int thread_joiner_application_pending_config_timestamp_set(int8_t interface_id, uint64_t timestamp) 01246 { 01247 thread_joiner_t *this = thread_joiner_find(interface_id); 01248 if (!this || !this->pending_configuration_ptr) { 01249 return -1; 01250 } 01251 this->pending_configuration_ptr->timestamp = timestamp; 01252 return 0; 01253 } 01254 01255 01256 int thread_joiner_application_pending_config_enable(int8_t interface_id, uint32_t timeout_in_ms) 01257 { 01258 thread_joiner_t *this = thread_joiner_find(interface_id); 01259 if (!this || !this->pending_configuration_ptr) { 01260 return -1; 01261 } 01262 this->pending_configuration_ptr->timeout_in_ms = timeout_in_ms; 01263 this->pending_set_in_sync = true; 01264 01265 if (this->pending_configuration_ptr->timeout_in_ms > THREAD_MAX_DELAY_TIMER_SECONDS * 1000) { 01266 this->pending_configuration_ptr->timeout_in_ms = THREAD_MAX_DELAY_TIMER_SECONDS * 1000; 01267 } 01268 thread_joiner_application_configuration_nvm_save(this->interface_id); 01269 01270 return 0; 01271 } 01272 01273 uint32_t thread_joiner_application_pending_config_timeout_get(int8_t interface_id) 01274 { 01275 thread_joiner_t *this = thread_joiner_find(interface_id); 01276 if (!this || !this->pending_configuration_ptr) { 01277 return 0; 01278 } 01279 return this->pending_configuration_ptr->timeout_in_ms; 01280 } 01281 01282 uint16_t thread_joiner_application_pending_config_length(uint8_t interface_id, uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 01283 { 01284 uint16_t result_len; 01285 thread_joiner_t *this = thread_joiner_find(interface_id); 01286 if (!this || !this->pending_configuration_ptr) { 01287 return 0; 01288 } 01289 01290 result_len = configuration_set_length(this->pending_configuration_ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len); 01291 01292 /* Add pending timestamp if required and not ignored*/ 01293 if (thread_meshcop_tlv_list_type_available(req_tlv_ptr, req_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP) && 01294 !thread_meshcop_tlv_list_type_available(ignored_tlv_ptr, ignored_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP)) { 01295 result_len += 10; 01296 } 01297 01298 /* Always add delay timer */ 01299 result_len += 6; 01300 01301 return result_len; 01302 } 01303 01304 uint8_t *thread_joiner_application_pending_config_build(uint8_t interface_id, uint8_t *ptr, uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 01305 { 01306 thread_joiner_t *this = thread_joiner_find(interface_id); 01307 if (!this || !this->pending_configuration_ptr) { 01308 return ptr; 01309 } 01310 01311 /* Build pending config data */ 01312 ptr = configuration_set_write(this->pending_configuration_ptr, ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len); 01313 01314 /* Add pending timestamp (len = 10) if required and not ignored */ 01315 if (thread_meshcop_tlv_list_type_available(req_tlv_ptr, req_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP) && 01316 !thread_meshcop_tlv_list_type_available(ignored_tlv_ptr, ignored_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP)) { 01317 ptr = thread_meshcop_tlv_data_write_uint64(ptr, MESHCOP_TLV_PENDING_TIMESTAMP, this->pending_configuration_ptr->timestamp); 01318 } 01319 01320 /* Always add delay timer (len = 6) */ 01321 ptr = thread_meshcop_tlv_data_write_uint32(ptr, MESHCOP_TLV_DELAY_TIMER, this->pending_configuration_ptr->timeout_in_ms); 01322 01323 return ptr; 01324 } 01325 01326 uint8_t *thread_joiner_application_pending_config_tlv_list_get(uint8_t interface_id, uint16_t *length) 01327 { 01328 uint16_t data_list_len = 0; 01329 uint8_t *result_ptr; 01330 uint8_t *return_ptr; 01331 01332 thread_joiner_t *this = thread_joiner_find(interface_id); 01333 if (!this || !this->pending_configuration_ptr) { 01334 return NULL; 01335 } 01336 *length = 0; 01337 thread_meshcop_tlv_list_generate(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, NULL, &data_list_len); 01338 if (data_list_len == 0) { 01339 return NULL; 01340 } 01341 01342 /* Add also room for pending timestamp */ 01343 *length = data_list_len + 1; 01344 result_ptr = return_ptr = ns_dyn_mem_alloc(*length); 01345 01346 if (!result_ptr) { 01347 return NULL; 01348 } 01349 01350 *result_ptr++ = MESHCOP_TLV_PENDING_TIMESTAMP; 01351 01352 thread_meshcop_tlv_list_generate(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, result_ptr, &data_list_len); 01353 01354 return return_ptr; 01355 } 01356 01357 void thread_joiner_application_pending_config_add_missing_fields(uint8_t interface_id) 01358 { 01359 thread_joiner_t *this = thread_joiner_find(interface_id); 01360 if (!this || !this->pending_configuration_ptr) { 01361 return; 01362 } 01363 //TODO Specification open here 01364 // a) copy only mandatory fields 01365 // b) copy everything but remove zero length tlvs 01366 //configuration_set_copy_mandatory(this->pending_configuration_ptr, this->active_configuration_ptr); 01367 configuration_set_copy_missing(this->pending_configuration_ptr, this->active_configuration_ptr); 01368 configuration_set_remove_null_tlv(this->pending_configuration_ptr); 01369 } 01370 01371 01372 bool thread_joiner_application_old_config_exists(int8_t interface_id) 01373 { 01374 thread_joiner_t *this = thread_joiner_find(interface_id); 01375 if (!this || !this->old_active_configuration_ptr) { 01376 return false; 01377 } 01378 return true; 01379 } 01380 void thread_joiner_application_old_config_delete(int8_t interface_id) 01381 { 01382 thread_joiner_t *this = thread_joiner_find(interface_id); 01383 if (!this || !this->old_active_configuration_ptr) { 01384 return; 01385 } 01386 ns_dyn_mem_free(this->old_active_configuration_ptr); 01387 this->old_active_configuration_ptr = NULL; 01388 01389 return; 01390 } 01391 int thread_joiner_application_old_config_activate(int8_t interface_id) 01392 { 01393 thread_joiner_t *this = thread_joiner_find(interface_id); 01394 if (!this || !this->old_active_configuration_ptr) { 01395 return -1; 01396 } 01397 this->active_configuration_ptr = this->old_active_configuration_ptr; 01398 this->old_active_configuration_ptr = NULL; 01399 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 01400 link_configuration_trace(this->configuration_ptr); 01401 01402 return 0; 01403 } 01404 01405 void thread_joiner_application_pending_config_delete(int8_t interface_id) 01406 { 01407 thread_joiner_t *this = thread_joiner_find(interface_id); 01408 if (!this || !this->pending_configuration_ptr) { 01409 return; 01410 } 01411 ns_dyn_mem_free(this->pending_configuration_ptr); 01412 this->pending_configuration_ptr = NULL; 01413 thread_joiner_application_configuration_nvm_save(interface_id); 01414 return; 01415 } 01416 01417 void thread_joiner_application_next_pending_config_save(int8_t interface_id) 01418 { 01419 thread_joiner_t *this = thread_joiner_find(interface_id); 01420 if (!this || !this->pending_configuration_ptr) { 01421 return; 01422 } 01423 this->next_pending_configuration_ptr = configuration_set_copy(this->pending_configuration_ptr); 01424 if (!this->next_pending_configuration_ptr) { 01425 tr_error("next pending configuration creation failed"); 01426 } 01427 return; 01428 } 01429 bool thread_joiner_application_next_pending_config_exists(int8_t interface_id) 01430 { 01431 thread_joiner_t *this = thread_joiner_find(interface_id); 01432 if (!this || !this->next_pending_configuration_ptr) { 01433 return false; 01434 } 01435 return true; 01436 } 01437 01438 uint16_t thread_joiner_application_next_pending_config_length(int8_t interface_id) 01439 { 01440 uint16_t response_len = 0; 01441 thread_joiner_t *this = thread_joiner_find(interface_id); 01442 if (!this || !this->next_pending_configuration_ptr) { 01443 return 0; 01444 } 01445 response_len += 2 + 8; // Pending timestamp 01446 response_len += 2 + 4; // delay timer 01447 response_len += this->next_pending_configuration_ptr->length; 01448 return response_len; 01449 } 01450 01451 uint8_t *thread_joiner_application_next_pending_config_build(int8_t interface_id, uint8_t *ptr) 01452 { 01453 thread_joiner_t *this = thread_joiner_find(interface_id); 01454 if (!this || !this->next_pending_configuration_ptr) { 01455 return ptr; 01456 } 01457 memcpy(ptr, this->next_pending_configuration_ptr->data, this->next_pending_configuration_ptr->length); 01458 ptr += this->next_pending_configuration_ptr->length; 01459 ptr = thread_meshcop_tlv_data_write_uint64(ptr, MESHCOP_TLV_PENDING_TIMESTAMP, this->next_pending_configuration_ptr->timestamp); 01460 ptr = thread_meshcop_tlv_data_write_uint32(ptr, MESHCOP_TLV_DELAY_TIMER, this->next_pending_configuration_ptr->timeout_in_ms); 01461 return ptr; 01462 } 01463 void thread_joiner_application_next_pending_config_delete(int8_t interface_id) 01464 { 01465 thread_joiner_t *this = thread_joiner_find(interface_id); 01466 if (!this || !this->next_pending_configuration_ptr) { 01467 return; 01468 } 01469 ns_dyn_mem_free(this->next_pending_configuration_ptr); 01470 this->next_pending_configuration_ptr = NULL; 01471 01472 return; 01473 } 01474 void thread_joiner_application_next_active_config_save(int8_t interface_id) 01475 { 01476 thread_joiner_t *this = thread_joiner_find(interface_id); 01477 if (!this || !this->configuration_ptr) { 01478 return; 01479 } 01480 this->next_active_configuration_ptr = configuration_set_copy(this->active_configuration_ptr); 01481 if (!this->next_active_configuration_ptr) { 01482 tr_error("next pending configuration creation failed"); 01483 return; 01484 } 01485 return; 01486 } 01487 bool thread_joiner_application_next_active_config_exists(int8_t interface_id) 01488 { 01489 thread_joiner_t *this = thread_joiner_find(interface_id); 01490 if (!this || !this->next_active_configuration_ptr) { 01491 return false; 01492 } 01493 return true; 01494 } 01495 uint16_t thread_joiner_application_next_active_config_length(int8_t interface_id) 01496 { 01497 thread_joiner_t *this = thread_joiner_find(interface_id); 01498 if (!this || !this->next_active_configuration_ptr) { 01499 return 0; 01500 } 01501 return this->next_active_configuration_ptr->length; 01502 } 01503 01504 uint8_t *thread_joiner_application_next_active_config_write(int8_t interface_id, uint8_t *ptr) 01505 { 01506 thread_joiner_t *this = thread_joiner_find(interface_id); 01507 if (!this || !this->next_active_configuration_ptr) { 01508 return ptr; 01509 } 01510 memcpy(ptr, this->next_active_configuration_ptr->data, this->next_active_configuration_ptr->length); 01511 ptr += this->next_active_configuration_ptr->length; 01512 return ptr; 01513 } 01514 01515 void thread_joiner_application_next_active_config_delete(int8_t interface_id) 01516 { 01517 thread_joiner_t *this = thread_joiner_find(interface_id); 01518 if (!this || !this->next_active_configuration_ptr) { 01519 return; 01520 } 01521 ns_dyn_mem_free(this->next_active_configuration_ptr); 01522 this->next_active_configuration_ptr = NULL; 01523 01524 return; 01525 } 01526 01527 device_configuration_s *thread_joiner_application_get_device_config(int8_t interface_id) 01528 { 01529 thread_joiner_t *this = thread_joiner_find(interface_id); 01530 if (!this) { 01531 return NULL; 01532 } 01533 return this->device_configuration_ptr; 01534 } 01535 01536 int thread_joiner_application_link_configuration_store(int8_t interface_id, link_configuration_s *link_config) 01537 { 01538 thread_joiner_t *this = thread_joiner_get(interface_id); 01539 01540 if (!link_config || !this) { 01541 return -1; 01542 } 01543 01544 if (!this->configuration_ptr) { 01545 this->configuration_ptr = link_configuration_create(); 01546 } 01547 01548 thread_joiner_application_validate_settings(this);// Generate all random information 01549 configuration_set_generate(this->interface_id, this->active_configuration_ptr, link_config); 01550 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 01551 this->configuration_ptr->key_sequence = link_config->key_sequence; 01552 this->configuration_valid = true; 01553 link_configuration_trace(this->configuration_ptr); 01554 01555 // store link configuration to NVM. This also stores pending configuration and some other parameters! 01556 return thread_joiner_application_configuration_nvm_save(this->interface_id); 01557 } 01558 01559 int thread_joiner_application_link_configuration_delete(int8_t interface_id) 01560 { 01561 thread_joiner_t *this = thread_joiner_get(interface_id); 01562 01563 // delete link configuration from NVM 01564 return thread_joiner_application_nvm_link_config_delete(this); 01565 } 01566 01567 bool thread_joiner_application_nvm_link_configuration_load(int8_t interface_id) 01568 { 01569 thread_joiner_t *this = thread_joiner_find(interface_id); 01570 if (this && this->nvm_link_configuration_load == true) { 01571 this->nvm_link_configuration_load = false; 01572 if (thread_joiner_application_nvm_link_config_read(this) == 0) { 01573 return true; 01574 } else { 01575 tr_error("Failed to read link configuration settings from NVM"); 01576 } 01577 } 01578 return false; 01579 } 01580 01581 int thread_joiner_application_provisioning_set(int8_t interface_id, thread_provisioning_status_e status) 01582 { 01583 thread_joiner_t *this = thread_joiner_find(interface_id); 01584 if (this) { 01585 this->provisioning_done = status; 01586 if (status == PROVISIONING_STATUS_REJECTED) { 01587 // If commissioner rejects us retry done after some time -> state is changed back to not done 01588 this->provisioning_timeout = randLIB_get_random_in_range(20, 120); 01589 } else { 01590 this->provisioning_timeout = 0; 01591 } 01592 } 01593 return 0; 01594 } 01595 01596 thread_provisioning_status_e thread_joiner_application_provisioning_get(int8_t interface_id) 01597 { 01598 thread_joiner_t *this = thread_joiner_find(interface_id); 01599 if (this) { 01600 return this->provisioning_done; 01601 } 01602 return PROVISIONING_STATUS_NOT_DONE; 01603 } 01604 01605 static int joiner_application_security_start_cb(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t *pw, uint8_t *pw_len) 01606 { 01607 int ret = -1; 01608 tr_debug("Thread joiner security started"); 01609 (void)address; 01610 (void)port; 01611 01612 thread_joiner_t *this = thread_joiner_find_by_service(service_id); 01613 01614 if (this) { 01615 memcpy(pw, this->device_configuration_ptr->PSKd_ptr, this->device_configuration_ptr->PSKd_len); 01616 *pw_len = this->device_configuration_ptr->PSKd_len; 01617 ret = 0; 01618 // ret = coap_service_security_key_set( service_id, address, port, 01619 // this->device_configuration_ptr->PSKd_ptr, 01620 // this->device_configuration_ptr->PSKd_len ); 01621 } 01622 01623 return ret; 01624 } 01625 01626 int joiner_application_security_done_cb(int8_t service_id, uint8_t address[16], uint8_t keyblock[40]) 01627 { 01628 thread_joiner_t *this = thread_joiner_find_by_service(service_id); 01629 uint8_t kek[32]; 01630 int ret; 01631 01632 tr_debug("Thread joiner security done service: %d, address: %s", service_id, trace_ipv6(address)); 01633 if (!this) { 01634 return -1; 01635 } 01636 01637 ns_sha256(keyblock, 40, kek); 01638 01639 ret = thread_commissioning_if_pairwise_key_add(this->interface_id, 10000, &address[8], kek); 01640 if (ret) { 01641 tr_debug("pairwise key set failed %d", ret); 01642 //TODO error? 01643 } 01644 thread_commissioning_if_enable_security(this->interface_id); 01645 return 0; 01646 } 01647 01648 static void thread_joiner_attach_cb(void *arg) 01649 { 01650 thread_joiner_t *this = arg; 01651 tr_debug("Attach to new network"); 01652 if (!this) { 01653 return; 01654 } 01655 // Cleaning up the joining information 01656 thread_joiner_application_commission_clean(this); 01657 if (this->done_cb) {// This is successfull 01658 this->done_cb(this->interface_id); 01659 } 01660 } 01661 static void thread_joiner_entrust_timeout_cb(void *arg) 01662 { 01663 thread_joiner_t *this = arg; 01664 tr_debug("No valid configuration received in time"); 01665 if (!this) { 01666 return; 01667 } 01668 // Cleaning up the joining information 01669 thread_joiner_application_commission_clean(this); 01670 if (this->done_cb) {// Failed 01671 this->done_cb(this->interface_id); 01672 } 01673 } 01674 01675 void thread_joiner_attach_if_needed(thread_joiner_t *this) 01676 { 01677 tr_debug("attach check"); 01678 if (this->finalisation_done && this->configuration_valid) { 01679 tr_debug("Start attach timer");// one second timer gives time for joiner router to get entrust response 01680 this->attach_timeout = eventOS_timeout_ms(thread_joiner_attach_cb, 1000, this); 01681 } else { 01682 tr_debug("Start entrust timeout");// 30 timer to get credentials 01683 this->entrust_timeout = eventOS_timeout_ms(thread_joiner_entrust_timeout_cb, 30000, this); 01684 } 01685 } 01686 01687 01688 int thread_joiner_application_finalisation_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 01689 { 01690 thread_joiner_t *this = thread_joiner_find_by_service(service_id); 01691 uint8_t result; 01692 (void)source_address; 01693 (void)source_port; 01694 01695 tr_debug("finalisation done"); 01696 01697 if (!this) { 01698 return -1; 01699 } 01700 01701 // CoAP message failed - try to reattach 01702 if (!response_ptr || !response_ptr->payload_ptr) { 01703 tr_debug("finalisation failed - no response"); 01704 goto error; 01705 } 01706 01707 thci_trace("Device - Joiner|Direction - recv|EUI - %s|Type - JOIN_FIN.resp|Length - %d|Payload - %s", trace_array(this->device_configuration_ptr->eui64, 8), response_ptr->payload_len, trace_array(response_ptr->payload_ptr, response_ptr->payload_len)); 01708 coap_service_close_secure_connection(service_id, this->parent_address, this->parent_port); 01709 // todo: free certificates 01710 if (1 <= thread_tmfcop_tlv_data_get_uint8(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &result)) { 01711 //Todo make attach 01712 this->finalisation_done = true; 01713 this->provisioning_done = PROVISIONING_STATUS_NOT_DONE; 01714 if (result == 1) { 01715 // If accepted no additional actions needed 01716 tr_debug("Provisioning done"); 01717 this->provisioning_done = PROVISIONING_STATUS_DONE; 01718 } 01719 thread_joiner_attach_if_needed(this); 01720 return 0; 01721 } 01722 thci_trace("joinerError"); 01723 tr_debug("finalisation rejected"); 01724 01725 error: 01726 //TODO cant delete as old configuration pointer is in use I quess 01727 // link_configuration_delete(this->configuration_ptr); 01728 thread_joiner_application_commission_clean(this); 01729 this->configuration_valid = false; 01730 this->done_cb(this->interface_id); 01731 blacklist_update(source_address, false); 01732 //This trigger re scan and we try to connect again 01733 //TODO this needs status code to allow blacklisting of thread network 01734 return 0; 01735 } 01736 static int thread_joiner_application_send_finalisation(thread_joiner_t *this, uint8_t parent_address[16], uint16_t port) 01737 { 01738 uint8_t *ptr, *data_ptr; 01739 uint16_t length; 01740 01741 tr_debug("Thread joiner finalisation send"); 01742 length = thread_joiner_application_device_configuration_length(this->device_configuration_ptr); 01743 length += 3;// State 01744 01745 data_ptr = ptr = ns_dyn_mem_alloc(length); 01746 if (!ptr) { 01747 tr_error("Failed to start Commissioning"); 01748 return -1; 01749 } 01750 ptr = thread_joiner_application_device_configuration_build(ptr, this->device_configuration_ptr); 01751 ptr = thread_tmfcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 0xff); 01752 01753 thci_trace("Device - Joiner|Direction - sent|EUI - %s|Type - JOIN_FIN.req|Length - %d|Payload - %s", trace_array(this->device_configuration_ptr->eui64, 8), (int)(ptr - data_ptr), trace_array(data_ptr, ptr - data_ptr)); 01754 coap_service_request_send(this->secure_coap_service_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, parent_address, port, 01755 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_JOINER_FINALIZATION, COAP_CT_OCTET_STREAM, data_ptr, ptr - data_ptr, thread_joiner_application_finalisation_cb); 01756 01757 ns_dyn_mem_free(data_ptr); 01758 01759 return 0; 01760 } 01761 01762 static uint8_t *thread_joiner_application_write_channel(uint8_t *ptr, uint16_t data) 01763 { 01764 *ptr++ = MESHCOP_TLV_CHANNEL; // type 01765 *ptr++ = 3; // length 01766 *ptr++ = 0; // channel page 01767 return common_write_16_bit(data, ptr); 01768 } 01769 01770 static int thread_joiner_application_entrust_recv_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr) 01771 { 01772 thread_joiner_t *this = thread_joiner_find_by_service(service_id); 01773 (void)source_address; 01774 (void)source_port; 01775 01776 if (!this) { 01777 return -1; 01778 } 01779 01780 if (thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MASTER_KEY, NULL) < 16 || 01781 thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, NULL) < 8 || 01782 thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_XPANID, NULL) < 8 || 01783 thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_NAME, NULL) == 0 || 01784 thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_PSKC, NULL) < 16) { 01785 // Absolutely minimum we must have is master secret to attach. 01786 // If commissioner wants to be connected we must have PSKc,Name,Xpanid 01787 // If there is some fields missing we could attach, but timestamp must be set to 0 which will then cause synchronization 01788 tr_debug("Not include all TLv's"); 01789 thci_trace("joinerError"); 01790 return -1; 01791 } 01792 uint8_t *result_ptr; 01793 memcpy(this->active_configuration_ptr->data, request_ptr->payload_ptr, request_ptr->payload_len); 01794 this->active_configuration_ptr->length = request_ptr->payload_len; 01795 01796 result_ptr = this->active_configuration_ptr->data + this->active_configuration_ptr->length; 01797 01798 if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, NULL) == 0) { 01799 result_ptr = thread_meshcop_tlv_data_write_uint64(result_ptr, MESHCOP_TLV_ACTIVE_TIME_STAMP, 0); 01800 } 01801 if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_XPANID, NULL) == 0) { 01802 result_ptr = thread_meshcop_tlv_data_write(result_ptr, MESHCOP_TLV_XPANID, 8, this->configuration_ptr->extented_pan_id); 01803 } 01804 if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_CHANNEL, NULL) == 0) { 01805 result_ptr = thread_joiner_application_write_channel(result_ptr, this->configuration_ptr->rfChannel); 01806 } 01807 if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_PANID, NULL) == 0) { 01808 result_ptr = thread_meshcop_tlv_data_write_uint16(result_ptr, MESHCOP_TLV_PANID, this->configuration_ptr->panId); 01809 } 01810 01811 this->active_configuration_ptr->length = result_ptr - this->active_configuration_ptr->data; 01812 01813 // check if everything is present 01814 if (!thread_meshcop_tlv_list_present(this->active_configuration_ptr->data, this->active_configuration_ptr->length, mle_active_configuration_dataset_tlvs, sizeof(mle_active_configuration_dataset_tlvs))) { 01815 // Some fields are missing we need to sync settings during attach 01816 uint8_t *timestamp_ptr = NULL; 01817 thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, ×tamp_ptr); 01818 if (timestamp_ptr) { 01819 common_write_64_bit(0, timestamp_ptr); 01820 } 01821 } 01822 01823 thread_meshcop_tlv_data_get_uint64(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, &this->active_configuration_ptr->timestamp); 01824 01825 uint32_t network_key_seq = 0; 01826 if (thread_meshcop_tlv_data_get_uint32(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_KEY_SEQUENCE, &network_key_seq)) { 01827 this->configuration_ptr->key_sequence = network_key_seq; 01828 } 01829 01830 /*We must null out the master secret*/ 01831 #ifdef THREAD_THCI_SUPPORT 01832 uint8_t *master_secret_ptr; 01833 if (thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MASTER_KEY, &master_secret_ptr) >= 16) { 01834 memset(master_secret_ptr, 0, 16); 01835 } 01836 thci_trace("Device - Joiner|Direction - recv|EUI - %s|Type - JOIN_ent.req|Length - %d|Payload - %s", trace_array(this->device_configuration_ptr->eui64, 8), request_ptr->payload_len, trace_array(request_ptr->payload_ptr, request_ptr->payload_len)); 01837 #endif 01838 01839 // save link configuration to NVM 01840 01841 thci_trace("joinerAccepted"); 01842 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 01843 this->configuration_valid = true; 01844 thread_joiner_application_configuration_nvm_save(this->interface_id); 01845 01846 link_configuration_trace(this->configuration_ptr); 01847 01848 #ifdef THREAD_THCI_SUPPORT 01849 thci_trace("Device - Joiner|Direction - sent|EUI - %s|Type - JOIN_ent.resp|Length - 0|Payload - ", trace_array(this->device_configuration_ptr->eui64, 8)); 01850 #endif 01851 coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, NULL, 0); 01852 01853 //TODO Add delay timer of 3 seconds and then do attach 01854 thread_joiner_attach_if_needed(this); 01855 01856 return 0; 01857 } 01858 01859 int thread_joiner_application_pskd_commission_start(int8_t interface_id, uint8_t parent_address[16], uint16_t joiner_port, uint16_t panid, uint8_t xpanid[8], uint8_t channel, thread_commission_done_cb *done_cb) 01860 { 01861 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 01862 thread_joiner_t *this = thread_joiner_find(interface_id); 01863 if (!this || !done_cb || !cur) { 01864 return -1; 01865 } 01866 if (!this->configuration_ptr) { 01867 this->configuration_ptr = link_configuration_create(); 01868 } 01869 01870 if (!this->configuration_ptr) { 01871 tr_error("Commission start failed"); 01872 return -2; 01873 } 01874 this->configuration_valid = false; 01875 01876 01877 this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); 01878 coap_service_register_uri(this->coap_service_id, THREAD_URI_JOINER_ENTRUST, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_joiner_application_entrust_recv_cb); 01879 01880 this->secure_coap_service_id = coap_service_initialize(this->interface_id, THREAD_DEFAULT_JOINER_PORT, COAP_SERVICE_OPTIONS_EPHEMERAL_PORT | COAP_SERVICE_OPTIONS_SECURE | 0x80, joiner_application_security_start_cb, joiner_application_security_done_cb); 01881 01882 tr_debug("start pskd commissioning: interface %d, parent: %s, port %d", interface_id, trace_ipv6(parent_address), joiner_port); 01883 // save initial information 01884 this->configuration_ptr->panId = panid; 01885 this->configuration_ptr->rfChannel = channel; 01886 if (xpanid) { 01887 memcpy(this->configuration_ptr->extented_pan_id, xpanid, 8); 01888 } 01889 01890 link_configuration_trace(this->configuration_ptr); 01891 //TODO this callback needs status for blacklist 01892 this->done_cb = done_cb; 01893 memcpy(this->parent_address, parent_address, 16); 01894 this->parent_port = joiner_port; 01895 01896 thci_trace("joinerDtlsSessionStarted"); 01897 thread_joiner_application_send_finalisation(this, parent_address, joiner_port); 01898 return 0; 01899 } 01900 01901 int thread_joiner_application_configuration_nvm_save(int8_t interface_id) 01902 { 01903 tr_info("thread_joiner_application_configuration_nvm_save"); 01904 01905 thread_joiner_t *this = thread_joiner_find(interface_id); 01906 if (!this) { 01907 return -1; 01908 } 01909 01910 thread_nvm_store_device_configuration_write(this->device_configuration_ptr->extended_random_mac, this->device_configuration_ptr->mesh_local_eid); 01911 thread_nvm_store_pending_configuration_write(this->pending_configuration_ptr, sizeof(configuration_set_t)); 01912 thread_nvm_store_seq_counter_write(this->configuration_ptr->key_sequence); 01913 thread_nvm_store_active_configuration_write(this->active_configuration_ptr, sizeof(configuration_set_t)); 01914 01915 /* allow configuration to be read in bootstrap */ 01916 this->nvm_link_configuration_load = true; 01917 return 0; 01918 } 01919 01920 int thread_joiner_application_update_configuration(uint8_t interface_id, uint8_t *msg_ptr, uint16_t msg_len, bool include_missing_tlvs) 01921 { 01922 thread_joiner_t *this = thread_joiner_find(interface_id); 01923 configuration_set_t *configuration_ptr; 01924 if (!this) { 01925 return -1; 01926 } 01927 configuration_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t)); 01928 if (!configuration_ptr) { 01929 return -2; 01930 } 01931 memcpy(configuration_ptr, this->active_configuration_ptr, sizeof(configuration_set_t)); 01932 this->active_configuration_ptr->length = 0; 01933 configuration_set_add_all_fields(this->active_configuration_ptr, msg_ptr, msg_len, meshcop_active_set_ignore, sizeof(meshcop_active_set_ignore)); 01934 if (include_missing_tlvs) { 01935 configuration_set_copy_missing(this->active_configuration_ptr, configuration_ptr); 01936 configuration_set_remove_null_tlv(this->active_configuration_ptr); 01937 } else { 01938 configuration_set_copy_mandatory(this->active_configuration_ptr, configuration_ptr); 01939 } 01940 thread_meshcop_tlv_data_get_uint64(msg_ptr, msg_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &this->active_configuration_ptr->timestamp); 01941 link_configuration_update(this->configuration_ptr, msg_ptr, msg_len); 01942 // allow 5 seconds delay before state change for data response propagation 01943 thread_router_bootstrap_delay_reed_jitter(interface_id, 5); 01944 ns_dyn_mem_free(configuration_ptr); 01945 thread_joiner_application_configuration_nvm_save(interface_id); 01946 01947 return 0; 01948 } 01949 uint8_t *thread_joiner_application_active_config_tlv_list_get(uint8_t interface_id, uint16_t *length) 01950 { 01951 uint8_t *result_ptr; 01952 thread_joiner_t *this = thread_joiner_find(interface_id); 01953 if (!this || !this->active_configuration_ptr) { 01954 return NULL; 01955 } 01956 *length = 0; 01957 thread_meshcop_tlv_list_generate(this->active_configuration_ptr->data, this->active_configuration_ptr->length, NULL, length); 01958 if (*length == 0) { 01959 return NULL; 01960 } 01961 result_ptr = ns_dyn_mem_alloc(*length); 01962 if (!result_ptr) { 01963 } 01964 thread_meshcop_tlv_list_generate(this->active_configuration_ptr->data, this->active_configuration_ptr->length, result_ptr, length); 01965 01966 return result_ptr; 01967 } 01968 uint8_t *thread_joiner_application_active_config_params_get(uint8_t interface_id, uint16_t *length) 01969 { 01970 thread_joiner_t *this = thread_joiner_find(interface_id); 01971 if (!this || !this->active_configuration_ptr || !length) { 01972 return NULL; 01973 } 01974 *length = this->active_configuration_ptr->length; 01975 return this->active_configuration_ptr->data; 01976 } 01977 01978 uint16_t thread_joiner_application_active_config_length(uint8_t interface_id, const uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 01979 { 01980 thread_joiner_t *this = thread_joiner_find(interface_id); 01981 if (!this || !this->active_configuration_ptr) { 01982 return 0; 01983 } 01984 return configuration_set_length(this->active_configuration_ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len); 01985 } 01986 01987 uint8_t *thread_joiner_application_active_config_write(uint8_t interface_id, uint8_t *ptr, const uint8_t *req_tlv_ptr, uint8_t req_tlv_len, const uint8_t *ignored_tlv_ptr, uint8_t ignored_tlv_len) 01988 { 01989 thread_joiner_t *this = thread_joiner_find(interface_id); 01990 if (!this || !this->active_configuration_ptr) { 01991 return ptr; 01992 } 01993 return configuration_set_write(this->active_configuration_ptr, ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len); 01994 } 01995 01996 int thread_joiner_application_device_configuration_length(device_configuration_s *device_configuration) 01997 { 01998 int length; 01999 02000 if (!device_configuration) { 02001 return 0; 02002 } 02003 length = 2 + 1 + 2 + 6 + 2 + device_configuration->vendor_data_len;// Status + Stack version + vendor data 02004 if (device_configuration->provisioning_uri_ptr) { 02005 length += 2 + strlen(device_configuration->provisioning_uri_ptr); 02006 } 02007 if (device_configuration->vendor_name_ptr) { 02008 length += 2 + strlen(device_configuration->vendor_name_ptr); 02009 } 02010 if (device_configuration->vendor_model_ptr) { 02011 length += 2 + strlen(device_configuration->vendor_model_ptr); 02012 } 02013 if (device_configuration->vendor_sw_version_ptr) { 02014 length += 2 + strlen(device_configuration->vendor_sw_version_ptr); 02015 } 02016 return length; 02017 } 02018 02019 uint8_t *thread_joiner_application_device_configuration_build(uint8_t *ptr, device_configuration_s *device_configuration) 02020 { 02021 if (!ptr || !device_configuration) { 02022 return ptr; 02023 } 02024 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_STACK_VERSION, 6, device_configuration->vendor_stack_version); 02025 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_DATA, 02026 device_configuration->vendor_data_len, 02027 device_configuration->vendor_data_ptr); 02028 02029 if (device_configuration->provisioning_uri_ptr) { 02030 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_PROVISIONING_URL, 02031 strlen(device_configuration->provisioning_uri_ptr), 02032 (uint8_t *)device_configuration->provisioning_uri_ptr); 02033 } 02034 if (device_configuration->vendor_name_ptr) { 02035 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_NAME, 02036 strlen(device_configuration->vendor_name_ptr), 02037 (uint8_t *)device_configuration->vendor_name_ptr); 02038 } 02039 if (device_configuration->vendor_model_ptr) { 02040 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_MODEL, 02041 strlen(device_configuration->vendor_model_ptr), 02042 (uint8_t *)device_configuration->vendor_model_ptr); 02043 } 02044 if (device_configuration->vendor_sw_version_ptr) { 02045 ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_SW_VERSION, 02046 strlen(device_configuration->vendor_sw_version_ptr), 02047 (uint8_t *)device_configuration->vendor_sw_version_ptr); 02048 } 02049 return ptr; 02050 } 02051 02052 int8_t thread_joiner_application_active_configuration_update(int8_t interface_id, uint8_t *data_ptr, uint16_t data_len, const uint8_t *ignore_ptr, uint8_t ingore_len) 02053 { 02054 thread_joiner_t *this = thread_joiner_find(interface_id); 02055 uint64_t timestamp = 0; 02056 02057 if (!this) { 02058 return -1; 02059 } 02060 configuration_set_add_all_fields(this->active_configuration_ptr, data_ptr, data_len, ignore_ptr, ingore_len); 02061 thread_meshcop_tlv_data_get_uint64(data_ptr, data_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, ×tamp); 02062 thread_joiner_application_active_timestamp_set(this->interface_id, timestamp); 02063 link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length); 02064 this->configuration_valid = true; 02065 thread_joiner_application_configuration_nvm_save(this->interface_id); 02066 02067 link_configuration_trace(this->configuration_ptr); 02068 02069 return 0; 02070 } 02071 #endif 02072
Generated on Tue Jul 12 2022 13:54:58 by
1.7.2