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