Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_joiner_application.c Source File

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, &timestamp_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, &timestamp_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, &timestamp);
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