Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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 static int thread_joiner_application_nvm_link_config_read(thread_joiner_t *this) {
00921 
00922     // read config from NVM, in case of failure current settings are unchanged.
00923     int nvm_read_status = thread_nvm_store_active_configuration_read(this->active_configuration_ptr, sizeof(configuration_set_t));
00924     tr_debug("active conf read %d", nvm_read_status);
00925     // validate that active configuration settings are valid, even if we couldn't read from nvm.
00926     if(!configuration_set_validate(this->active_configuration_ptr->data, this->active_configuration_ptr->length, true)) {
00927         tr_debug("No active configuration avail");
00928         return -1;
00929     }
00930     link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length);
00931 
00932     thread_nvm_fast_data_t fast_data;
00933     memset(&fast_data,0,sizeof(thread_nvm_fast_data_t));
00934     int fast_data_read_ret = thread_nvm_store_fast_data_read(&fast_data);
00935     tr_info("From NVM %d", fast_data_read_ret);
00936     tr_info("mac-counter %"PRIu32,fast_data.mac_frame_counter);
00937     tr_info("mle-counter %"PRIu32,fast_data.mle_frame_counter);
00938     tr_info("seq-counter %"PRIu32,fast_data.seq_counter);
00939 
00940     if (THREAD_NVM_FILE_SUCCESS == fast_data_read_ret) {
00941         if (this->configuration_ptr->key_sequence < fast_data.seq_counter) {
00942             this->configuration_ptr->key_sequence = fast_data.seq_counter;
00943         }
00944     }
00945 
00946     fast_data.mac_frame_counter += MAC_FRAME_COUNTER_LIMIT;
00947     fast_data.mle_frame_counter += MLE_FRAME_COUNTER_LIMIT;
00948     thread_nvm_store_fast_data_write(&fast_data);
00949 
00950     thread_nvm_store_device_configuration_read(this->device_configuration_ptr->extended_random_mac,this->device_configuration_ptr->mesh_local_eid);
00951     thread_nvm_store_link_info_read();
00952     // Generate all random information, if device configuration read failed then the random mac and eid are created.
00953     bool new_value_generated = thread_joiner_application_validate_settings(this);
00954     if (new_value_generated) {
00955         thread_nvm_store_device_configuration_write(this->device_configuration_ptr->extended_random_mac,this->device_configuration_ptr->mesh_local_eid);
00956     }
00957 
00958     this->configuration_valid = true;
00959     link_configuration_trace(this->configuration_ptr);
00960 
00961     //Add Security to MLE service
00962     uint8_t key_material[32];
00963     uint8_t key_index;
00964     //Define KEY's
00965 
00966     thread_key_get(this->configuration_ptr->master_key, key_material, this->configuration_ptr->key_sequence);
00967     key_index = THREAD_KEY_INDEX(this->configuration_ptr->key_sequence);
00968     //Set Keys
00969     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00970     mac_helper_security_default_key_set(cur, &key_material[16], key_index, MAC_KEY_ID_MODE_IDX);
00971     mle_service_security_set_security_key(this->interface_id, key_material, key_index, true);
00972     // update counters
00973     mle_service_security_set_frame_counter(this->interface_id, fast_data.mle_frame_counter);
00974     mac_helper_link_frame_counter_set(this->interface_id, fast_data.mac_frame_counter);
00975 
00976     // this saves all configurations
00977     if (THREAD_NVM_FILE_SUCCESS!=nvm_read_status) {
00978         thread_joiner_application_configuration_nvm_save(this->interface_id);
00979     }
00980     else {
00981         tr_info("Reading pending set");
00982         configuration_set_t *pend_conf_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t));
00983         if (pend_conf_ptr) {
00984             memset(pend_conf_ptr, 0, sizeof(configuration_set_t));
00985             int pending_ret = thread_nvm_store_pending_configuration_read(pend_conf_ptr, sizeof(configuration_set_t));
00986             if(THREAD_NVM_FILE_SUCCESS==pending_ret) {
00987                 if (this->pending_configuration_ptr) {
00988                     ns_dyn_mem_free(this->pending_configuration_ptr);
00989                 }
00990                 this->pending_configuration_ptr = pend_conf_ptr;
00991                 this->pending_configuration_ptr->timeout_in_ms = 0;
00992                 this->pending_set_in_sync = false;
00993             }
00994             else {
00995                 tr_info("Reading pending from NVM error:%d", pending_ret);
00996                 ns_dyn_mem_free(pend_conf_ptr);
00997             }
00998         }
00999     }
01000     this->nvm_link_configuration_load = false;
01001     return 0;
01002 }
01003 
01004 static int thread_joiner_application_nvm_link_config_delete(thread_joiner_t *this)
01005 {
01006     if (!this) {
01007         return -1;
01008     }
01009     int ret = thread_nvm_store_pending_configuration_remove();
01010 
01011     if (ret!=THREAD_NVM_FILE_SUCCESS) {
01012         tr_error("Pending configuration delete error: %d", ret);
01013     }
01014 
01015     ret = thread_nvm_store_active_configuration_remove();
01016 
01017     if (ret!=THREAD_NVM_FILE_SUCCESS) {
01018         tr_error("Active configuration delete error: %d", ret);
01019     }
01020 
01021     // delete link configuration from cache, device will be restarted after settings are deleted
01022     this->configuration_valid = false;
01023     return 0;
01024 }
01025 
01026 uint64_t thread_joiner_application_active_timestamp_get(int8_t interface_id)
01027 {
01028     thread_joiner_t *this = thread_joiner_find(interface_id);
01029     if (!this) {
01030         return 0;
01031     }
01032 
01033     return this->configuration_ptr->timestamp;
01034 }
01035 
01036 uint8_t thread_joiner_application_security_policy_get(int8_t interface_id)
01037 {
01038     thread_joiner_t *this = thread_joiner_find(interface_id);
01039     if (!this) {
01040         return 0;
01041     }
01042 
01043     return this->configuration_ptr->securityPolicy;
01044 }
01045 
01046 uint8_t *thread_joiner_application_random_mac_get(int8_t interface_id)
01047 {
01048     thread_joiner_t *this = thread_joiner_find(interface_id);
01049     if (!this || !this->device_configuration_ptr) {
01050         tr_error("thread_joiner_application_random_mac_get NULL parameter ");
01051         return (uint8_t*)ADDR_UNSPECIFIED;
01052     }
01053     return this->device_configuration_ptr->extended_random_mac;
01054 }
01055 uint8_t *thread_joiner_application_ml_eid_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_ml_eid_get parameter NULL");
01060         return (uint8_t*)ADDR_UNSPECIFIED;
01061     }
01062     return this->device_configuration_ptr->mesh_local_eid;
01063 }
01064 void thread_joiner_application_active_timestamp_set(int8_t interface_id, uint64_t timestamp)
01065 {
01066     thread_joiner_t *this = thread_joiner_find(interface_id);
01067     uint8_t *timestamp_ptr = NULL;
01068     if (!this) {
01069         return;
01070     }
01071 
01072     thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, &timestamp_ptr);
01073     if (timestamp_ptr) {
01074         common_write_64_bit(timestamp,timestamp_ptr);
01075     }
01076 
01077     //update timestamps in active configuration and link configuration
01078     this->active_configuration_ptr->timestamp = timestamp;
01079     this->configuration_ptr->timestamp = timestamp;
01080     return;
01081 }
01082 
01083 void thread_joiner_pending_config_activate(int8_t interface_id)
01084 {
01085     thread_joiner_t *this = thread_joiner_find(interface_id);
01086 
01087     if (!this || !this->pending_configuration_ptr) {
01088         tr_error("No pending configuration or joiner!");
01089         return;
01090     }
01091 
01092     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id);
01093 
01094     if (!cur) {
01095         tr_error("No interface information!");
01096         return;
01097     }
01098 
01099     /*
01100      * If pending configuration active timestamp is lower than current active timestamp allow pending configuration activation only
01101      * if master key is changed by the pending set
01102      */
01103     link_configuration_s *link_configuration = thread_joiner_application_get_config(interface_id);
01104 
01105     if (!link_configuration) {
01106         return;
01107     }
01108 
01109     // Validate new link configuration
01110     uint8_t *master_key_ptr = NULL;
01111     uint64_t pending_active_timestamp = 0;
01112     thread_meshcop_tlv_data_get_uint64(this->pending_configuration_ptr->data,this->pending_configuration_ptr->length,MESHCOP_TLV_ACTIVE_TIME_STAMP, &pending_active_timestamp);
01113     thread_meshcop_tlv_find(this->pending_configuration_ptr->data,this->pending_configuration_ptr->length,MESHCOP_TLV_NETWORK_MASTER_KEY,&master_key_ptr);
01114 
01115     if ((pending_active_timestamp < thread_joiner_application_active_timestamp_get(interface_id))) {
01116         // If new active timestamp is older than current master key must be changed.
01117         if (!master_key_ptr ||
01118             memcmp(master_key_ptr,link_configuration->master_key,16) == 0) {
01119             tr_info("*** Pending set activation aborted - device has newer active timestamp");
01120             thread_joiner_application_pending_config_delete(interface_id);
01121             return;
01122         }
01123     }
01124 
01125     if (master_key_ptr && memcmp(master_key_ptr,link_configuration->master_key,16) != 0) {
01126         this->configuration_ptr->key_sequence = 0;
01127         // if write fails, keep going...
01128         (void)thread_nvm_store_seq_counter_write(this->configuration_ptr->key_sequence);
01129     }
01130 
01131     tr_info("*** Activating pending configuration.");
01132 
01133     ns_dyn_mem_free(this->old_active_configuration_ptr);
01134     this->old_active_configuration_ptr = this->active_configuration_ptr;
01135     this->active_configuration_ptr = this->pending_configuration_ptr;
01136     this->active_configuration_ptr->timestamp = pending_active_timestamp;
01137     // All information is copied from old configuration so if configuration is corrupt we dont change anything.
01138     this->pending_configuration_ptr = NULL;
01139     (void)thread_nvm_store_pending_configuration_remove();
01140     configuration_set_copy_mandatory(this->active_configuration_ptr, this->old_active_configuration_ptr);
01141     link_configuration_update(this->configuration_ptr,this->active_configuration_ptr->data, this->active_configuration_ptr->length);
01142     link_configuration_trace(this->configuration_ptr);
01143 
01144     thread_joiner_application_configuration_nvm_save(this->interface_id);
01145 
01146 
01147     if (thread_link_configuration_activate(cur, this->configuration_ptr) != 0) {
01148         tr_error("Activating pending configuration failed.");
01149     }
01150 
01151     tr_info("*** Activating pending configuration done.");
01152 }
01153 
01154 
01155 void thread_joiner_application_seconds_timer(int8_t interface_id, uint32_t seconds)
01156 {
01157     thread_joiner_t *this = thread_joiner_find(interface_id);
01158     //tr_debug("seconds tick for joiner pending timeout in %d",this->pending_timeout_in_ms);
01159     if (!this) {
01160         return;
01161     }
01162     if (this->provisioning_timeout) {
01163         if (this->provisioning_timeout < seconds) {
01164             this->provisioning_done = PROVISIONING_STATUS_NOT_DONE;
01165         }
01166         this->provisioning_timeout -= seconds;
01167     }
01168     if (!this->pending_configuration_ptr || this->pending_configuration_ptr->timeout_in_ms == 0) {
01169         return;
01170     }
01171     if (this->pending_configuration_ptr->timeout_in_ms > seconds*1000) {
01172         this->pending_configuration_ptr->timeout_in_ms -= seconds*1000;
01173         return;
01174     }
01175     // Activate the pending config
01176     thread_joiner_pending_config_activate(interface_id);
01177 }
01178 
01179 int thread_joiner_application_pending_config_create(int8_t interface_id, uint8_t *data_ptr, uint16_t data_len)
01180 {
01181     thread_joiner_t *this = thread_joiner_find(interface_id);
01182     if (!this || data_len > MAX_OPERATIONAL_DATASET_SIZE) {
01183         return -1;
01184     }
01185     if(!this->pending_configuration_ptr){
01186         this->pending_configuration_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t));
01187     }
01188     if (!this->pending_configuration_ptr) {
01189         tr_error("pending configuration creation failed");
01190         return -2;
01191     }
01192     memset(this->pending_configuration_ptr, 0, sizeof(configuration_set_t));
01193     configuration_set_add_all_fields(this->pending_configuration_ptr,data_ptr,data_len, meshcop_pending_set_ignore, sizeof(meshcop_pending_set_ignore));
01194     return 0;
01195 }
01196 
01197 bool thread_joiner_application_pending_config_exists(int8_t interface_id)
01198 {
01199     thread_joiner_t *this = thread_joiner_find(interface_id);
01200     if (!this || !this->pending_configuration_ptr) {
01201         return false;
01202     }
01203     return true;
01204 }
01205 
01206 bool thread_joiner_application_pending_delay_timer_in_sync(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 this->pending_set_in_sync;
01213 }
01214 
01215 uint64_t thread_joiner_application_pending_config_timestamp_get(int8_t interface_id)
01216 {
01217     thread_joiner_t *this = thread_joiner_find(interface_id);
01218     if (!this || !this->pending_configuration_ptr || !this->pending_set_in_sync) {
01219         return 0;
01220     }
01221     return this->pending_configuration_ptr->timestamp;
01222 }
01223 
01224 int thread_joiner_application_pending_config_timestamp_set(int8_t interface_id, uint64_t timestamp)
01225 {
01226     thread_joiner_t *this = thread_joiner_find(interface_id);
01227     if (!this || !this->pending_configuration_ptr) {
01228         return -1;
01229     }
01230     this->pending_configuration_ptr->timestamp = timestamp;
01231     return 0;
01232 }
01233 
01234 
01235 int thread_joiner_application_pending_config_enable(int8_t interface_id, uint32_t timeout_in_ms)
01236 {
01237     thread_joiner_t *this = thread_joiner_find(interface_id);
01238     if (!this || !this->pending_configuration_ptr) {
01239         return -1;
01240     }
01241     this->pending_configuration_ptr->timeout_in_ms = timeout_in_ms;
01242     this->pending_set_in_sync = true;
01243 
01244     if(this->pending_configuration_ptr->timeout_in_ms > THREAD_MAX_DELAY_TIMER_SECONDS*1000) {
01245         this->pending_configuration_ptr->timeout_in_ms = THREAD_MAX_DELAY_TIMER_SECONDS*1000;
01246     }
01247     thread_joiner_application_configuration_nvm_save(this->interface_id);
01248 
01249     return 0;
01250 }
01251 
01252 uint32_t thread_joiner_application_pending_config_timeout_get(int8_t interface_id)
01253 {
01254     thread_joiner_t *this = thread_joiner_find(interface_id);
01255     if (!this || !this->pending_configuration_ptr) {
01256         return 0;
01257     }
01258     return this->pending_configuration_ptr->timeout_in_ms;
01259 }
01260 
01261 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)
01262 {
01263     uint16_t result_len;
01264     thread_joiner_t *this = thread_joiner_find(interface_id);
01265     if (!this || !this->pending_configuration_ptr) {
01266         return 0;
01267     }
01268 
01269     result_len = configuration_set_length(this->pending_configuration_ptr,req_tlv_ptr,req_tlv_len, ignored_tlv_ptr, ignored_tlv_len);
01270 
01271     /* Add pending timestamp if required and not ignored*/
01272     if (thread_meshcop_tlv_list_type_available(req_tlv_ptr, req_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP) &&
01273             !thread_meshcop_tlv_list_type_available(ignored_tlv_ptr, ignored_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP)) {
01274         result_len += 10;
01275     }
01276 
01277     /* Always add delay timer */
01278     result_len += 6;
01279 
01280     return result_len;
01281 }
01282 
01283 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)
01284 {
01285     thread_joiner_t *this = thread_joiner_find(interface_id);
01286     if (!this || !this->pending_configuration_ptr) {
01287         return ptr;
01288     }
01289 
01290     /* Build pending config data */
01291     ptr = configuration_set_write(this->pending_configuration_ptr, ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len);
01292 
01293     /* Add pending timestamp (len = 10) if required and not ignored */
01294     if (thread_meshcop_tlv_list_type_available(req_tlv_ptr, req_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP) &&
01295             !thread_meshcop_tlv_list_type_available(ignored_tlv_ptr, ignored_tlv_len, MESHCOP_TLV_PENDING_TIMESTAMP)) {
01296         ptr = thread_meshcop_tlv_data_write_uint64(ptr,MESHCOP_TLV_PENDING_TIMESTAMP, this->pending_configuration_ptr->timestamp);
01297     }
01298 
01299     /* Always add delay timer (len = 6) */
01300     ptr = thread_meshcop_tlv_data_write_uint32(ptr, MESHCOP_TLV_DELAY_TIMER, this->pending_configuration_ptr->timeout_in_ms);
01301 
01302     return ptr;
01303 }
01304 
01305 uint8_t *thread_joiner_application_pending_config_tlv_list_get(uint8_t interface_id, uint16_t *length)
01306 {
01307     uint16_t data_list_len = 0;
01308     uint8_t *result_ptr;
01309     uint8_t *return_ptr;
01310 
01311     thread_joiner_t *this = thread_joiner_find(interface_id);
01312     if (!this || !this->pending_configuration_ptr) {
01313         return NULL;
01314     }
01315     *length = 0;
01316     thread_meshcop_tlv_list_generate(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, NULL, &data_list_len);
01317     if (data_list_len == 0){
01318         return NULL;
01319     }
01320 
01321     /* Add also room for pending timestamp */
01322     *length = data_list_len + 1;
01323     result_ptr = return_ptr = ns_dyn_mem_alloc(*length);
01324 
01325     if (!result_ptr) {
01326         return NULL;
01327     }
01328 
01329     *result_ptr++ = MESHCOP_TLV_PENDING_TIMESTAMP;
01330 
01331     thread_meshcop_tlv_list_generate(this->pending_configuration_ptr->data, this->pending_configuration_ptr->length, result_ptr, &data_list_len);
01332 
01333     return return_ptr;
01334 }
01335 
01336 void thread_joiner_application_pending_config_add_missing_fields(uint8_t interface_id)
01337 {
01338     thread_joiner_t *this = thread_joiner_find(interface_id);
01339     if (!this || !this->pending_configuration_ptr) {
01340         return;
01341     }
01342     //TODO Specification open here
01343     // a) copy only mandatory fields
01344     // b) copy everything but remove zero length tlvs
01345     //configuration_set_copy_mandatory(this->pending_configuration_ptr, this->active_configuration_ptr);
01346     configuration_set_copy_missing(this->pending_configuration_ptr, this->active_configuration_ptr);
01347     configuration_set_remove_null_tlv(this->pending_configuration_ptr);
01348 }
01349 
01350 
01351 bool thread_joiner_application_old_config_exists(int8_t interface_id)
01352 {
01353     thread_joiner_t *this = thread_joiner_find(interface_id);
01354     if (!this || !this->old_active_configuration_ptr) {
01355         return false;
01356     }
01357     return true;
01358 }
01359 void thread_joiner_application_old_config_delete(int8_t interface_id)
01360 {
01361     thread_joiner_t *this = thread_joiner_find(interface_id);
01362     if (!this || !this->old_active_configuration_ptr) {
01363         return;
01364     }
01365     ns_dyn_mem_free(this->old_active_configuration_ptr);
01366     this->old_active_configuration_ptr = NULL;
01367 
01368     return;
01369 }
01370 int thread_joiner_application_old_config_activate(int8_t interface_id)
01371 {
01372     thread_joiner_t *this = thread_joiner_find(interface_id);
01373     if (!this || !this->old_active_configuration_ptr) {
01374         return -1;
01375     }
01376     this->active_configuration_ptr = this->old_active_configuration_ptr;
01377     this->old_active_configuration_ptr = NULL;
01378     link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length);
01379     link_configuration_trace(this->configuration_ptr);
01380 
01381     return 0;
01382 }
01383 
01384 void thread_joiner_application_pending_config_delete(int8_t interface_id)
01385 {
01386     thread_joiner_t *this = thread_joiner_find(interface_id);
01387     if (!this || !this->pending_configuration_ptr) {
01388         return;
01389     }
01390     ns_dyn_mem_free(this->pending_configuration_ptr);
01391     this->pending_configuration_ptr = NULL;
01392     thread_joiner_application_configuration_nvm_save(interface_id);
01393     return;
01394 }
01395 
01396 void thread_joiner_application_next_pending_config_save(int8_t interface_id)
01397 {
01398     thread_joiner_t *this = thread_joiner_find(interface_id);
01399     if (!this || !this->pending_configuration_ptr) {
01400         return;
01401     }
01402     this->next_pending_configuration_ptr = configuration_set_copy(this->pending_configuration_ptr);
01403     if (!this->next_pending_configuration_ptr) {
01404         tr_error("next pending configuration creation failed");
01405     }
01406     return;
01407 }
01408 bool thread_joiner_application_next_pending_config_exists(int8_t interface_id)
01409 {
01410     thread_joiner_t *this = thread_joiner_find(interface_id);
01411     if (!this || !this->next_pending_configuration_ptr) {
01412         return false;
01413     }
01414     return true;
01415 }
01416 
01417 uint16_t thread_joiner_application_next_pending_config_length(int8_t interface_id)
01418 {
01419     uint16_t response_len = 0;
01420     thread_joiner_t *this = thread_joiner_find(interface_id);
01421     if (!this || !this->next_pending_configuration_ptr) {
01422         return 0;
01423     }
01424     response_len += 2 + 8; // Pending timestamp
01425     response_len += 2 + 4;  // delay timer
01426     response_len += this->next_pending_configuration_ptr->length;
01427     return response_len;
01428 }
01429 
01430 uint8_t *thread_joiner_application_next_pending_config_build(int8_t interface_id, uint8_t *ptr)
01431 {
01432     thread_joiner_t *this = thread_joiner_find(interface_id);
01433     if (!this || !this->next_pending_configuration_ptr) {
01434         return ptr;
01435     }
01436     memcpy(ptr, this->next_pending_configuration_ptr->data, this->next_pending_configuration_ptr->length );
01437     ptr +=this->next_pending_configuration_ptr->length;
01438     ptr = thread_meshcop_tlv_data_write_uint64(ptr,MESHCOP_TLV_PENDING_TIMESTAMP, this->next_pending_configuration_ptr->timestamp);
01439     ptr = thread_meshcop_tlv_data_write_uint32(ptr,MESHCOP_TLV_DELAY_TIMER, this->next_pending_configuration_ptr->timeout_in_ms);
01440     return ptr;
01441 }
01442 void thread_joiner_application_next_pending_config_delete(int8_t interface_id)
01443 {
01444     thread_joiner_t *this = thread_joiner_find(interface_id);
01445     if (!this || !this->next_pending_configuration_ptr) {
01446         return;
01447     }
01448     ns_dyn_mem_free(this->next_pending_configuration_ptr);
01449     this->next_pending_configuration_ptr = NULL;
01450 
01451     return;
01452 }
01453 void thread_joiner_application_next_active_config_save(int8_t interface_id)
01454 {
01455     thread_joiner_t *this = thread_joiner_find(interface_id);
01456     if (!this || !this->configuration_ptr) {
01457         return;
01458     }
01459     this->next_active_configuration_ptr = configuration_set_copy(this->active_configuration_ptr);
01460     if (!this->next_active_configuration_ptr) {
01461         tr_error("next pending configuration creation failed");
01462         return;
01463     }
01464     return;
01465 }
01466 bool thread_joiner_application_next_active_config_exists(int8_t interface_id)
01467 {
01468     thread_joiner_t *this = thread_joiner_find(interface_id);
01469     if (!this || !this->next_active_configuration_ptr) {
01470         return false;
01471     }
01472     return true;
01473 }
01474 uint16_t thread_joiner_application_next_active_config_length(int8_t interface_id)
01475 {
01476     thread_joiner_t *this = thread_joiner_find(interface_id);
01477     if (!this || !this->next_active_configuration_ptr) {
01478         return 0;
01479     }
01480     return this->next_active_configuration_ptr->length;
01481 }
01482 
01483 uint8_t *thread_joiner_application_next_active_config_write(int8_t interface_id, uint8_t *ptr)
01484 {
01485     thread_joiner_t *this = thread_joiner_find(interface_id);
01486     if (!this || !this->next_active_configuration_ptr) {
01487         return ptr;
01488     }
01489     memcpy(ptr, this->next_active_configuration_ptr->data, this->next_active_configuration_ptr->length );
01490     ptr +=this->next_active_configuration_ptr->length;
01491     return ptr;
01492 }
01493 
01494 void thread_joiner_application_next_active_config_delete(int8_t interface_id)
01495 {
01496     thread_joiner_t *this = thread_joiner_find(interface_id);
01497     if (!this || !this->next_active_configuration_ptr) {
01498         return;
01499     }
01500     ns_dyn_mem_free(this->next_active_configuration_ptr);
01501     this->next_active_configuration_ptr = NULL;
01502 
01503     return;
01504 }
01505 
01506 device_configuration_s *thread_joiner_application_get_device_config(int8_t interface_id)
01507 {
01508     thread_joiner_t *this = thread_joiner_find(interface_id);
01509     if (!this) {
01510         return NULL;
01511     }
01512     return this->device_configuration_ptr;
01513 }
01514 
01515 int thread_joiner_application_link_configuration_store(int8_t interface_id, link_configuration_s *link_config)
01516 {
01517     thread_joiner_t *this = thread_joiner_get(interface_id);
01518 
01519     if (!link_config || !this) {
01520         return -1;
01521     }
01522 
01523     if (!this->configuration_ptr) {
01524             this->configuration_ptr = link_configuration_create();
01525         }
01526 
01527     thread_joiner_application_validate_settings(this);// Generate all random information
01528     configuration_set_generate(this->active_configuration_ptr, link_config);
01529     link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length);
01530     this->configuration_ptr->key_sequence = link_config->key_sequence;
01531     this->configuration_valid = true;
01532     link_configuration_trace(this->configuration_ptr);
01533 
01534     // store link configuration to NVM. This also stores pending configuration and some other parameters!
01535     return thread_joiner_application_configuration_nvm_save(this->interface_id);
01536 }
01537 
01538 int thread_joiner_application_link_configuration_delete(int8_t interface_id)
01539 {
01540     thread_joiner_t *this = thread_joiner_get(interface_id);
01541 
01542     // delete link configuration from NVM
01543     return thread_joiner_application_nvm_link_config_delete(this);
01544 }
01545 
01546 bool thread_joiner_application_nvm_link_configuration_load(int8_t interface_id)
01547 {
01548     thread_joiner_t *this = thread_joiner_find(interface_id);
01549     if (this && this->nvm_link_configuration_load == true) {
01550         this->nvm_link_configuration_load = false;
01551         if (thread_joiner_application_nvm_link_config_read(this) == 0) {
01552             return true;
01553         } else {
01554             tr_error("Failed to read link configuration settings from NVM");
01555         }
01556     }
01557     return false;
01558 }
01559 
01560 int thread_joiner_application_provisioning_set(int8_t interface_id, thread_provisioning_status_e status)
01561 {
01562     thread_joiner_t *this = thread_joiner_find(interface_id);
01563     if (this) {
01564         this->provisioning_done = status;
01565         if (status == PROVISIONING_STATUS_REJECTED) {
01566             // If commissioner rejects us retry done after some time -> state is changed back to not done
01567             this->provisioning_timeout = randLIB_get_random_in_range(20,120);
01568         } else {
01569             this->provisioning_timeout = 0;
01570         }
01571     }
01572     return 0;
01573 }
01574 
01575 thread_provisioning_status_e thread_joiner_application_provisioning_get(int8_t interface_id)
01576 {
01577     thread_joiner_t *this = thread_joiner_find(interface_id);
01578     if (this) {
01579         return this->provisioning_done;
01580     }
01581     return PROVISIONING_STATUS_NOT_DONE;
01582 }
01583 
01584 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)
01585 {
01586     int ret = -1;
01587     tr_debug("Thread joiner security started");
01588     (void)address;
01589     (void)port;
01590 
01591     thread_joiner_t *this = thread_joiner_find_by_service(service_id);
01592 
01593     if( this ){
01594         memcpy(pw, this->device_configuration_ptr->PSKd_ptr, this->device_configuration_ptr->PSKd_len );
01595         *pw_len = this->device_configuration_ptr->PSKd_len;
01596         ret = 0;
01597 //        ret = coap_service_security_key_set( service_id, address, port,
01598 //                                             this->device_configuration_ptr->PSKd_ptr,
01599 //                                             this->device_configuration_ptr->PSKd_len );
01600     }
01601 
01602     return ret;
01603 }
01604 
01605 int joiner_application_security_done_cb(int8_t service_id, uint8_t address[16], uint8_t keyblock[40])
01606 {
01607     thread_joiner_t *this = thread_joiner_find_by_service(service_id);
01608     uint8_t kek[32];
01609     int ret;
01610 
01611     tr_debug("Thread joiner security done service: %d, address: %s", service_id, trace_ipv6(address));
01612     if (!this) {
01613         return -1;
01614     }
01615 
01616     ns_sha256(keyblock, 40, kek);
01617 
01618     ret = thread_commissioning_if_pairwise_key_add(this->interface_id, 10000, &address[8], kek);
01619     if (ret) {
01620         tr_debug("pairwise key set failed %d", ret);
01621         //TODO error?
01622     }
01623     thread_commissioning_if_enable_security(this->interface_id);
01624     return 0;
01625 }
01626 
01627 static void thread_joiner_attach_cb(void* arg)
01628 {
01629     thread_joiner_t *this = arg;
01630     tr_debug("Attach to new network");
01631     if (!this){
01632         return;
01633     }
01634     // Cleaning up the joining information
01635     thread_joiner_application_commission_clean(this);
01636     if (this->done_cb) {// This is successfull
01637         this->done_cb(this->interface_id);
01638     }
01639 }
01640 static void thread_joiner_entrust_timeout_cb(void* arg)
01641 {
01642     thread_joiner_t *this = arg;
01643     tr_debug("No valid configuration received in time");
01644     if (!this){
01645         return;
01646     }
01647     // Cleaning up the joining information
01648     thread_joiner_application_commission_clean(this);
01649     if (this->done_cb) {// Failed
01650         this->done_cb(this->interface_id);
01651     }
01652 }
01653 
01654 void thread_joiner_attach_if_needed(thread_joiner_t *this)
01655 {
01656     tr_debug("attach check");
01657     if (this->finalisation_done && this->configuration_valid) {
01658         tr_debug("Start attach timer");// one second timer gives time for joiner router to get entrust response
01659         this->attach_timeout = eventOS_timeout_ms(thread_joiner_attach_cb, 1000, this);
01660     } else {
01661         tr_debug("Start entrust timeout");// 30 timer to get credentials
01662         this->entrust_timeout = eventOS_timeout_ms(thread_joiner_entrust_timeout_cb, 30000, this);
01663     }
01664 }
01665 
01666 
01667 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)
01668 {
01669     thread_joiner_t *this = thread_joiner_find_by_service(service_id);
01670     uint8_t result;
01671     (void)source_address;
01672     (void)source_port;
01673 
01674     tr_debug("finalisation done");
01675 
01676     if (!this) {
01677         return -1;
01678     }
01679 
01680     // CoAP message failed - try to reattach
01681     if(!response_ptr || !response_ptr->payload_ptr){
01682         tr_debug("finalisation failed - no response");
01683         goto error;
01684     }
01685 
01686     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));
01687     coap_service_close_secure_connection(service_id, this->parent_address, this->parent_port);
01688     // todo: free certificates
01689     if (1 <= thread_tmfcop_tlv_data_get_uint8(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &result)) {
01690         //Todo make attach
01691         this->finalisation_done = true;
01692         this->provisioning_done = PROVISIONING_STATUS_NOT_DONE;
01693         if (result == 1) {
01694             // If accepted no additional actions needed
01695             tr_debug("Provisioning done");
01696             this->provisioning_done = PROVISIONING_STATUS_DONE;
01697         }
01698         thread_joiner_attach_if_needed(this);
01699         return 0;
01700     }
01701     thci_trace("joinerError");
01702     tr_debug("finalisation rejected");
01703 
01704 error:
01705     //TODO cant delete as old configuration pointer is in use I quess
01706 //    link_configuration_delete(this->configuration_ptr);
01707     thread_joiner_application_commission_clean(this);
01708     this->configuration_valid = false;
01709     this->done_cb(this->interface_id);
01710     blacklist_update(source_address, false);
01711     //This trigger re scan and we try to connect again
01712     //TODO this needs status code to allow blacklisting of thread network
01713     return 0;
01714 }
01715 static int thread_joiner_application_send_finalisation(thread_joiner_t *this, uint8_t parent_address[16], uint16_t port)
01716 {
01717     uint8_t *ptr, *data_ptr;
01718     uint16_t length;
01719 
01720     tr_debug("Thread joiner finalisation send");
01721     length = thread_joiner_application_device_configuration_length(this->device_configuration_ptr);
01722     length += 3;// State
01723 
01724     data_ptr = ptr = ns_dyn_mem_alloc(length);
01725     if (!ptr) {
01726         tr_error("Failed to start Commissioning");
01727         return -1;
01728     }
01729     ptr = thread_joiner_application_device_configuration_build(ptr, this->device_configuration_ptr);
01730     ptr = thread_tmfcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 0xff);
01731 
01732     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));
01733     coap_service_request_send(this->secure_coap_service_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, parent_address, port,
01734                               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);
01735 
01736     ns_dyn_mem_free(data_ptr);
01737 
01738     return 0;
01739 }
01740 
01741 static uint8_t *thread_joiner_application_write_channel(uint8_t *ptr, uint16_t data)
01742 {
01743     *ptr++ = MESHCOP_TLV_CHANNEL; // type
01744     *ptr++ = 3; // length
01745     *ptr++ = 0; // channel page
01746     return common_write_16_bit(data, ptr);
01747 }
01748 
01749 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)
01750 {
01751     thread_joiner_t *this = thread_joiner_find_by_service(service_id);
01752     (void)source_address;
01753     (void)source_port;
01754 
01755     if (!this) {
01756         return -1;
01757     }
01758 
01759     if (thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MASTER_KEY, NULL) < 16 ||
01760         thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, NULL) < 8 ||
01761         thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_XPANID, NULL) < 8 ||
01762         thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_NAME, NULL) == 0 ||
01763         thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_PSKC, NULL) < 16 ) {
01764         // Absolutely minimum we must have is master secret to attach.
01765         // If commissioner wants to be connected we must have PSKc,Name,Xpanid
01766         // If there is some fields missing we could attach, but timestamp must be set to 0 which will then cause synchronization
01767         tr_debug("Not include all TLv's");
01768         thci_trace("joinerError");
01769         return -1;
01770     }
01771     uint8_t *result_ptr;
01772     memcpy(this->active_configuration_ptr->data,request_ptr->payload_ptr, request_ptr->payload_len);
01773     this->active_configuration_ptr->length = request_ptr->payload_len;
01774 
01775     result_ptr = this->active_configuration_ptr->data + this->active_configuration_ptr->length;
01776 
01777     if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_ACTIVE_TIME_STAMP, NULL) == 0) {
01778         result_ptr = thread_meshcop_tlv_data_write_uint64(result_ptr,MESHCOP_TLV_ACTIVE_TIME_STAMP, 0);
01779     }
01780     if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_XPANID, NULL) == 0) {
01781         result_ptr = thread_meshcop_tlv_data_write(result_ptr,MESHCOP_TLV_XPANID, 8, this->configuration_ptr->extented_pan_id );
01782     }
01783     if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_CHANNEL, NULL) == 0) {
01784         result_ptr = thread_joiner_application_write_channel(result_ptr, this->configuration_ptr->rfChannel);
01785     }
01786     if (thread_meshcop_tlv_find(this->active_configuration_ptr->data, this->active_configuration_ptr->length, MESHCOP_TLV_PANID, NULL) == 0) {
01787         result_ptr = thread_meshcop_tlv_data_write_uint16(result_ptr,MESHCOP_TLV_PANID, this->configuration_ptr->panId );
01788     }
01789 
01790     this->active_configuration_ptr->length = result_ptr - this->active_configuration_ptr->data;
01791 
01792     // check if everything is present
01793     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))) {
01794         // Some fields are missing we need to sync settings during attach
01795         uint8_t *timestamp_ptr = NULL;
01796         thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &timestamp_ptr);
01797         if (timestamp_ptr) {
01798             common_write_64_bit(0,timestamp_ptr);
01799         }
01800     }
01801 
01802     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);
01803 
01804     uint32_t network_key_seq = 0;
01805     if (thread_meshcop_tlv_data_get_uint32(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_KEY_SEQUENCE, &network_key_seq)) {
01806         this->configuration_ptr->key_sequence = network_key_seq;
01807     }
01808 
01809     /*We must null out the master secret*/
01810 #ifdef THREAD_THCI_SUPPORT
01811     uint8_t *master_secret_ptr;
01812     if (thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_NETWORK_MASTER_KEY, &master_secret_ptr) >= 16) {
01813         memset(master_secret_ptr,0,16);
01814     }
01815     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));
01816 #endif
01817 
01818     // save link configuration to NVM
01819 
01820     thci_trace("joinerAccepted");
01821     link_configuration_update(this->configuration_ptr,this->active_configuration_ptr->data,this->active_configuration_ptr->length);
01822     this->configuration_valid = true;
01823     thread_joiner_application_configuration_nvm_save(this->interface_id);
01824 
01825     link_configuration_trace(this->configuration_ptr);
01826 
01827 #ifdef THREAD_THCI_SUPPORT
01828     thci_trace("Device - Joiner|Direction - sent|EUI - %s|Type - JOIN_ent.resp|Length - 0|Payload - ", trace_array(this->device_configuration_ptr->eui64,8));
01829 #endif
01830     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);
01831 
01832     //TODO Add delay timer of 3 seconds and then do attach
01833     thread_joiner_attach_if_needed(this);
01834 
01835     return 0;
01836 }
01837 
01838 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)
01839 {
01840     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
01841     thread_joiner_t *this = thread_joiner_find(interface_id);
01842     if (!this || !done_cb || !cur) {
01843         return -1;
01844     }
01845     if (!this->configuration_ptr) {
01846         this->configuration_ptr = link_configuration_create();
01847     }
01848 
01849     if (!this->configuration_ptr) {
01850         tr_error("Commission start failed");
01851         return -2;
01852     }
01853     this->configuration_valid = false;
01854 
01855 
01856     this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL);
01857     coap_service_register_uri(this->coap_service_id, THREAD_URI_JOINER_ENTRUST, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_joiner_application_entrust_recv_cb);
01858 
01859     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);
01860 
01861     tr_debug("start pskd commissioning: interface %d, parent: %s, port %d", interface_id, trace_ipv6(parent_address), joiner_port);
01862     // save initial information
01863     this->configuration_ptr->panId = panid;
01864     this->configuration_ptr->rfChannel = channel;
01865     if (xpanid) {
01866         memcpy(this->configuration_ptr->extented_pan_id, xpanid, 8);
01867     }
01868 
01869     link_configuration_trace(this->configuration_ptr);
01870     //TODO this callback needs status for blacklist
01871     this->done_cb = done_cb;
01872     memcpy(this->parent_address,parent_address,16);
01873     this->parent_port = joiner_port;
01874 
01875     thci_trace("joinerDtlsSessionStarted");
01876     thread_joiner_application_send_finalisation(this, parent_address, joiner_port);
01877     return 0;
01878 }
01879 
01880 int thread_joiner_application_configuration_nvm_save(int8_t interface_id)
01881 {
01882     tr_info("thread_joiner_application_configuration_nvm_save");
01883 
01884     thread_joiner_t *this = thread_joiner_find(interface_id);
01885     if (!this) {
01886         return -1;
01887     }
01888 
01889     thread_nvm_store_device_configuration_write(this->device_configuration_ptr->extended_random_mac,this->device_configuration_ptr->mesh_local_eid);
01890     thread_nvm_store_pending_configuration_write(this->pending_configuration_ptr, sizeof(configuration_set_t));
01891     thread_nvm_store_seq_counter_write(this->configuration_ptr->key_sequence);
01892     thread_nvm_store_active_configuration_write(this->active_configuration_ptr, sizeof(configuration_set_t));
01893 
01894     /* allow configuration to be read in bootstrap */
01895     this->nvm_link_configuration_load = true;
01896     return 0;
01897 }
01898 
01899 int thread_joiner_application_update_configuration(uint8_t interface_id, uint8_t *msg_ptr, uint16_t msg_len, bool include_missing_tlvs)
01900 {
01901     thread_joiner_t *this = thread_joiner_find(interface_id);
01902     configuration_set_t *configuration_ptr;
01903     if (!this) {
01904         return -1;
01905     }
01906     configuration_ptr = ns_dyn_mem_alloc(sizeof(configuration_set_t));
01907     if (!configuration_ptr) {
01908         return -2;
01909     }
01910     memcpy(configuration_ptr,this->active_configuration_ptr,sizeof(configuration_set_t));
01911     this->active_configuration_ptr->length = 0;
01912     configuration_set_add_all_fields(this->active_configuration_ptr,msg_ptr,msg_len, meshcop_active_set_ignore, sizeof(meshcop_active_set_ignore));
01913     if (include_missing_tlvs) {
01914         configuration_set_copy_missing(this->active_configuration_ptr, configuration_ptr);
01915         configuration_set_remove_null_tlv(this->active_configuration_ptr);
01916     } else {
01917         configuration_set_copy_mandatory(this->active_configuration_ptr, configuration_ptr);
01918     }
01919     thread_meshcop_tlv_data_get_uint64(msg_ptr, msg_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &this->active_configuration_ptr->timestamp);
01920     link_configuration_update(this->configuration_ptr,msg_ptr,msg_len);
01921     ns_dyn_mem_free(configuration_ptr);
01922     thread_joiner_application_configuration_nvm_save(interface_id);
01923 
01924     return 0;
01925 }
01926 uint8_t *thread_joiner_application_active_config_tlv_list_get(uint8_t interface_id, uint16_t *length)
01927 {
01928     uint8_t *result_ptr;
01929     thread_joiner_t *this = thread_joiner_find(interface_id);
01930     if (!this || !this->active_configuration_ptr) {
01931         return NULL;
01932     }
01933     *length = 0;
01934     thread_meshcop_tlv_list_generate(this->active_configuration_ptr->data, this->active_configuration_ptr->length,NULL, length);
01935     if (*length == 0){
01936         return NULL;
01937     }
01938     result_ptr = ns_dyn_mem_alloc(*length);
01939     if (!result_ptr) {
01940     }
01941     thread_meshcop_tlv_list_generate(this->active_configuration_ptr->data, this->active_configuration_ptr->length,result_ptr, length);
01942 
01943     return result_ptr;
01944 }
01945 uint8_t *thread_joiner_application_active_config_params_get(uint8_t interface_id, uint16_t *length)
01946 {
01947     thread_joiner_t *this = thread_joiner_find(interface_id);
01948     if (!this || !this->active_configuration_ptr || !length) {
01949         return NULL;
01950     }
01951     *length = this->active_configuration_ptr->length;
01952     return this->active_configuration_ptr->data;
01953 }
01954 
01955 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)
01956 {
01957     thread_joiner_t *this = thread_joiner_find(interface_id);
01958     if (!this || !this->active_configuration_ptr) {
01959         return 0;
01960     }
01961     return configuration_set_length(this->active_configuration_ptr, req_tlv_ptr, req_tlv_len, ignored_tlv_ptr, ignored_tlv_len);
01962 }
01963 
01964 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)
01965 {
01966     thread_joiner_t *this = thread_joiner_find(interface_id);
01967     if (!this || !this->active_configuration_ptr) {
01968         return ptr;
01969     }
01970     return configuration_set_write(this->active_configuration_ptr, ptr,req_tlv_ptr,req_tlv_len, ignored_tlv_ptr,ignored_tlv_len);
01971 }
01972 
01973 int thread_joiner_application_device_configuration_length(device_configuration_s *device_configuration)
01974 {
01975     int length;
01976 
01977     if (!device_configuration) {
01978         return 0;
01979     }
01980     length = 2 + 1 + 2 + 6 + 2 + device_configuration->vendor_data_len;// Status + Stack version + vendor data
01981     if (device_configuration->provisioning_uri_ptr) {
01982         length += 2 + strlen(device_configuration->provisioning_uri_ptr);
01983     }
01984     if (device_configuration->vendor_name_ptr) {
01985         length += 2 + strlen(device_configuration->vendor_name_ptr);
01986     }
01987     if (device_configuration->vendor_model_ptr) {
01988         length += 2 + strlen(device_configuration->vendor_model_ptr);
01989     }
01990     if (device_configuration->vendor_sw_version_ptr) {
01991         length += 2 + strlen(device_configuration->vendor_sw_version_ptr);
01992     }
01993     return length;
01994 }
01995 
01996 uint8_t *thread_joiner_application_device_configuration_build(uint8_t *ptr, device_configuration_s *device_configuration)
01997 {
01998     if (!ptr || !device_configuration) {
01999         return ptr;
02000     }
02001     ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_STACK_VERSION, 6, device_configuration->vendor_stack_version);
02002     ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_DATA,
02003             device_configuration->vendor_data_len,
02004             device_configuration->vendor_data_ptr);
02005 
02006     if (device_configuration->provisioning_uri_ptr) {
02007         ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_PROVISIONING_URL,
02008                                            strlen(device_configuration->provisioning_uri_ptr),
02009                                            (uint8_t *)device_configuration->provisioning_uri_ptr);
02010     }
02011     if (device_configuration->vendor_name_ptr) {
02012         ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_NAME,
02013                                            strlen(device_configuration->vendor_name_ptr),
02014                                            (uint8_t *)device_configuration->vendor_name_ptr);
02015     }
02016     if (device_configuration->vendor_model_ptr) {
02017         ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_MODEL,
02018                                            strlen(device_configuration->vendor_model_ptr),
02019                                            (uint8_t *)device_configuration->vendor_model_ptr);
02020     }
02021     if (device_configuration->vendor_sw_version_ptr) {
02022         ptr = thread_tmfcop_tlv_data_write(ptr, MESHCOP_TLV_VENDOR_SW_VERSION,
02023                                            strlen(device_configuration->vendor_sw_version_ptr),
02024                                            (uint8_t *)device_configuration->vendor_sw_version_ptr);
02025     }
02026     return ptr;
02027 }
02028 
02029 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)
02030 {
02031     thread_joiner_t *this = thread_joiner_find(interface_id);
02032     uint64_t timestamp = 0;
02033 
02034     if (!this) {
02035         return -1;
02036     }
02037     configuration_set_add_all_fields(this->active_configuration_ptr, data_ptr, data_len, ignore_ptr, ingore_len);
02038     thread_meshcop_tlv_data_get_uint64(data_ptr, data_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &timestamp);
02039     thread_joiner_application_active_timestamp_set(this->interface_id, timestamp);
02040     link_configuration_update(this->configuration_ptr,this->active_configuration_ptr->data,this->active_configuration_ptr->length);
02041     this->configuration_valid = true;
02042     thread_joiner_application_configuration_nvm_save(this->interface_id);
02043 
02044     link_configuration_trace(this->configuration_ptr);
02045 
02046     return 0;
02047 }
02048 #endif
02049