takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_joiner_application.c Source File

thread_joiner_application.c

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