Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_commissioning_api.c Source File

thread_commissioning_api.c

00001 /*
00002  * Copyright (c) 2015-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 /*Nanostack includes*/
00031 #include "nsconfig.h"
00032 
00033 #include <string.h>
00034 #include "ns_types.h"
00035 #include "ns_list.h"
00036 #include "ns_trace.h"
00037 #include "nsdynmemLIB.h"
00038 #include "common_functions.h"
00039 #include "ns_sha256.h"
00040 
00041 /*thread includes*/
00042 #include "thread_config.h"
00043 #include "thread_management_if.h"
00044 #include "thread_meshcop_lib.h"
00045 #include "thread_management_api.h"
00046 #include "thread_commissioning_api.h"
00047 #include "thread_beacon.h"
00048 /*Private includes*/
00049 #include "6LoWPAN/Thread/thread_common.h"
00050 #include "6LoWPAN/Thread/thread_management_internal.h"
00051 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"// Get coordinator address
00052 
00053 #define TRACE_GROUP TRACE_GROUP_THREAD_COMMISSIONING_API
00054 #ifdef HAVE_THREAD
00055 
00056 #include "coap_service_api.h"
00057 
00058 typedef struct device {
00059     uint8_t PSKd[32];
00060     uint8_t kek[32];// shal libs needs 32 bytes kek is first 16
00061     uint8_t EUI64[8];
00062     uint8_t IID[8];
00063     thread_commissioning_joiner_finalisation_cb *joining_device_cb_ptr;
00064     uint16_t joiner_router_rloc;
00065     uint8_t PSKd_len;
00066     bool send_kek: 1;
00067     bool short_eui64: 1;/*< Use short format for bloom filter creation*/
00068 
00069     ns_list_link_t link;
00070 } device_t;
00071 
00072 typedef NS_LIST_HEAD (device_t, link) device_list_t;
00073 
00074 typedef struct commissioner_entry {
00075     device_list_t device_list;
00076     uint8_t destination_address[16];
00077     uint8_t PSKc_ptr[16];
00078     thread_commissioning_status_cb *status_cb_ptr;
00079     uint16_t destination_port;
00080     uint16_t session_id;
00081     int8_t management_instance;
00082     int8_t interface_id;
00083     int8_t coap_service_id;
00084     int8_t coap_secure_service_id;
00085     int8_t coap_virtual_service_id;
00086     bool registered: 1;
00087     bool native_commissioner: 1;
00088 
00089     ns_list_link_t link;
00090 } commissioner_t;
00091 
00092 static NS_LIST_DEFINE(instance_list, commissioner_t, link);
00093 
00094 const uint8_t any_device[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
00095 
00096 /*
00097  * Commissioned device handlers;
00098  */
00099 static device_t *device_create(commissioner_t *commissioner_ptr)
00100 {
00101     device_t *device_ptr = ns_dyn_mem_alloc(sizeof(device_t));
00102     if (device_ptr) {
00103         memset(device_ptr, 0, sizeof(device_t));
00104         device_ptr->send_kek = false;
00105         device_ptr->joining_device_cb_ptr = NULL;
00106         ns_list_add_to_start(&commissioner_ptr->device_list, device_ptr);
00107     }
00108     return device_ptr;
00109 }
00110 
00111 static void device_delete(commissioner_t *commissioner_ptr, device_t *device_ptr)
00112 {
00113     if (device_ptr) {
00114         ns_list_remove(&commissioner_ptr->device_list, device_ptr);
00115         ns_dyn_mem_free(device_ptr);
00116     }
00117     return;
00118 }
00119 
00120 static device_t *device_find(commissioner_t *commissioner_ptr, uint8_t EUI64[8])
00121 {
00122     device_t *this = NULL;
00123     if (!commissioner_ptr || !EUI64) {
00124         return NULL;
00125     }
00126 
00127     ns_list_foreach(device_t, cur_ptr, &commissioner_ptr->device_list) {
00128         if (memcmp(cur_ptr->EUI64, EUI64, 8) == 0) {
00129             this = cur_ptr;
00130             break;
00131         }
00132     }
00133     return this;
00134 }
00135 
00136 static device_t *device_find_by_iid(commissioner_t *commissioner_ptr, uint8_t IID[8])
00137 {
00138     device_t *this = NULL;
00139     if (!IID) {
00140         return NULL;
00141     }
00142     ns_list_foreach(device_t, cur_ptr, &commissioner_ptr->device_list) {
00143         tr_debug("device iid %s and commissioner iid %s", trace_array(cur_ptr->IID,8),trace_array(IID,8));
00144         if (memcmp(cur_ptr->IID, IID, 8) == 0) {
00145             this = cur_ptr;
00146             break;
00147         }
00148     }
00149     return this;
00150 }
00151 #define device_get_first(commissioner) ns_list_get_first(&commissioner->device_list)
00152 
00153 
00154 /* Commissioner class handlers*/
00155 static commissioner_t *commissioner_find(int8_t interface_id)
00156 {
00157     commissioner_t *this = NULL;
00158     ns_list_foreach(commissioner_t, cur_ptr, &instance_list) {
00159         if (cur_ptr->interface_id == interface_id) {
00160             this = cur_ptr;
00161             break;
00162         }
00163     }
00164     return this;
00165 }
00166 static commissioner_t *commissioner_find_by_service(int8_t service_id)
00167 {
00168     commissioner_t *this = NULL;
00169     ns_list_foreach(commissioner_t, cur_ptr, &instance_list) {
00170         if (cur_ptr->coap_service_id == service_id || cur_ptr->coap_virtual_service_id == service_id || cur_ptr->coap_secure_service_id == service_id) {
00171             this = cur_ptr;
00172             break;
00173         }
00174     }
00175     return this;
00176 }
00177 static commissioner_t *commissioner_create(int8_t interface_id)
00178 {
00179     commissioner_t *this = ns_dyn_mem_alloc(sizeof(commissioner_t));
00180     if (this) {
00181         memset(this, 0, sizeof(commissioner_t));
00182         this->interface_id = interface_id;
00183         this->registered = false;
00184         ns_list_init(&this->device_list);
00185         ns_list_add_to_start(&instance_list, this);
00186     }
00187     return this;
00188 }
00189 
00190 static void commissioner_delete(commissioner_t *this)
00191 {
00192     if (this) {
00193         device_t *device_ptr = device_get_first(this);
00194         while (device_ptr != NULL) {
00195             device_delete(this, device_ptr);
00196             device_ptr = device_get_first(this);
00197         }
00198         ns_list_remove(&instance_list, this);
00199         ns_dyn_mem_free(this);
00200     }
00201     return;
00202 }
00203 
00204 /*Internal helper functions*/
00205 static int commissioning_meshcop_map_state(commissioning_state_e state)
00206 {
00207     if (state == COMMISSIONING_STATE_ACCEPT) {
00208         return 1;
00209     } else if (state == COMMISSIONING_STATE_PENDING) {
00210         return 0;
00211     }
00212 
00213     return -1;
00214 }
00215 
00216 
00217 static int commission_finalisation_resp_send(int8_t coap_service_id, device_t *device_ptr, sn_coap_hdr_s *request_ptr, commissioning_state_e state)
00218 {
00219     commissioner_t *this = commissioner_find_by_service(coap_service_id);
00220     uint8_t payload[11];// 4 + 1 + 4 + 2
00221     uint8_t *ptr;
00222 
00223     if (!this || !request_ptr || !device_ptr) {
00224         return -1;
00225     }
00226 
00227     ptr = payload;
00228     ptr = thread_meshcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, (uint8_t)commissioning_meshcop_map_state(state));
00229 
00230     thci_trace("Device - Comm|Direction - sent|EUI - %s|Type - JOIN_FIN.resp|Length - %d|Payload - %s",trace_array(device_ptr->EUI64,8), (int)(ptr - payload), trace_array(payload, ptr - payload));
00231     tr_debug("finalisation response send state:%d value:%d ", state, (uint8_t)commissioning_meshcop_map_state(state));
00232     coap_service_response_send(coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload, ptr - payload);
00233     return 0;
00234 }
00235 
00236 /*
00237  * Callback functions
00238 */
00239 
00240 static int commissioning_leader_petition_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00241 {
00242     commissioner_t *this = commissioner_find_by_service(service_id);
00243     commissioning_state_e state = COMMISSIONING_STATE_REJECT;
00244     uint16_t session_id = 0;
00245     uint8_t *ptr;
00246     (void) source_address;
00247     (void) source_port;
00248 
00249     tr_debug("Thread Petition response received service %d",service_id);
00250     if (!this) {
00251         return -1;
00252     }
00253 
00254     if (!response_ptr || !response_ptr->payload_ptr || response_ptr->payload_len < 1) {
00255         tr_debug("invalid response");
00256         thci_trace("commissionerPetitionError");
00257         goto user_response;
00258     }
00259 
00260     if ((2 <= thread_meshcop_tlv_data_get_uint16(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &session_id)) &&
00261             (1 <= thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &ptr) && *ptr == 1)) {
00262         state = COMMISSIONING_STATE_ACCEPT;
00263         thci_trace("commissionerPetitionAccepted");
00264         this->session_id = session_id;
00265         this->registered = true;
00266         //@TODO order keep alive timer for the message and start sending it periodically
00267     }
00268     tr_debug("petition response session_id: %d state:%d",session_id, state);
00269 
00270 user_response:
00271     if (state == COMMISSIONING_STATE_REJECT) {
00272         thci_trace("commissionerPetitionRejected");
00273     }
00274     if (this->status_cb_ptr) {
00275         this->status_cb_ptr(this->interface_id, this->session_id, state);
00276     }
00277     return 0;
00278 }
00279 
00280 static int commissioning_keep_alive_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00281 {
00282     commissioner_t *this = commissioner_find_by_service(service_id);
00283     uint8_t *ptr;
00284     (void) source_address;
00285     (void) source_port;
00286 
00287     tr_debug("Thread keep alive response received");
00288     if (!this) {
00289         tr_warn("commissioner service missing!");
00290         thci_trace("commissionerError");
00291         return -1;
00292     }
00293     if (!response_ptr) {
00294         tr_warn("commission ka response without ptr!");
00295         thci_trace("commissionerError");
00296         return -1;
00297     }
00298 
00299     if (1 <= thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &ptr) && *ptr == 1) {
00300         // only handle success
00301         return 0;
00302     }
00303 
00304     this->session_id = 0;
00305     this->registered = false;
00306     if (this->status_cb_ptr) {
00307         this->status_cb_ptr(this->interface_id, this->session_id, COMMISSIONING_STATE_REJECT);
00308     }
00309 
00310     return -2;
00311 }
00312 
00313 static int commission_finalisation_req_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00314 {
00315     commissioner_t *this = commissioner_find_by_service(service_id);
00316     uint8_t address[16];
00317     device_t *device_ptr;
00318     int ret = -1;// always reject
00319     (void) source_port;
00320 
00321     tr_debug("joiner finalisation recv addr %s", trace_ipv6(source_address));
00322     if (!this || !source_address || !request_ptr) {
00323         return -1;
00324     }
00325 
00326     device_ptr = device_find_by_iid(this, &source_address[8]);
00327     if (device_ptr) {
00328         ret = 0;    // accept even without application confirmation
00329     }
00330     thci_trace("Device - Comm|Direction - recv|EUI - %s|Type - JOIN_FIN.req|Length - %d|Payload - %s",trace_array(device_ptr->EUI64,8), request_ptr->payload_len, trace_array(request_ptr->payload_ptr, request_ptr->payload_len));
00331     memcpy(address,source_address,16);
00332 
00333     if (device_ptr) {
00334         if (device_ptr->joining_device_cb_ptr) {
00335             ret = device_ptr->joining_device_cb_ptr(this->interface_id, &source_address[8], request_ptr->payload_ptr, request_ptr->payload_len);
00336         }
00337 
00338         device_ptr->send_kek = true;
00339     }
00340 
00341     if (ret == 0) {
00342         thci_trace("commissionerJoinerAccepted");
00343     }
00344 
00345     commission_finalisation_resp_send(service_id, device_ptr, request_ptr, ret == 0 ? COMMISSIONING_STATE_ACCEPT : COMMISSIONING_STATE_REJECT);
00346     coap_service_close_secure_connection(service_id, address, source_port);
00347 
00348     return 0;
00349 }
00350 static int commission_application_provision_req_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00351 {
00352     commissioner_t *this = commissioner_find_by_service(service_id);
00353     uint8_t payload[11];// 4 + 1 + 4 + 2
00354     uint8_t *ptr;
00355 
00356     (void) source_port;
00357 
00358     tr_debug("joiner application provisioning recv addr %s", trace_ipv6(source_address));
00359     if (!this || !source_address || !request_ptr) {
00360         return -1;
00361     }
00362 
00363     thci_trace("Device - Comm|Direction - recv|EUI - %s|Type - JOIN_APP.req|Length - %d|Payload - %s",trace_array(&source_address[8],8), request_ptr->payload_len, trace_array(request_ptr->payload_ptr, request_ptr->payload_len));
00364 
00365     ptr = payload;
00366     ptr = thread_meshcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 1);
00367 
00368     thci_trace("Device - Comm|Direction - sent|EUI - %s|Type - JOIN_APP.resp|Length - %d|Payload - %s",trace_array(&source_address[8],8), (int)(ptr - payload), trace_array(payload, ptr - payload));
00369     coap_service_response_send(service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload, ptr - payload);
00370     return 0;
00371 }
00372 
00373 static int commission_dataset_changed_notify_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00374 {
00375     (void)source_address;
00376     (void)source_port;
00377 
00378     tr_debug("Dataset changed - notification received from: %s", trace_ipv6(source_address));
00379     coap_service_response_send(service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_NONE, NULL, 0);
00380 
00381     return 0;
00382 }
00383 
00384 static uint8_t *bloom_filter_calculate(uint8_t *bloom_filter_ptr,device_list_t device_list, int *steering_tlv_max_length)
00385 {
00386     memset(bloom_filter_ptr,0,*steering_tlv_max_length);
00387     ns_list_foreach(device_t, cur_ptr, &device_list)
00388     {
00389         if (memcmp(cur_ptr->EUI64, any_device, 8) != 0)
00390         {
00391             tr_debug("eui64 used on commissioning side = %s",trace_array(cur_ptr->EUI64,8));
00392             cur_ptr->IID[0] |= 2; //Changed IID to MAC extended address for bloom filter calculation
00393             thread_beacon_calculate_bloom_filter(bloom_filter_ptr,*steering_tlv_max_length,cur_ptr->IID, 8);
00394             cur_ptr->IID[0] &= ~2;//Restore IID
00395         }
00396         else
00397         {
00398             bloom_filter_ptr[0] = 0xff;
00399             *steering_tlv_max_length = 1;
00400             break;
00401         }
00402     }
00403 
00404     return bloom_filter_ptr;
00405 }
00406 
00407 static int commission_steering_data_update(commissioner_t *this)
00408 {
00409     //variable for steering tlv length - maximum possible length is 16 bytes - section 8.10.1.9 Max length
00410     int steering_tlv_length = 16;
00411     uint8_t bloom_filter_ptr[16];
00412     int ret;
00413 
00414     //bloom filter calculation function call
00415     bloom_filter_calculate(bloom_filter_ptr, this->device_list, &steering_tlv_length);
00416     tr_debug("Steering bloom set :%s", trace_array(bloom_filter_ptr, 16));
00417     ret = thread_management_set_steering_data(this->management_instance, this->session_id,bloom_filter_ptr, steering_tlv_length, NULL);
00418     if (ret) {
00419         tr_warn("Steering data set failed %d", ret);
00420         return -1;
00421     }
00422 
00423     return 0;
00424 }
00425 
00426 /*
00427  * These functions are the relay endpoint for commissioner device.
00428  * this can be either:
00429  * secure native commissioner
00430  * or unsecure native commissioner
00431  * */
00432 static int commission_relay_rx_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00433 {
00434     commissioner_t *this = commissioner_find_by_service(service_id);
00435     uint8_t joiner_address[16] = { 0xfe, 0x80 };
00436     uint8_t *joiner_iid_ptr;
00437     uint8_t *udp_ptr;
00438     uint16_t udp_len;
00439     uint16_t joiner_port;
00440     uint16_t joiner_router_rloc;
00441     device_t *device_ptr;
00442     (void) source_port;
00443 
00444     if (!this || !source_address || !request_ptr) {
00445         return -1;    // goto error response
00446     }
00447 
00448     if ((0 == (udp_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_ENCAPSULATION, &udp_ptr))) ||
00449             (8 > thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_IID, &joiner_iid_ptr))  ||
00450             (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_UDP_PORT, &joiner_port)) ||
00451             (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_ROUTER_LOCATOR, &joiner_router_rloc))) {
00452         tr_warn("Corrupted relay packet received");
00453         return -1;
00454     }
00455 
00456     memcpy(&joiner_address[8], joiner_iid_ptr, 8);
00457     tr_debug("Relay RX from (%x) addr %s, port %d, len:%d", joiner_router_rloc, trace_ipv6(joiner_address), joiner_port, udp_len);
00458 
00459     device_ptr = device_find_by_iid(this, joiner_iid_ptr);
00460     if (!device_ptr) {
00461         tr_warn("unknown device connected");
00462         //Interop HACK
00463         device_ptr = device_find(this, (uint8_t*)any_device);
00464         if (!device_ptr) {
00465             tr_warn("No catch all device added");
00466             return -1;
00467         }
00468 
00469         memcpy(device_ptr->IID, &joiner_address[8], 8);
00470         memcpy(device_ptr->EUI64, &joiner_address[8], 8); // This is wrong as we cannot reverse the SHA1 But ok For Any device
00471         device_ptr->EUI64[0] ^= 2;// We are searching for list of eui64 so need to flip
00472         if (commission_steering_data_update(this) != 0) {
00473             return -1;
00474         }
00475         tr_warn("catching device for iid:%s", trace_array(&joiner_address[8], 8));
00476     }
00477     device_ptr->joiner_router_rloc = joiner_router_rloc;
00478     coap_service_virtual_socket_recv(this->coap_virtual_service_id, joiner_address, joiner_port, udp_ptr, udp_len);
00479     return -1; // no response sent
00480 }
00481 
00482 static int commission_virtual_socket_send_cb(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port, const uint8_t *data_ptr, uint16_t data_len)
00483 {
00484     commissioner_t *this = commissioner_find_by_service(service_id);
00485     uint8_t destination_address[16];
00486     uint16_t destination_port;
00487     device_t *device_ptr;
00488     uint8_t *payload_ptr;
00489     uint8_t *ptr;
00490     uint16_t payload_len;
00491     uint8_t destination_service_id;
00492 
00493     tr_debug("Relay RX send addr %s, port %d, len:%d", trace_ipv6(destination_addr_ptr), port, data_len);
00494     if (!this || !destination_addr_ptr || !data_ptr) {
00495         return -1;
00496     }
00497 
00498     device_ptr = device_find_by_iid(this, &destination_addr_ptr[8]);
00499     if (!device_ptr) {
00500         return -2;
00501     }
00502     payload_len =  4 + data_len + 4 + 8 + 4 + 2;
00503 
00504     if (device_ptr->send_kek) {
00505         payload_len += 4 + 16;
00506     }
00507 
00508     payload_ptr = ns_dyn_mem_alloc(payload_len);
00509     if (!payload_ptr) {
00510         return -3;
00511     }
00512     if (this->native_commissioner){
00513         destination_service_id = this->coap_secure_service_id;
00514         memcpy(destination_address,this->destination_address,16);
00515         destination_port = this->destination_port;
00516     } else {
00517         memset(destination_address,0,16);
00518         destination_service_id = this->coap_service_id;
00519         thread_management_get_ml_prefix(this->interface_id, destination_address);
00520         common_write_16_bit(0xfffe, &destination_address[11]);
00521         common_write_16_bit(device_ptr->joiner_router_rloc, &destination_address[14]);
00522         destination_port = THREAD_MANAGEMENT_PORT;
00523     }
00524 
00525     tr_debug("Relay destination %s:%d", trace_ipv6(destination_address), destination_port);
00526 
00527     ptr = payload_ptr;
00528     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_ENCAPSULATION, data_len, data_ptr);
00529     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_IID, 8, &destination_addr_ptr[8]);
00530     ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_JOINER_UDP_PORT, port);
00531     ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_JOINER_ROUTER_LOCATOR, device_ptr->joiner_router_rloc);
00532 
00533     if (device_ptr->send_kek) {
00534         tr_debug("Relay RX Send KEK");
00535         ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_ROUTER_KEK, 16, device_ptr->kek);
00536         device_ptr->send_kek = false;
00537     }
00538 
00539     coap_service_request_send(destination_service_id, COAP_REQUEST_OPTIONS_NONE, destination_address, destination_port,
00540                               COAP_MSG_TYPE_NON_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_RELAY_TRANSMIT, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr, NULL);
00541 
00542     ns_dyn_mem_free(payload_ptr);
00543 
00544     return 0;
00545 }
00546 
00547 static int commissioning_security_done_cb(int8_t service_id, uint8_t address[static 16], uint8_t keyblock[static 40])
00548 {
00549     commissioner_t *this = commissioner_find_by_service(service_id);
00550     device_t *device_ptr;
00551 
00552     if (!this) {
00553         return -1;
00554     }
00555 
00556     tr_debug("Commissioner security done addr %s keyblock %s", trace_ipv6(address), trace_array(keyblock, 40));
00557     device_ptr = device_find_by_iid(this, &address[8]);
00558     if (!device_ptr) {
00559         tr_debug("Commissioner device not found");
00560         thci_trace("commissionerBrError");
00561         return -1;
00562     }
00563     ns_sha256(keyblock, 40, device_ptr->kek);
00564 
00565     return 0;
00566 }
00567 
00568 static int joiner_commissioner_security_start_cb(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t *pw, uint8_t *pw_len)
00569 {
00570     int ret = -1;
00571     (void)port;
00572     tr_info("commissionerJoinerDtlsSessionStarted");
00573 
00574     commissioner_t *this = commissioner_find_by_service(service_id);
00575 
00576     if (!this) {
00577         return ret;
00578     }
00579 
00580     device_t *device_ptr = device_find_by_iid(this, &address[8]);
00581 
00582     if( device_ptr ){
00583         memcpy(pw, device_ptr->PSKd, device_ptr->PSKd_len );
00584         *pw_len = device_ptr->PSKd_len;
00585         ret = 0;
00586 //        ret = coap_service_security_key_set( service_id, address, port, device_ptr->PSKd, device_ptr->PSKd_len );
00587     }
00588 
00589     return ret;
00590 }
00591 
00592 static int commissioner_br_security_start_cb(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t *pw, uint8_t *pw_len)
00593 {
00594     int ret = -1;
00595     (void)address;
00596     (void)port;
00597     tr_info("commissionerBrDtlsSessionStarted");
00598     commissioner_t *this = commissioner_find_by_service(service_id);
00599     if(this){
00600         memcpy(pw, this->PSKc_ptr, 16 );
00601         *pw_len = 16;
00602         ret = 0;
00603 //        ret = coap_service_security_key_set( service_id, address, port, this->PSKc_ptr, this->PSKc_len );
00604     }
00605 
00606     return ret;
00607 }
00608 
00609 static int commissioner_br_security_done_cb(int8_t service_id, uint8_t address[16], uint8_t keyblock[static 40])
00610 {
00611     (void)service_id;
00612     (void)address;
00613     (void)keyblock;
00614     thci_trace("commissionerBrAccepted");
00615     thci_trace("commissionerPetitionStarted");
00616     return 0;
00617 }
00618 
00619 static int thread_commissioning_remote_addr_set(commissioner_t *this)
00620 {
00621     if (0 == thread_management_get_leader_address(this->interface_id, this->destination_address)) {
00622         tr_debug("on-mesh commissioner");
00623         this->destination_port = THREAD_MANAGEMENT_PORT;
00624         this->native_commissioner = false;
00625     } else if (0 == thread_commissioning_native_commissioner_get_connection_info(this->interface_id,
00626                this->destination_address, &this->destination_port)) {
00627         tr_debug("native commissioner");
00628         this->native_commissioner = true;
00629     } else {
00630         tr_error("No remote address");
00631         return -1;
00632     }
00633     return 0;
00634 }
00635 
00636 /*
00637 Public api functions
00638 */
00639 int thread_commissioning_register(int8_t interface_id, uint8_t PSKc[static 16])
00640 {
00641     if (commissioner_find(interface_id)) {
00642         return -1;
00643     }
00644     commissioner_t *this = commissioner_create(interface_id);
00645     if (!this) {
00646         return -2;
00647     }
00648     memcpy(this->PSKc_ptr,PSKc,16);
00649 
00650     this->management_instance = thread_management_register(interface_id);
00651     this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL);
00652     coap_service_register_uri(this->coap_service_id, THREAD_URI_RELAY_RECEIVE, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_relay_rx_recv_cb);
00653     coap_service_register_uri(this->coap_service_id, THREAD_URI_JOINER_APPLICATION_REQUEST, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_application_provision_req_recv_cb);
00654     coap_service_register_uri(this->coap_service_id, THREAD_URI_DATASET_CHANGED, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_dataset_changed_notify_recv_cb);
00655 
00656     this->coap_secure_service_id = coap_service_initialize(this->interface_id, THREAD_COMMISSIONING_PORT, COAP_SERVICE_OPTIONS_SECURE | COAP_SERVICE_OPTIONS_SECURE_BYPASS, commissioner_br_security_start_cb, commissioner_br_security_done_cb);
00657     coap_service_register_uri(this->coap_secure_service_id, THREAD_URI_RELAY_RECEIVE, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_relay_rx_recv_cb);
00658 
00659     this->coap_virtual_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_SECURE | COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET, joiner_commissioner_security_start_cb, commissioning_security_done_cb);
00660     coap_service_register_uri(this->coap_virtual_service_id, THREAD_URI_JOINER_FINALIZATION, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_finalisation_req_recv_cb);
00661     coap_service_virtual_socket_set_cb(this->coap_virtual_service_id, commission_virtual_socket_send_cb);
00662     return 0;
00663 }
00664 
00665 int thread_commissioning_unregister(int8_t interface_id)
00666 {
00667     commissioner_t *this = commissioner_find(interface_id);
00668     if (!this) {
00669         return -1;
00670     }
00671     if (this->registered) {
00672         // Unregister the commissioner
00673         thread_commissioning_petition_keep_alive(this->interface_id, COMMISSIONING_STATE_REJECT);
00674     }
00675     thread_management_unregister(this->management_instance);
00676 
00677     coap_service_delete(this->coap_service_id);
00678     coap_service_delete(this->coap_secure_service_id);
00679     coap_service_delete(this->coap_virtual_service_id);
00680 
00681     commissioner_delete(this);
00682     return 0;
00683 }
00684 
00685 int thread_commissioning_petition_start(int8_t interface_id, char *commissioner_id_ptr, thread_commissioning_status_cb *status_cb_ptr)
00686 {
00687     commissioner_t *this;
00688     uint8_t payload[68];// max length for commissioner id is 64 + 4 byte header
00689     uint8_t commissioner_id_length;
00690     uint8_t service_id;
00691     uint8_t *ptr;
00692     char *uri_ptr;
00693 
00694     this = commissioner_find(interface_id);
00695 
00696     if (!this) {
00697         return -1;
00698     }
00699     if (!commissioner_id_ptr) {
00700         return -2;
00701     }
00702     commissioner_id_length = strlen(commissioner_id_ptr);
00703 
00704     if (commissioner_id_length > 64) {
00705         return -3;
00706     }
00707 
00708     if (thread_commissioning_remote_addr_set(this)) {
00709         return -4;
00710     }
00711 
00712     if (this->native_commissioner) {
00713         uri_ptr = THREAD_URI_COMMISSIONER_PETITION;
00714         service_id = this->coap_secure_service_id;
00715     } else {
00716         uri_ptr = THREAD_URI_LEADER_PETITION;
00717         service_id = this->coap_service_id;
00718     }
00719 
00720     this->status_cb_ptr = status_cb_ptr;
00721     ptr = payload;
00722     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_COMMISSIONER_ID, commissioner_id_length, (uint8_t *) commissioner_id_ptr);
00723 
00724     tr_debug("Thread Petition send to %s:%d id %s ", trace_ipv6(this->destination_address),this->destination_port, commissioner_id_ptr);
00725 
00726     //TODO there must be way to set PSKc for request
00727     //TODO there must be way to make client transactions with security and no security
00728     coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port,
00729                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, uri_ptr, COAP_CT_OCTET_STREAM, payload, ptr - payload, commissioning_leader_petition_recv_cb);
00730     return 0;
00731 }
00732 
00733 int thread_commissioning_petition_keep_alive(int8_t interface_id, commissioning_state_e state)
00734 {
00735     commissioner_t *this;
00736     uint8_t payload[7];
00737     uint8_t *ptr;
00738     uint8_t service_id;
00739     char *uri_ptr;
00740     /* length is
00741        state tlv 3
00742        session id tlv 4
00743     */
00744     this = commissioner_find(interface_id);
00745 
00746     if (!this) {
00747         return -1;
00748     }
00749 
00750     if (thread_commissioning_remote_addr_set(this)) {
00751         return -4;
00752     }
00753 
00754     if (this->native_commissioner) {
00755         uri_ptr = THREAD_URI_COMMISSIONER_KEEP_ALIVE;
00756         service_id = this->coap_secure_service_id;
00757     } else {
00758         uri_ptr = THREAD_URI_LEADER_KEEP_ALIVE;
00759         service_id = this->coap_service_id;
00760     }
00761 
00762     ptr = payload;
00763     ptr = thread_meshcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, (uint8_t)commissioning_meshcop_map_state(state));
00764     ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_COMMISSIONER_SESSION_ID, this->session_id);
00765 
00766     tr_debug("Commissioner keep alive send to %s:%d, session_id=%d, state=%d",
00767              trace_ipv6(this->destination_address), this->destination_port,
00768              this->session_id, state);
00769     thci_trace("commissionerKeepAliveSent");
00770     if (state != COMMISSIONING_STATE_ACCEPT) {
00771         this->session_id = 0;
00772     }
00773     coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port,
00774                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, uri_ptr, COAP_CT_OCTET_STREAM, payload, ptr - payload, commissioning_keep_alive_recv_cb);
00775     return 0;
00776 }
00777 
00778 /*
00779  * PSKD (Pre-Shared Key -Device). A PSKD can be a minimum of six (6) uppercase alphanumeric characters long
00780  *
00781  * */
00782 int thread_commissioning_device_add(int8_t interface_id, bool short_eui64, uint8_t EUI64[static 8], uint8_t *PSKd_ptr, uint8_t PSKd_len, thread_commissioning_joiner_finalisation_cb *joining_device_cb_ptr)
00783 {
00784     commissioner_t *this;
00785     device_t *device_ptr = NULL;
00786 
00787     this = commissioner_find(interface_id);
00788     if (!this || PSKd_len < 1 || PSKd_len > 32 || !PSKd_ptr ) {
00789         return -1;
00790     }
00791 
00792     if (memcmp(EUI64, any_device, 8) == 0) {
00793         // always add 'any' device to allow multiple 'any' devices
00794         device_ptr = device_create(this);
00795     }
00796 
00797     if (!device_ptr) {
00798         // try to find an existing device
00799         device_ptr = device_find(this, EUI64);
00800     }
00801 
00802     if (!device_ptr) {
00803         // create device
00804         device_ptr = device_create(this);
00805     }
00806 
00807     if (!device_ptr) {
00808         return -2;
00809     }
00810 
00811     memcpy(device_ptr->EUI64, EUI64, 8);
00812     if (memcmp(EUI64, any_device, 8) != 0){
00813         ns_sha256_nbits(EUI64, 8, device_ptr->IID, 64);
00814         device_ptr->IID[0] &= ~2; //local administered bit is set in MAC and flipped in IID
00815     } else {
00816         memcpy(device_ptr->IID, any_device, 8);
00817     }
00818 
00819     memcpy(device_ptr->PSKd, PSKd_ptr, PSKd_len);
00820     device_ptr->PSKd_len = PSKd_len;
00821     device_ptr->short_eui64 = short_eui64;
00822     device_ptr->joining_device_cb_ptr = joining_device_cb_ptr;
00823 
00824     if (commission_steering_data_update(this) != 0) {
00825         return -2;
00826     }
00827     thci_trace("commissionerNwkDataSynced");
00828     return 0;
00829 }
00830 
00831 int thread_commissioning_device_delete(int8_t interface_id, uint8_t EUI64[static 8])
00832 {
00833     commissioner_t *this = commissioner_find(interface_id);
00834 
00835     if (!this) {
00836         return -1;
00837     }
00838 
00839     tr_debug("delete commissioned device EUI64:%s", trace_array(EUI64, 8));
00840     device_delete(this, device_find(this, EUI64));
00841 
00842     if (commission_steering_data_update(this) != 0) {
00843         return -2;
00844     }
00845     return 0;
00846 }
00847 
00848 
00849 void *thread_commission_device_get_next(void *ptr, int8_t interface_id, bool *short_eui64, uint8_t EUI64[8], uint8_t PSKd[32], uint8_t *PSKd_len)
00850 {
00851     commissioner_t *this = commissioner_find(interface_id);
00852     if (!this) {
00853         return NULL;
00854     }
00855     device_t *cur_ptr = (device_t*)ptr;
00856     if(cur_ptr == NULL) {
00857         cur_ptr = (device_t*)ns_list_get_first(&this->device_list);
00858     } else {
00859         cur_ptr = (device_t*)ns_list_get_next(&this->device_list, cur_ptr);
00860     }
00861     if(!cur_ptr) return NULL;
00862     if(short_eui64) *short_eui64 = cur_ptr->short_eui64;
00863     if(EUI64) memcpy(EUI64, cur_ptr->EUI64, 8);
00864     if(PSKd) memcpy(PSKd, cur_ptr->PSKd, 32);
00865     if(PSKd_len) *PSKd_len = cur_ptr->PSKd_len;
00866 
00867     return cur_ptr;
00868 }
00869 
00870 int thread_commissioning_native_commissioner_start(int8_t interface_id, thread_commissioning_native_select_cb *cb_ptr)
00871 {
00872     protocol_interface_info_entry_t *cur;
00873     cur = protocol_stack_interface_info_get_by_id(interface_id);
00874     tr_debug("start native commissioner scanning");
00875     if(!cur || !cur->thread_info) {
00876         return -1;
00877     }
00878     cur->thread_info->native_commissioner_link = NULL;
00879     cur->thread_info->native_commissioner_cb = cb_ptr;
00880     //TODO check if bootstrap is connected then we have to drop from old network and trigger scanning
00881     return 0;
00882 
00883 }
00884 
00885 int thread_commissioning_native_commissioner_stop(int8_t interface_id)
00886 {
00887     protocol_interface_info_entry_t *cur;
00888     cur = protocol_stack_interface_info_get_by_id(interface_id);
00889     tr_debug("stop native commissioner scanning");
00890     if(!cur || !cur->thread_info) {
00891         return -1;
00892     }
00893     ns_dyn_mem_free(cur->thread_info->native_commissioner_link);
00894     cur->thread_info->native_commissioner_link = NULL;
00895     cur->thread_info->native_commissioner_cb = NULL;
00896     return 0;
00897 }
00898 
00899 int thread_commissioning_native_commissioner_connect(int8_t interface_id, thread_commissioning_link_configuration_s *link_ptr)
00900 {
00901     protocol_interface_info_entry_t *cur;
00902     cur = protocol_stack_interface_info_get_by_id(interface_id);
00903     tr_debug("connect native commissioner");
00904     if(!cur || !cur->thread_info) {
00905         return -1;
00906     }
00907     cur->thread_info->native_commissioner_link = ns_dyn_mem_alloc(sizeof(thread_commissioning_link_configuration_s));
00908     if(!cur->thread_info->native_commissioner_link) {
00909         return -2;
00910     }
00911     *cur->thread_info->native_commissioner_link = *link_ptr;
00912     //TODO check that we are scanning for networks and reset backup timers
00913 
00914     return 0;
00915 }
00916 
00917 int thread_commissioning_native_commissioner_get_connection_info(int8_t interface_id, uint8_t *address_ptr, uint16_t *port)
00918 {
00919     protocol_interface_info_entry_t *cur;
00920     cur = protocol_stack_interface_info_get_by_id(interface_id);
00921     tr_debug("get native connection info");
00922     if(!cur || !cur->thread_info) {
00923         return -1;
00924     }
00925 
00926     if (thread_attach_ready(cur) != 0) {
00927         return -2;
00928     }
00929     if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, address_ptr) != 0) {
00930         return -1;
00931     }
00932     if (port) {
00933         *port = cur->thread_info->native_commissioner_port;
00934     }
00935     return 0;
00936 }
00937 
00938 int8_t thread_commissioning_get_management_id(int8_t interface_id)
00939 {
00940     commissioner_t *this = commissioner_find(interface_id);
00941     if (!this) {
00942         return -1;
00943     }
00944 
00945     return this->management_instance;
00946 }
00947 
00948 
00949 #else
00950 int thread_commissioning_register(int8_t interface_id, uint8_t PSKc[static 16]) {
00951     (void)interface_id;
00952     (void)PSKc;
00953     return -1;
00954 }
00955 
00956 int thread_commissioning_unregister(int8_t interface_id)
00957 {
00958     (void)interface_id;
00959     return -1;
00960 }
00961 
00962 int thread_commissioning_device_add(int8_t interface_id, bool short_eui64, uint8_t EUI64[static 8], uint8_t *PSKd_ptr, uint8_t PSKd_len, thread_commissioning_joiner_finalisation_cb *joining_device_cb_ptr)
00963 {
00964     (void)interface_id;
00965     (void)short_eui64;
00966     (void)EUI64;
00967     (void)PSKd_ptr;
00968     (void)PSKd_len;
00969     (void)joining_device_cb_ptr;
00970     return -1;
00971 }
00972 
00973 int thread_commissioning_device_delete(int8_t interface_id, uint8_t EUI64[8])
00974 {
00975     (void)interface_id;
00976     (void)EUI64;
00977     return -1;
00978 }
00979 void *thread_commission_device_get_next(void *ptr, int8_t interface_id, bool *short_eui64, uint8_t EUI64[8], uint8_t PSKd[32], uint8_t *PSKd_len)
00980 {
00981     (void)ptr;
00982     (void)interface_id;
00983     (void)short_eui64;
00984     (void)EUI64;
00985     (void)PSKd;
00986     (void)PSKd_len;
00987     return NULL;
00988 }
00989 
00990 int thread_commissioning_petition_keep_alive(int8_t interface_id, commissioning_state_e state)
00991 {
00992     (void)interface_id;
00993     (void)state;
00994     return -1;
00995 }
00996 
00997 int thread_commissioning_petition_start(int8_t interface_id, char *commissioner_id_ptr, thread_commissioning_status_cb *status_cb_ptr)
00998 {
00999     (void)interface_id;
01000     (void)commissioner_id_ptr;
01001     (void)status_cb_ptr;
01002     return -1;
01003 }
01004 
01005 int thread_commissioning_native_commissioner_get_connection_info(int8_t interface_id, uint8_t *address_ptr, uint16_t *port) {
01006     (void)interface_id;
01007     (void)address_ptr;
01008     (void)port;
01009     return -1;
01010 }
01011 
01012 int8_t thread_commissioning_get_management_id(int8_t interface_id) {
01013     (void)interface_id;
01014     return -1;
01015 }
01016 
01017 int thread_commissioning_native_commissioner_start(int8_t interface_id, thread_commissioning_native_select_cb *cb_ptr) {
01018     (void)interface_id;
01019     (void)cb_ptr;
01020     return -1;
01021 }
01022 
01023 int thread_commissioning_native_commissioner_stop(int8_t interface_id) {
01024     (void)interface_id;
01025     return -1;
01026 }
01027 
01028 int thread_commissioning_native_commissioner_connect(int8_t interface_id, thread_commissioning_link_configuration_s *link_ptr) {
01029     (void)interface_id;
01030     (void)link_ptr;
01031     return -1;
01032 }
01033 
01034 #endif