EL4121 Embedded System / mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_joiner_application.c Source File

thread_joiner_application.c

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