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_management_server.c Source File

thread_management_server.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 #include <string.h>
00033 #include <ns_types.h>
00034 #include <ns_list.h>
00035 #include <ns_trace.h>
00036 #include "nsdynmemLIB.h"
00037 #include "common_functions.h"
00038 #include "NWK_INTERFACE/Include/protocol.h"
00039 #include "6LoWPAN/Thread/thread_common.h"
00040 #include "6LoWPAN/Thread/thread_management_server.h"
00041 #include "6LoWPAN/Thread/thread_network_data_lib.h"
00042 #include "6LoWPAN/Thread/thread_leader_service.h"
00043 #include "6LoWPAN/Thread/thread_extension.h"
00044 #include "6LoWPAN/Thread/thread_discovery.h"
00045 #include "6LoWPAN/Thread/thread_bbr_api_internal.h"
00046 #include "6LoWPAN/Thread/thread_border_router_api_internal.h"
00047 #include "6LoWPAN/MAC/mac_helper.h"
00048 
00049 #define TRACE_GROUP "TMFs"
00050 
00051 #include "eventOS_event_timer.h"
00052 #include "coap_service_api.h"
00053 
00054 #include "net_interface.h"
00055 #include "socket_api.h"
00056 #include "thread_common.h"
00057 #include "thread_config.h"
00058 #include "thread_tmfcop_lib.h"
00059 #include "thread_meshcop_lib.h"
00060 #include "thread_management_if.h"
00061 #include "thread_management_internal.h"
00062 #include "thread_commissioning_if.h"
00063 #include "thread_joiner_application.h"
00064 #include "thread_beacon.h"
00065 #include "thread_bootstrap.h"
00066 #include "thread_management_server.h"
00067 #include "mac_api.h"
00068 #include "6LoWPAN/MAC/mac_data_poll.h"
00069 #include "mlme.h"
00070 
00071 #ifdef HAVE_THREAD_ROUTER
00072 
00073 typedef struct scan_query {
00074     int8_t coap_service_id;
00075     uint8_t channel_mask[6]; //<!** first byte is channel page
00076     uint16_t channel_mask_len;
00077     uint8_t *energy_list_ptr;
00078     uint8_t energy_list_length;
00079     uint8_t scan_count;
00080     timeout_t *timer;
00081     uint8_t address[16];
00082     uint16_t port;
00083     uint16_t panid;
00084     uint8_t count;
00085     uint16_t period;
00086     uint16_t duration;
00087     bool panid_scan: 1;
00088     bool energy_scan: 1;
00089 } scan_query_t;
00090 
00091 typedef struct announce {
00092     uint8_t channel_mask[6]; //<!** first byte is channel page support only channel page 0
00093     uint16_t channel_mask_len;
00094     timeout_t *timer;
00095     uint8_t count;
00096     uint16_t period;
00097     uint16_t channel;
00098 } announce_t;
00099 
00100 typedef struct thread_management_server {
00101     scan_query_t *scan_ptr;
00102     announce_t *announce_ptr;
00103     uint16_t relay_port_joiner;
00104     uint16_t external_commissioner_port;
00105     int8_t interface_id;
00106     int8_t coap_service_id;
00107     int8_t listen_socket_joiner;
00108     bool joiner_router_enabled: 1;
00109     ns_list_link_t link;
00110 } thread_management_server_t;
00111 
00112 static NS_LIST_DEFINE(instance_list, thread_management_server_t, link);
00113 void thread_energy_scan_timeout_cb(void* arg);
00114 
00115 static bool thread_channel_mask_is_channel_set(uint8_t *mask_ptr, uint8_t channel)
00116 {
00117     uint8_t n;
00118     uint8_t bit;
00119 
00120     n = (channel) / 8;
00121     bit = 1 << (7 - (channel) % 8);
00122 
00123     if (n > 5 || channel > 27)
00124         return false;
00125     if( mask_ptr[n+2] & bit  )
00126         return true;
00127     return false;
00128 }
00129 
00130 
00131 static uint8_t thread_channel_mask_count(uint8_t *mask_ptr)
00132 {
00133     uint8_t n;
00134     uint8_t result = 0;
00135     uint32_t bits;
00136 
00137     bits = common_read_32_bit(mask_ptr+2);
00138     bits = bits >> 5;// five lover bits are not used
00139     for (n= 0; n < 27;n++) {
00140         if((bits & 1)== 1)
00141             result++;
00142         bits = bits >> 1;
00143     }
00144     tr_debug ("Channel mask count = %d ", result);
00145     return result;
00146 }
00147 
00148 /*This method identifies the channels to be scanned based on the bits set in the channel mask
00149  * */
00150 static uint8_t thread_channels_to_be_scanned(uint8_t *mask_ptr)
00151 {
00152     uint8_t result = 0;
00153     uint8_t val = 1;
00154     uint8_t *ptr = mask_ptr + 2; // first two bytes do not contain the channels to be scanned
00155     uint8_t j = 0;
00156     while (j<4){
00157 
00158         // one channel for every bit that is set in the mask ptr
00159         for (int i = 0; i<8 ; i++){
00160             if (val & (*ptr)){
00161                 result++;
00162             }
00163          val = val << 1;
00164         }
00165         val = 1;
00166         ptr++;
00167         j++;
00168     }
00169     return result;
00170 }
00171 
00172 static thread_management_server_t *thread_management_server_find(int8_t interface_id)
00173 {
00174     thread_management_server_t *this = NULL;
00175     ns_list_foreach(thread_management_server_t, cur_ptr, &instance_list) {
00176         if (cur_ptr->interface_id == interface_id) {
00177             this = cur_ptr;
00178             break;
00179         }
00180     }
00181     return this;
00182 }
00183 static thread_management_server_t *thread_management_find_by_service(int8_t service_id)
00184 {
00185     thread_management_server_t *this = NULL;
00186     ns_list_foreach(thread_management_server_t, cur_ptr, &instance_list) {
00187         if (cur_ptr->coap_service_id == service_id) {
00188             this = cur_ptr;
00189             break;
00190         }
00191     }
00192     return this;
00193 }
00194 
00195 static thread_management_server_t *thread_management_find_by_sckt_id(int8_t sckt_id)
00196 {
00197     thread_management_server_t *this = NULL;
00198     ns_list_foreach(thread_management_server_t, cur_ptr, &instance_list) {
00199         if (cur_ptr->listen_socket_joiner == sckt_id) {
00200             this = cur_ptr;
00201             break;
00202         }
00203     }
00204     return this;
00205 }
00206 
00207 static bool tlv_is_requested(uint8_t *tlv_list, uint16_t list_len, uint8_t tlv)
00208 {
00209     if (!list_len || !tlv_list) {
00210         return true;
00211     }
00212     for(uint16_t n = 0; n<list_len; n++) {
00213         if (tlv_list[n] == tlv )
00214             return true;
00215     }
00216     return false;
00217 }
00218 
00219 static int thread_management_server_management_get_respond(int8_t interface_id, int8_t coap_service_id, sn_coap_hdr_s *request_ptr)
00220 {
00221     uint8_t *ptr = NULL;
00222     int response_len;
00223     uint8_t *response_ptr = NULL;
00224     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00225     link_configuration_s *link_configuration;
00226     device_configuration_s *device_configuration;
00227 
00228     link_configuration = thread_joiner_application_get_config(interface_id);
00229     device_configuration = thread_joiner_application_get_device_config(interface_id);
00230 
00231     if(!link_configuration || !device_configuration){
00232         return -1;
00233     }
00234 
00235     tr_debug("Recv MGMT_GET request");
00236 
00237     response_len = thread_joiner_application_device_configuration_length(device_configuration);
00238     response_ptr = ptr = ns_dyn_mem_alloc(response_len);
00239     if (!ptr) {
00240         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00241         tr_error("Out of resources");
00242         goto send_response;
00243     }
00244     ptr = thread_joiner_application_device_configuration_build(ptr, device_configuration);
00245     return_code = COAP_MSG_CODE_RESPONSE_CHANGED;
00246 
00247 send_response:
00248     coap_service_response_send(coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_OCTET_STREAM, response_ptr, ptr -response_ptr);
00249     ns_dyn_mem_free(response_ptr);
00250     return 0;
00251 }
00252 
00253 static int thread_management_server_active_get_respond(uint8_t interface_id, int8_t coap_service_id, sn_coap_hdr_s *request_ptr)
00254 {
00255     link_configuration_s *link_configuration;
00256     uint8_t *request_tlv_ptr = NULL;
00257     uint8_t *request_tlv_copy = NULL;
00258     uint16_t request_tlv_len;
00259     uint8_t *ptr = NULL;
00260     uint8_t *payload_ptr = NULL;
00261     uint8_t *response_ptr = NULL;
00262     uint8_t error_msg[3];
00263     int response_len;
00264     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_CHANGED;
00265 
00266     link_configuration = thread_joiner_application_get_config(interface_id);
00267     if(!link_configuration){
00268         return -1;
00269     }
00270 
00271     tr_debug("Recv MGMT_ACTIVE_GET request");
00272 
00273     request_tlv_len = thread_tmfcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_GET, &request_tlv_ptr);
00274 
00275     if(!request_tlv_len){
00276         request_tlv_copy = request_tlv_ptr = thread_joiner_application_active_config_tlv_list_get(interface_id, &request_tlv_len);
00277     }
00278 
00279     if(!request_tlv_ptr){
00280         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00281         goto send_response;
00282     }
00283 
00284     if(request_tlv_len && !(link_configuration->securityPolicy & SECURITY_POLICY_OUT_OF_BAND_COMMISSIONING_ALLOWED)){
00285         request_tlv_len = thread_meshcop_tlv_list_remove(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_NETWORK_MASTER_KEY);
00286         request_tlv_len = thread_meshcop_tlv_list_remove(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_SECURITY_POLICY);
00287     }
00288 
00289     if (!request_tlv_len) {
00290         goto send_response;
00291     }
00292 
00293     response_len = thread_joiner_application_active_config_length(interface_id, request_tlv_ptr, request_tlv_len, NULL, 0);
00294 
00295     payload_ptr = ptr = error_msg;
00296     if(response_len < 1){
00297         //Error in message is responded with Thread status or if we have access rights problem
00298         goto send_response;
00299     }
00300     payload_ptr = ptr = response_ptr = ns_dyn_mem_alloc(response_len);
00301     if (!response_ptr) {
00302         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00303         goto send_response;
00304     }
00305     memset(response_ptr, 0, response_len);
00306 
00307     ptr = thread_joiner_application_active_config_write(interface_id, ptr, request_tlv_ptr, request_tlv_len, NULL, 0);
00308 
00309 send_response:
00310     coap_service_response_send(coap_service_id, COAP_REQUEST_OPTIONS_NONE,request_ptr, return_code, COAP_CT_OCTET_STREAM,payload_ptr, ptr - payload_ptr);
00311     ns_dyn_mem_free(response_ptr);
00312     ns_dyn_mem_free(request_tlv_copy);
00313     return 0;
00314 }
00315 
00316 static int thread_management_server_pending_get_respond(int8_t interface_id, int8_t coap_service_id, sn_coap_hdr_s *request_ptr)
00317 {
00318     link_configuration_s *link_configuration;
00319     uint8_t *request_tlv_ptr = NULL;
00320     uint8_t *request_tlv_copy = NULL;
00321     uint16_t request_tlv_len;
00322     uint8_t *ptr;
00323     uint8_t *payload_ptr;
00324     uint8_t *response_ptr = NULL;
00325     uint8_t error_msg[3];
00326     int response_len;
00327     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_CHANGED;
00328 
00329     tr_debug("Recv MGMT_PENDING_GET request");
00330     payload_ptr = ptr = error_msg;
00331     link_configuration = thread_joiner_application_get_config(interface_id);
00332 
00333     if (!link_configuration) {
00334         return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00335         goto send_response;
00336     }
00337     if (!thread_joiner_application_pending_config_exists(interface_id)) {
00338         goto send_response;
00339     }
00340 
00341     request_tlv_len = thread_tmfcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_GET, &request_tlv_ptr);
00342 
00343     if(!request_tlv_len){
00344         request_tlv_copy = request_tlv_ptr = thread_joiner_application_pending_config_tlv_list_get(interface_id, &request_tlv_len);
00345     }
00346 
00347     if(!request_tlv_ptr){
00348         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00349         goto send_response;
00350     }
00351 
00352     if(request_tlv_len && !(link_configuration->securityPolicy & SECURITY_POLICY_OUT_OF_BAND_COMMISSIONING_ALLOWED)){
00353         request_tlv_len = thread_meshcop_tlv_list_remove(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_NETWORK_MASTER_KEY);
00354         request_tlv_len = thread_meshcop_tlv_list_remove(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_SECURITY_POLICY);
00355     }
00356 
00357     if (!request_tlv_len) {
00358         goto send_response;
00359     }
00360 
00361     response_len = thread_joiner_application_pending_config_length(interface_id, request_tlv_ptr, request_tlv_len, NULL, 0);
00362 
00363     payload_ptr = ptr = response_ptr = ns_dyn_mem_alloc(response_len);
00364     if (!response_ptr) {
00365         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00366         goto send_response;
00367     }
00368     memset(response_ptr, 0, response_len);
00369 
00370     ptr = thread_joiner_application_pending_config_build(interface_id, ptr,request_tlv_ptr, request_tlv_len, NULL, 0);
00371 
00372 send_response:
00373     coap_service_response_send(coap_service_id, COAP_REQUEST_OPTIONS_NONE,request_ptr, return_code, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr);
00374     ns_dyn_mem_free(response_ptr);
00375     ns_dyn_mem_free(request_tlv_copy);
00376     return 0;
00377 }
00378 
00379 /**
00380  * Thread management GET command callback.
00381  * Handle messages:
00382  * -MGMT_GET (uri = /c/mg),
00383  * -MGMT_ACTIVE_GET (uri = /c/ag),
00384  * -MGMT_PENDING_GET (uri = /c/pg)
00385  */
00386 static int thread_management_server_get_command_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00387 {
00388     (void) source_port;
00389 
00390     thread_management_server_t *this = thread_management_find_by_service(service_id);
00391 
00392     if (!this) {
00393         return -1;
00394     }
00395 
00396     if (!thread_management_server_source_address_check(this->interface_id, source_address)) {
00397         // request is coming from illegal address, return error immediately
00398         coap_service_response_send(service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_BAD_REQUEST, COAP_CT_OCTET_STREAM, NULL, 0);
00399         return 0;
00400     }
00401 
00402     return thread_management_server_tmf_get_request_handler(this->interface_id, service_id, request_ptr);
00403 
00404 }
00405 
00406 static int thread_management_server_commissioner_get_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00407 {
00408     (void) source_address;
00409     (void) source_port;
00410     protocol_interface_info_entry_t *cur;
00411     thread_management_server_t *this = thread_management_find_by_service(service_id);
00412     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_CHANGED;
00413     uint8_t response_msg[2+2 + 2+2 + 2+16 +2+2];
00414     uint8_t *request_tlv_ptr = NULL;
00415     uint16_t request_tlv_len;
00416     uint8_t *ptr;
00417     uint8_t *payload_ptr = NULL;
00418     if (!this) {
00419         return -1;
00420     }
00421     tr_debug("Thread management commission get request");
00422     cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00423     if (!cur || !cur->thread_info) {
00424         return -1;
00425     }
00426     payload_ptr = ptr = response_msg;
00427 
00428     if (!thread_management_server_source_address_check(this->interface_id, source_address)) {
00429         return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00430         goto send_response;
00431     }
00432 
00433     if (!cur->thread_info->registered_commissioner.commissioner_valid) {
00434         //Error in message is responded with Thread status or if we have access rights problem
00435         tr_warn("No registered commissioner");
00436         ptr = thread_tmfcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 0xff);
00437         goto send_response;
00438     }
00439     uint16_t border_router_locator = common_read_16_bit( &cur->thread_info->registered_commissioner.border_router_address[14]);
00440     request_tlv_len = thread_tmfcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_GET, &request_tlv_ptr);
00441 
00442     if (tlv_is_requested(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_BORDER_ROUTER_LOCATOR))
00443         ptr = thread_meshcop_tlv_data_write_uint16(ptr,MESHCOP_TLV_BORDER_ROUTER_LOCATOR, border_router_locator);
00444 
00445     if (tlv_is_requested(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID))
00446         ptr = thread_meshcop_tlv_data_write_uint16(ptr,MESHCOP_TLV_COMMISSIONER_SESSION_ID, cur->thread_info->registered_commissioner.session_id);
00447 
00448     if (tlv_is_requested(request_tlv_ptr, request_tlv_len, MESHCOP_TLV_STEERING_DATA))
00449         ptr = thread_meshcop_tlv_data_write(ptr,MESHCOP_TLV_STEERING_DATA, cur->thread_info->registered_commissioner.steering_data_len, cur->thread_info->registered_commissioner.steering_data);
00450 
00451     if (payload_ptr == ptr) {
00452         tr_warn("No TLVs found");
00453         ptr = thread_tmfcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 0xff);
00454         goto send_response;
00455     }
00456 send_response:
00457     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE,request_ptr, return_code, COAP_CT_OCTET_STREAM,payload_ptr, ptr - payload_ptr);
00458     return 0;
00459 }
00460 
00461 static int thread_start_mac_with_link_configuration(protocol_interface_info_entry_t *cur, link_configuration_s *linkConfiguration)
00462 {
00463         mlme_start_t start_req;
00464         memset(&start_req, 0, sizeof(mlme_start_t));
00465         /*Enable RF interface */
00466         if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
00467             mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true);
00468         } else {
00469             mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, false);
00470         }
00471 
00472         mac_helper_default_security_level_set(cur, SEC_ENC_MIC32);
00473         mac_helper_default_security_key_id_mode_set(cur,MAC_KEY_ID_MODE_IDX);
00474 
00475         cur->mac_parameters->mac_channel = linkConfiguration->rfChannel;
00476         cur->mac_parameters->pan_id = linkConfiguration->panId;
00477         cur->mac_parameters->mac_channel = linkConfiguration->rfChannel;
00478 
00479         start_req.PANId = linkConfiguration->panId;
00480         start_req.LogicalChannel = linkConfiguration->rfChannel;
00481         start_req.ChannelPage = 0;
00482         start_req.BeaconOrder = 0x0f;
00483         start_req.SuperframeOrder = 0x0f;
00484 
00485         cur->interface_mode = INTERFACE_UP;
00486         thread_discovery_responser_enable(cur->id, false);
00487         if( cur->mac_api ){
00488             cur->mac_api->mlme_req(cur->mac_api, MLME_START, (void*)&start_req);
00489         }
00490         if (cur->thread_info->sleepy_host_poll_time != 0) {
00491             mac_data_poll_host_mode_set(cur,NET_HOST_SLOW_POLL_MODE,cur->thread_info->sleepy_host_poll_time);
00492         } else {
00493             mac_data_poll_init(cur);
00494         }
00495 
00496         return 0;
00497 }
00498 
00499 
00500 static void thread_panid_conflict_timeout_cb(void* arg)
00501 {
00502     uint8_t payload[12];// 2+6 + 2+2
00503     uint8_t *ptr;
00504     thread_management_server_t *this = arg;
00505     if(!this || !this->scan_ptr)
00506     {
00507         tr_error("panid conflict scan ptr missing");
00508         return;
00509     }
00510 
00511     this->scan_ptr->timer = NULL;
00512 
00513     ptr = payload;
00514     ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_PANID, this->scan_ptr->panid);
00515     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_CHANNEL_MASK, this->scan_ptr->channel_mask_len, this->scan_ptr->channel_mask);
00516     //Send pan id conflict coap
00517     coap_service_request_send(this->scan_ptr->coap_service_id, COAP_REQUEST_OPTIONS_NONE, this->scan_ptr->address, this->scan_ptr->port,
00518                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_PANID_CONFLICT, COAP_CT_OCTET_STREAM, payload, ptr - payload, NULL);
00519     ns_dyn_mem_free(this->scan_ptr);
00520     this->scan_ptr = NULL;
00521 }
00522 
00523 //style = 0 means thread style, style = anything else means zigbee style
00524 // for thread style the bit is set from left to right and for zigbee style it is set from right to left
00525 static void set_channel_mask(uint8_t *channel_mask,uint8_t channel_number, uint8_t style)
00526 {
00527     uint8_t byte_position;
00528     uint8_t bit_position;
00529     if (0 == style){
00530         byte_position = channel_number / 8;
00531         bit_position = 7 - (channel_number % 8);
00532         channel_mask[byte_position + 2] |= (1 << bit_position);
00533         return;
00534     }
00535     else {
00536         byte_position = 3 - (channel_number / 8);
00537         bit_position = channel_number % 8;
00538         channel_mask[byte_position + 2] |= (1 << bit_position);
00539         return;
00540     }
00541 }
00542 static uint32_t reverse_bits(uint32_t num)
00543 {
00544     uint32_t NO_OF_BITS = sizeof(num) * 8;
00545     uint32_t reversed_value = 0, i, temp;
00546     for (i = 0; i < NO_OF_BITS; i++){
00547         temp = (num & (1 << i));
00548         if(temp)
00549             reversed_value |= (1 << ((NO_OF_BITS - 1) - i));
00550     }
00551     return reversed_value;
00552 }
00553 static void thread_panid_scan_response(int8_t if_id, const mlme_scan_conf_t* conf)
00554 {
00555         bool conflict_occured = false;
00556         nwk_scan_params_t *scan_parameters_ptr;
00557         nwk_pan_descriptor_t *result;
00558         protocol_interface_info_entry_t *interface;
00559         link_configuration_s *linkConfiguration;
00560 
00561         if (conf->ScanType != MAC_ACTIVE_SCAN) {
00562             tr_error("Not active scan");
00563             return;
00564         }
00565 
00566         interface = protocol_stack_interface_info_get_by_id(if_id);
00567         if (!interface) {
00568             tr_error("Mac scan confirm:Unknow Interface");
00569             return;
00570         }
00571 
00572         linkConfiguration = thread_joiner_application_get_config(if_id);
00573         if (!linkConfiguration) {
00574             return;
00575         }
00576 
00577         scan_parameters_ptr = &interface->mac_parameters->nwk_scan_params; //mac_mlme_get_scan_params(interface);
00578         if (!scan_parameters_ptr ||!scan_parameters_ptr->nwk_response_info || !conf->ResultListSize) {
00579             tr_debug("Mac scan confirm:No Beacons");
00580             thread_start_mac_with_link_configuration(interface,linkConfiguration);
00581             return;
00582         }
00583         scan_parameters_ptr->active_scan_active = false;
00584 
00585         thread_management_server_t *this = thread_management_server_find(if_id);
00586 
00587         if (!this) {
00588             return;
00589         }
00590 
00591         result = scan_parameters_ptr->nwk_response_info;
00592         // reset all channel masks
00593         this->scan_ptr->channel_mask[2] = 0x00;
00594         this->scan_ptr->channel_mask[3] = 0x00;
00595         this->scan_ptr->channel_mask[4] = 0x00;
00596         this->scan_ptr->channel_mask[5] = 0x00;
00597     do {
00598         tr_debug("Mac scan confirm:scanning results");
00599         if(result->pan_descriptor->CoordPANId == this->scan_ptr->panid) { //if pan id matches then send a conflict message
00600                 tr_debug("Same pan id was found on channel %d", result->pan_descriptor->LogicalChannel);
00601                 set_channel_mask(this->scan_ptr->channel_mask,result->pan_descriptor->LogicalChannel,0);
00602                 conflict_occured = true;
00603     }
00604     result = result->next;
00605     } while (result);
00606     if (conflict_occured){
00607         tr_debug("conflict occured");
00608         this->scan_ptr->timer = eventOS_timeout_ms(thread_panid_conflict_timeout_cb, 2000, this);
00609     }
00610     thread_start_mac_with_link_configuration(interface,linkConfiguration);
00611     //TODO if no conflict scan again after delay seconds
00612 }
00613 static int thread_management_server_energy_scan_response_resp_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00614 {
00615     // Dummy response handler needed as otherwise retransmissions dont work in coap service.
00616     (void)service_id;
00617     (void)source_address;
00618     (void)source_port;
00619     (void)response_ptr;
00620     return 0;
00621 }
00622 
00623 static void thread_energy_scan_coap(thread_management_server_t *arg)
00624 {
00625     uint8_t *ptr;
00626     thread_management_server_t *this = arg;
00627     link_configuration_s *linkConfiguration;
00628     protocol_interface_info_entry_t *interface;
00629 
00630     linkConfiguration = thread_joiner_application_get_config(this->interface_id);
00631     if (!linkConfiguration) {
00632         return;
00633     }
00634 
00635     interface = protocol_stack_interface_info_get_by_id(this->interface_id);
00636     if (!interface) {
00637         tr_error("Mac scan confirm:Unknow Interface");
00638         return;
00639     }
00640 
00641     thread_start_mac_with_link_configuration(interface,linkConfiguration);
00642     uint8_t channel_count = thread_channels_to_be_scanned(this->scan_ptr->channel_mask);
00643     tr_debug("energy scan result mask %s, result %s, count %d",trace_array(this->scan_ptr->channel_mask,6),
00644              trace_array(this->scan_ptr->energy_list_ptr,channel_count* this->scan_ptr->count),channel_count);
00645 
00646 
00647     uint8_t *payload_ptr = ns_dyn_mem_alloc( 2 + 6 + 2 + channel_count * this->scan_ptr->count);
00648     if (!payload_ptr) {
00649         tr_error("out of resources");
00650         return;
00651     }
00652     ptr = payload_ptr;
00653 
00654     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_CHANNEL_MASK, this->scan_ptr->channel_mask_len, this->scan_ptr->channel_mask);
00655     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_ENERGY_LIST, channel_count * this->scan_ptr->count, this->scan_ptr->energy_list_ptr);
00656 
00657     coap_service_request_send(this->scan_ptr->coap_service_id, COAP_REQUEST_OPTIONS_NONE, this->scan_ptr->address, this->scan_ptr->port,
00658                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_ED_REPORT, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr, thread_management_server_energy_scan_response_resp_cb);
00659     ns_dyn_mem_free(payload_ptr);
00660     ns_dyn_mem_free(this->scan_ptr->energy_list_ptr);
00661     ns_dyn_mem_free(this->scan_ptr);
00662     this->scan_ptr = NULL;
00663 }
00664 
00665 static void energy_scan_confirm_cb(int8_t if_id, const mlme_scan_conf_t* conf)
00666 {
00667     if (conf->ScanType != MAC_ED_SCAN_TYPE) {
00668         tr_error("Not energy scan");
00669         return;
00670     }
00671 
00672     if (conf->ResultListSize < 1){
00673         tr_error("No scan responses");
00674         return;
00675     }
00676 
00677     protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(if_id);
00678     if (!interface) {
00679         tr_error("could not get interface");
00680         return;
00681     }
00682 
00683     thread_management_server_t *this = thread_management_server_find(if_id);
00684     if (!this) {
00685         tr_error("could not find thread management server");
00686         return;
00687     }
00688     // reduce the scan_count by one since one scan has been performed and results are also obtained
00689     this->scan_ptr->scan_count--;
00690 
00691     for( int i=0; i < conf->ResultListSize; i++){
00692         *this->scan_ptr->energy_list_ptr++ = conf->ED_values[i];
00693     }
00694 
00695     link_configuration_s *linkConfiguration = thread_joiner_application_get_config(this->interface_id);
00696     if (!linkConfiguration) {
00697         return;
00698     }
00699 
00700     //the energy list has now the response_size set of responses so increase the length of energy_list_length
00701     this->scan_ptr->energy_list_length += conf->ResultListSize;
00702 
00703     // if all scans have been completed then, move the energy_list_ptr back to the beginning
00704     if (this->scan_ptr->scan_count == 0){
00705         this->scan_ptr->energy_list_ptr-=this->scan_ptr->energy_list_length;
00706         thread_energy_scan_coap(this);
00707     }
00708     else{
00709         // if all scans have not been completed, enable RF, wait for scan period and call energy scan method again
00710         thread_start_mac_with_link_configuration(interface,linkConfiguration);
00711         if (this->scan_ptr->timer) {
00712             eventOS_timeout_cancel(this->scan_ptr->timer);
00713         }
00714         this->scan_ptr->timer = eventOS_timeout_ms(thread_energy_scan_timeout_cb, this->scan_ptr->period, this);
00715     }
00716 }
00717 
00718 void thread_energy_scan_timeout_cb(void* arg)
00719 {
00720     link_configuration_s *linkConfiguration;
00721     thread_management_server_t *this = arg;
00722     if(!this || !this->scan_ptr || !this->scan_ptr->energy_list_ptr){
00723         tr_error("Invalid query");
00724         return;
00725     }
00726 
00727     this->scan_ptr->timer = NULL;
00728 
00729     linkConfiguration = thread_joiner_application_get_config(this->interface_id);
00730     if (!linkConfiguration) {
00731         return;
00732     }
00733 
00734     protocol_interface_info_entry_t *s;
00735     s = protocol_stack_interface_info_get_by_id(this->interface_id);
00736 
00737     if (!s) {
00738         return;
00739     }
00740 
00741     uint32_t channel_mask = 0;
00742     channel_mask = (this->scan_ptr->channel_mask[2]<<24) | (this->scan_ptr->channel_mask[3]<<16)| (this->scan_ptr->channel_mask[4]<<8) | (this->scan_ptr->channel_mask[5]);
00743     //Modify reversed_mask after the right way to interpret channel mask is obtained
00744     uint32_t reversed_mask = reverse_bits(channel_mask);
00745     channel_mask = reversed_mask;
00746     s->mac_parameters->nwk_scan_params.stack_chan_list.channel_mask[0] = channel_mask;
00747     //Channel page is 0 for thread
00748     s->mac_parameters->nwk_scan_params.stack_chan_list.channel_page = CHANNEL_PAGE_0;
00749 
00750     // Convert duration in ms to MAC exponent value
00751     uint8_t duration_n;
00752     if(this->scan_ptr->duration <= (CHANNEL_PAGE_0_SUPERFRAME_DURATION * 2)) {
00753         duration_n = 0;
00754     } else {
00755         duration_n = thread_log2_aprx((this->scan_ptr->duration / CHANNEL_PAGE_0_SUPERFRAME_DURATION) - 1);
00756     }
00757 
00758     // 10 == 15.7s
00759     // 11 == 31.5s
00760     // 12 == 62.9s
00761     // 13 == 125.8s (maximum when duration is 65535 and result of log2 is rounded up)
00762     // 14 == 251.6s (not possible)
00763     tr_debug("Start Energy scan duration:%d", duration_n);
00764     mac_data_poll_disable(s);
00765     mlme_scan_t req;
00766     mac_create_scan_request(MAC_ED_SCAN_TYPE, &s->mac_parameters->nwk_scan_params.stack_chan_list, duration_n, &req);
00767     if( s->mac_api ){
00768         s->scan_cb = energy_scan_confirm_cb;
00769         s->mac_api->mlme_req(s->mac_api, MLME_SCAN, &req);
00770     }
00771 }
00772 
00773 
00774 static void thread_panid_scan_timeout_cb(void* arg)
00775 {
00776     thread_management_server_t *this = arg;
00777     if(!this || !this->scan_ptr)
00778         return;
00779 
00780     this->scan_ptr->timer = NULL;
00781 
00782 
00783     protocol_interface_info_entry_t *s;
00784     s = protocol_stack_interface_info_get_by_id(this->interface_id);
00785 
00786     if (!s || !s->mac_api) {
00787         return;
00788     }
00789 
00790     uint32_t channel_mask = 0;
00791     channel_mask = (this->scan_ptr->channel_mask[2]<<24) | (this->scan_ptr->channel_mask[3]<<16)| (this->scan_ptr->channel_mask[4]<<8) | (this->scan_ptr->channel_mask[5]);
00792     //Modify reversed_mask after the right way to interpret channel mask is obtained
00793     uint32_t reversed_mask = reverse_bits(channel_mask);
00794     channel_mask = reversed_mask;
00795     s->mac_parameters->nwk_scan_params.stack_chan_list.channel_mask[0] = channel_mask;
00796     //Channel page is 0 for thread
00797     s->mac_parameters->nwk_scan_params.stack_chan_list.channel_page = CHANNEL_PAGE_0;
00798     mac_data_poll_disable(s);
00799     mlme_scan_t req;
00800     mac_create_scan_request(MAC_ACTIVE_SCAN, &s->mac_parameters->nwk_scan_params.stack_chan_list, 5, &req);
00801     /*
00802     Before commencing an active or passive scan, the MAC sub-layer shall store the value of macPANId and
00803     then set it to 0xffff for the duration of the scan. This enables the receive filter to accept all beacons rather
00804     than just the beacons from its current PAN, as described in 5.1.6.2. On completion of the scan, the MAC
00805     sub-layer shall restore the value of macPANId to the value stored before the scan began.
00806      */
00807     mac_helper_panid_set(s,0xffff);
00808 
00809     s->scan_cb = thread_panid_scan_response;
00810     s->mac_parameters->nwk_scan_params.active_scan_active = true;
00811     s->mac_api->mlme_req(s->mac_api, MLME_SCAN, &req);
00812 }
00813 
00814 
00815 /**
00816  * Thread PANID scan request
00817  */
00818 static int thread_management_server_panid_query_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00819 {
00820     thread_management_server_t *this = thread_management_find_by_service(service_id);
00821     sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00822     uint16_t session_id;
00823     uint16_t panid;
00824     uint8_t *mask_ptr;
00825     uint8_t mask_len;
00826 
00827     if (!this) {
00828         return -1;
00829     }
00830     tr_debug("thread management panid query");
00831     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &session_id)) {
00832         tr_warn("Missing Session id TLV");
00833         goto error_exit;
00834     }
00835     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_PANID, &panid)) {
00836         tr_warn("Missing PANID TLV");
00837         goto error_exit;
00838     }
00839     mask_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_CHANNEL_MASK, &mask_ptr);
00840     if (mask_len < 6 ) {
00841         tr_warn("Missing channel mask TLV");
00842         goto error_exit;
00843     }
00844     tr_info("PANID TLV %02x, session_id %d, Channel mask TLV %s", panid, session_id, trace_array(mask_ptr, 5));
00845 
00846     if (!this->scan_ptr) {
00847         this->scan_ptr = ns_dyn_mem_alloc(sizeof(scan_query_t));
00848         memset(this->scan_ptr,0,sizeof(scan_query_t));
00849     } else {
00850         eventOS_timeout_cancel(this->scan_ptr->timer);
00851         this->scan_ptr->timer = NULL;
00852     }
00853     if (!this->scan_ptr) {
00854         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00855         goto error_exit;
00856     }
00857     this->scan_ptr->timer = eventOS_timeout_ms(thread_panid_scan_timeout_cb, 500, this);// Delay for the confirm response message
00858     if (!this->scan_ptr->timer) {
00859         ns_dyn_mem_free(this->scan_ptr);
00860         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00861         goto error_exit;
00862     }
00863 
00864     this->scan_ptr->coap_service_id = service_id;
00865     memcpy(this->scan_ptr->channel_mask,mask_ptr,mask_len);
00866     this->scan_ptr->channel_mask_len = mask_len;
00867     this->scan_ptr->port = source_port;
00868     memcpy(this->scan_ptr->address,source_address,16);
00869     this->scan_ptr->panid = panid;
00870     this->scan_ptr->panid_scan = true;
00871 
00872     if (request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE ){
00873         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);
00874         return 0;
00875     }
00876     return -1;
00877 error_exit:
00878     this->scan_ptr = NULL;
00879     if (request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE ){
00880         coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, NULL, 0);
00881         return 0;
00882     }
00883 
00884     return -1;
00885 }
00886 /**
00887  * Thread PANID scan request
00888  */
00889 static int thread_management_server_energy_scan_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00890 {
00891     thread_management_server_t *this = thread_management_find_by_service(service_id);
00892     sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00893     uint16_t period;
00894     uint16_t session_id;
00895     uint8_t count;
00896     uint16_t duration;
00897     uint8_t *mask_ptr;
00898     uint8_t mask_len;
00899 
00900 
00901     if (!this) {
00902         return -1;
00903     }
00904     tr_debug("thread management energy scan");
00905     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_PERIOD, &period)) {
00906         tr_warn("Missing PERIOD TLV");
00907         goto error_exit;
00908     }
00909     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &session_id)) {
00910         tr_warn("Missing Session id TLV");
00911         goto error_exit;
00912     }
00913     if (1 > thread_meshcop_tlv_data_get_uint8(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COUNT, &count)) {
00914         tr_warn("Missing COUNT TLV");
00915         goto error_exit;
00916     }
00917     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_DURATION, &duration)) {
00918         tr_warn("Missing DURATION TLV");
00919         goto error_exit;
00920     }
00921     mask_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_CHANNEL_MASK, &mask_ptr);
00922     if (mask_len < 6 ) {
00923         tr_warn("Missing channel mask TLV");
00924         goto error_exit;
00925     }
00926     tr_info("Channel mask TLV %s, period %d, count %d, duration %d", trace_array(mask_ptr, mask_len), period, count, duration);
00927 
00928     if (count < 1  || thread_channel_mask_count(mask_ptr) < 1 ) {
00929         // Sanity checks
00930         response_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE;
00931         goto error_exit;
00932     }
00933     if (!this->scan_ptr) {
00934         this->scan_ptr = ns_dyn_mem_alloc(sizeof(scan_query_t));
00935         memset(this->scan_ptr,0,sizeof(scan_query_t));
00936     } else {
00937         eventOS_timeout_cancel(this->scan_ptr->timer);
00938         this->scan_ptr->timer = NULL;
00939     }
00940     if (!this->scan_ptr) {
00941         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00942         goto error_exit;
00943     }
00944     uint16_t channel_count = thread_channels_to_be_scanned(mask_ptr);
00945 
00946     this->scan_ptr->energy_list_length = 0;
00947     this->scan_ptr->scan_count = count;
00948 
00949     // allocate memory for the energy scan results
00950     this->scan_ptr->energy_list_ptr = ns_dyn_mem_temporary_alloc(channel_count * this->scan_ptr->scan_count);
00951     if(!this->scan_ptr->energy_list_ptr){
00952         response_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE;
00953         tr_debug ("Exiting after no energy list ptr was allocated");
00954         goto error_exit;
00955     }
00956 
00957     memset(this->scan_ptr->energy_list_ptr,0,(channel_count* this->scan_ptr->scan_count));
00958 
00959     this->scan_ptr->timer = eventOS_timeout_ms(thread_energy_scan_timeout_cb, 500, this);
00960 
00961     if (!this->scan_ptr->timer) {
00962         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00963         goto error_exit;
00964     }
00965 
00966     this->scan_ptr->coap_service_id = service_id;
00967     memcpy(this->scan_ptr->channel_mask,mask_ptr,mask_len);
00968     this->scan_ptr->channel_mask_len = mask_len;
00969     this->scan_ptr->port = source_port;
00970     memcpy(this->scan_ptr->address,source_address,16);
00971     this->scan_ptr->count = count;
00972     this->scan_ptr->duration = duration;
00973     this->scan_ptr->period = period;
00974     this->scan_ptr->energy_scan = true;
00975 
00976 
00977     if (request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE ){
00978         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);
00979         return 0;
00980     }
00981     return -1;
00982 error_exit:
00983     if(this->scan_ptr) {
00984         ns_dyn_mem_free(this->scan_ptr->energy_list_ptr);
00985         ns_dyn_mem_free(this->scan_ptr);
00986     }
00987     this->scan_ptr = NULL;
00988 
00989     if (request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE ){
00990         coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, NULL, 0);
00991         return 0;
00992     }
00993 
00994     return -1;
00995 }
00996 
00997 
00998 static void thread_announce_timeout_cb(void* arg)
00999 {
01000     link_configuration_s *linkConfiguration;
01001     thread_management_server_t *this = arg;
01002     protocol_interface_info_entry_t *cur;
01003 
01004     if(!this || !this->announce_ptr) {
01005         return;
01006     }
01007 
01008     this->announce_ptr->timer = NULL;
01009 
01010     cur = protocol_stack_interface_info_get_by_id(this->interface_id);
01011     linkConfiguration = thread_joiner_application_get_config(this->interface_id);
01012     if (!cur || !linkConfiguration) {
01013         return;
01014     }
01015     while (this->announce_ptr->channel < 27) {
01016         if(thread_channel_mask_is_channel_set(this->announce_ptr->channel_mask, this->announce_ptr->channel)) {
01017             break;
01018         }
01019         this->announce_ptr->channel++;
01020     }
01021     if(this->announce_ptr->channel > 26) {
01022         tr_debug("Announce done");
01023         ns_dyn_mem_free(this->announce_ptr);
01024         this->announce_ptr = NULL;
01025         return;
01026     }
01027     tr_debug("Announce to channel %d",this->announce_ptr->channel);
01028 
01029     thread_bootstrap_announcement_start(cur,this->announce_ptr->channel_mask[0],this->announce_ptr->channel, this->announce_ptr->count, this->announce_ptr->period);
01030 
01031     this->announce_ptr->channel++; // Next time we start the next channel
01032     this->announce_ptr->timer = eventOS_timeout_ms(thread_announce_timeout_cb, 5000, this);
01033     if (!this->announce_ptr->timer) {
01034         tr_warn("Announce failed");
01035         ns_dyn_mem_free(this->announce_ptr);
01036         this->announce_ptr = NULL;
01037         return;
01038     }
01039 }
01040 
01041 static int thread_management_server_announce_begin_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
01042 {
01043     thread_management_server_t *this = thread_management_find_by_service(service_id);
01044     link_configuration_s *linkConfiguration;
01045     sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01046     uint16_t period;
01047     uint16_t session_id;
01048     uint8_t count;
01049     uint8_t *mask_ptr;
01050     uint8_t mask_len;
01051 
01052     (void)source_address;
01053     (void)source_port;
01054 
01055     if (!this) {
01056         return -1;
01057     }
01058     linkConfiguration = thread_joiner_application_get_config(this->interface_id);
01059     if (!linkConfiguration) {
01060         return -1;
01061     }
01062 
01063     tr_debug("thread management announce begin");
01064     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &session_id)) {
01065         tr_warn("Missing Session id TLV");
01066         goto error_exit;
01067     }
01068     if (2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_PERIOD, &period)) {
01069         tr_warn("Missing PERIOD TLV");
01070         goto error_exit;
01071     }
01072     if (1 > thread_meshcop_tlv_data_get_uint8(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COUNT, &count)) {
01073         tr_warn("Missing COUNT TLV");
01074         goto error_exit;
01075     }
01076     mask_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_CHANNEL_MASK, &mask_ptr);
01077     if (mask_len < 6 ) {
01078         tr_warn("Missing channel mask TLV");
01079         goto error_exit;
01080     }
01081     // TODO validity checks session id must be validated
01082     tr_info("start announcing session id %d, mask TLV %s, period %d, count %d",session_id, trace_array(mask_ptr, mask_len), period, count);
01083 
01084     if (!this->announce_ptr) {
01085         this->announce_ptr = ns_dyn_mem_alloc(sizeof(announce_t));
01086     } else {
01087         eventOS_timeout_cancel(this->announce_ptr->timer);
01088         this->announce_ptr->timer = NULL;
01089     }
01090     if (!this->announce_ptr) {
01091         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
01092         goto error_exit;
01093     }
01094     this->announce_ptr->timer = eventOS_timeout_ms(thread_announce_timeout_cb, 500, this);
01095     if (!this->announce_ptr->timer) {
01096         ns_dyn_mem_free(this->announce_ptr);
01097         response_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
01098         goto error_exit;
01099     }
01100     memcpy(this->announce_ptr->channel_mask,mask_ptr,mask_len);
01101     this->announce_ptr->channel_mask_len = mask_len;
01102     this->announce_ptr->count = count;
01103     this->announce_ptr->period = period;
01104     this->announce_ptr->channel = 0;
01105 // Set own information to announce
01106     response_code = COAP_MSG_CODE_RESPONSE_CHANGED;
01107 
01108     error_exit:
01109     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, NULL, 0);
01110     return 0;
01111 }
01112 
01113 /**
01114  * Public interface functions
01115  */
01116 int thread_management_server_init(int8_t interface_id)
01117 {
01118 
01119     thread_management_server_t *this = thread_management_server_find(interface_id);
01120     if (this) {
01121         return 0;
01122     }
01123 
01124     this = ns_dyn_mem_alloc(sizeof(thread_management_server_t));
01125     if (!this) {
01126         return -2;
01127     }
01128 
01129     this->joiner_router_enabled = false;
01130     this->interface_id = interface_id;
01131     this->listen_socket_joiner = -1;
01132     this->relay_port_joiner = 0;
01133     this->scan_ptr = NULL;
01134     this->announce_ptr = NULL;
01135     this->external_commissioner_port = THREAD_COMMISSIONING_PORT;
01136 
01137     if (thread_border_router_init(this->interface_id) != 0) {
01138         ns_dyn_mem_free(this);
01139         return -5;
01140     }
01141 
01142     if (thread_bbr_init(this->interface_id, this->external_commissioner_port) != 0) {
01143         ns_dyn_mem_free(this);
01144         return -5;
01145     }
01146 
01147     this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL);
01148     if (this->coap_service_id < 0) {
01149         tr_warn("Thread management init failed");
01150         ns_dyn_mem_free(this);
01151         return -3;
01152     }
01153 
01154     if (thread_leader_service_init(interface_id, this->coap_service_id) != 0) {
01155         tr_warn("Thread leader service init failed");
01156         ns_dyn_mem_free(this);
01157         return -3;
01158     }
01159     thread_extension_init(interface_id, this->coap_service_id);
01160 
01161     // All thread devices
01162     coap_service_register_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_GET, COAP_SERVICE_ACCESS_GET_ALLOWED, thread_management_server_get_command_cb);
01163 
01164     // Full functioning devices(Router,reed,fed)
01165     coap_service_register_uri(this->coap_service_id, THREAD_URI_ACTIVE_GET, COAP_SERVICE_ACCESS_GET_ALLOWED, thread_management_server_get_command_cb);
01166     coap_service_register_uri(this->coap_service_id, THREAD_URI_PENDING_GET, COAP_SERVICE_ACCESS_GET_ALLOWED, thread_management_server_get_command_cb);
01167     coap_service_register_uri(this->coap_service_id, THREAD_URI_COMMISSIONER_GET, COAP_SERVICE_ACCESS_GET_ALLOWED, thread_management_server_commissioner_get_cb);
01168 
01169     coap_service_register_uri(this->coap_service_id, THREAD_URI_PANID_QUERY, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_management_server_panid_query_cb);
01170     coap_service_register_uri(this->coap_service_id, THREAD_URI_ED_SCAN, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_management_server_energy_scan_cb);
01171     coap_service_register_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_ANNOUNCE_BEGIN, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_management_server_announce_begin_cb);
01172 
01173     ns_list_add_to_start(&instance_list, this);
01174     return 0;
01175 }
01176 
01177 void thread_management_server_delete(int8_t interface_id)
01178 {
01179     thread_management_server_t *this = thread_management_server_find(interface_id);
01180     if (!this) {
01181         return;
01182     }
01183 
01184     thread_leader_service_delete(interface_id);
01185 
01186     if (this->joiner_router_enabled) {
01187         thread_management_server_joiner_router_deinit(interface_id);
01188     }
01189     //TODO move uri deletion to delete
01190     coap_service_unregister_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_GET);
01191     coap_service_unregister_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_SET);
01192     coap_service_delete(this->coap_service_id);
01193     ns_list_remove(&instance_list, this);
01194     if (this->announce_ptr) {
01195         if (this->announce_ptr->timer) {
01196             eventOS_timeout_cancel(this->announce_ptr->timer);
01197         }
01198         ns_dyn_mem_free(this->announce_ptr);
01199     }
01200     if (this->scan_ptr) {
01201         if (this->scan_ptr->timer) {
01202             eventOS_timeout_cancel(this->scan_ptr->timer);
01203         }
01204         if (this->scan_ptr->energy_list_ptr) {
01205             ns_dyn_mem_free(this->scan_ptr->energy_list_ptr);
01206         }
01207         ns_dyn_mem_free(this->scan_ptr);
01208     }
01209 
01210     ns_dyn_mem_free(this);
01211 
01212     thread_border_router_delete(interface_id);
01213     thread_bbr_delete(interface_id);
01214     return;
01215 }
01216 
01217 int8_t thread_management_server_interface_id_get(int8_t coap_service_id)
01218 {
01219     thread_management_server_t *this = thread_management_find_by_service(coap_service_id);
01220     if (!this) {
01221         return -1;
01222     }
01223     return this->interface_id;
01224 }
01225 
01226 #ifdef THREAD_THCI_SUPPORT
01227 static uint8_t Joiner_iid[8];
01228 #endif
01229 
01230 static int thread_management_server_entrust_resp_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
01231 {
01232     thread_management_server_t *this = thread_management_find_by_service(service_id);
01233     (void)source_address;
01234     (void)source_port;
01235 
01236     if (response_ptr) {
01237         thci_trace("Device - Joiner Router|Direction - recv|IID - %s|Type - JOIN_ent.resp|Length - %d|Payload - %s", trace_array(Joiner_iid, 8), response_ptr->payload_len, trace_array(response_ptr->payload_ptr, response_ptr->payload_len));
01238     } else {
01239         thci_trace("Device - Joiner Router|Direction - recv|IID - %s|Type - JOIN_ent.resp|Payload - NULL", Joiner_iid);
01240     }
01241     tr_debug("Joiner entrust response received");
01242     if (!this) {
01243         tr_warn("commissioner service missing!");
01244         return -1;
01245     }
01246 
01247     thread_commissioning_if_pairwise_key_del(this->interface_id, &source_address[8]);
01248 
01249     return 0;
01250 }
01251 static int thread_management_server_entrust_send(thread_management_server_t *this, uint8_t destination_address[16], uint8_t one_time_key[16])
01252 {
01253     uint8_t *response_ptr;
01254     uint16_t response_len;
01255     uint8_t *ptr;
01256     link_configuration_s *link_configuration_ptr;
01257     //int ret;
01258     if (!this || !destination_address || !one_time_key) {
01259         tr_err("entrust send fail");
01260         return -1;
01261     }
01262 
01263     tr_debug("Joiner_entrust_send Pairwise key %s address %s", trace_array(one_time_key, 16), trace_ipv6(destination_address));
01264 
01265     link_configuration_ptr = thread_management_configuration_get(this->interface_id);
01266     if (!link_configuration_ptr) {
01267         tr_err("Entrust sending failed no configuration");
01268         return -2;
01269     }
01270     int ret;
01271     uint8_t options = COAP_REQUEST_OPTIONS_NONE;
01272     ret = thread_commissioning_if_pairwise_key_add(this->interface_id, 10000, &destination_address[8], one_time_key);
01273 
01274     if (ret) {
01275         tr_err("Pairwise key set failed");
01276         return -3;
01277     }
01278     response_len = 6 + thread_joiner_application_active_config_length(this->interface_id, entrust_dataset_tlvs, entrust_dataset_tlvs_size(), NULL, 0);
01279 
01280     ptr = response_ptr = ns_dyn_mem_alloc(response_len);
01281     if(!response_ptr) {
01282         tr_warn("Out of mem");
01283         return -2;
01284     }
01285     ptr = thread_joiner_application_active_config_write(this->interface_id, ptr, entrust_dataset_tlvs, entrust_dataset_tlvs_size(), NULL, 0);
01286     ptr = thread_meshcop_tlv_data_write_uint32(ptr,MESHCOP_TLV_NETWORK_KEY_SEQUENCE, link_configuration_ptr->key_sequence);
01287 
01288     thci_trace("joinerrouterJoinerAccepted");
01289     /*We must null out the master secret*/
01290 #ifdef THREAD_THCI_SUPPORT
01291     uint8_t *master_secret_ptr;
01292     uint8_t *pskc_ptr;
01293     if (thread_meshcop_tlv_find(response_ptr, ptr - response_ptr, MESHCOP_TLV_NETWORK_MASTER_KEY, &master_secret_ptr) >= 16) {
01294         memset(master_secret_ptr,0,16);
01295     }
01296     if (thread_meshcop_tlv_find(response_ptr, ptr - response_ptr, MESHCOP_TLV_PSKC, &pskc_ptr) >= 16) {
01297         memset(pskc_ptr,0,16);
01298     }
01299 
01300     memcpy(Joiner_iid, &destination_address[8], 8);
01301     thci_trace("Device - Joiner Router|Direction - sent|IID - %s|Type - JOIN_ent.req|Length - %d|Payload - %s", trace_array(Joiner_iid, 8),(int) (ptr - response_ptr), trace_array(response_ptr, ptr - response_ptr));
01302     if (master_secret_ptr) {
01303         memcpy(master_secret_ptr,link_configuration_ptr->master_key,16);
01304     }
01305     if (pskc_ptr) {
01306         memcpy(pskc_ptr,link_configuration_ptr->PSKc,16);
01307     }
01308 #endif
01309     coap_service_request_send(this->coap_service_id, options, destination_address, THREAD_MANAGEMENT_PORT,
01310                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_JOINER_ENTRUST, COAP_CT_OCTET_STREAM, response_ptr, ptr - response_ptr, thread_management_server_entrust_resp_cb);
01311     ns_dyn_mem_free(response_ptr);
01312     return 0;
01313 }
01314 void joiner_router_recv_commission_msg(void *cb_res)
01315 {
01316     socket_callback_t *sckt_data = 0;
01317     ns_address_t source_address;
01318     uint8_t rloc16[16];
01319     uint8_t relay_destination_address[16];
01320     uint8_t *data_ptr = NULL;
01321     uint16_t data_len = 0;
01322     uint8_t *ptr;
01323     uint8_t *payload_ptr;
01324     uint16_t payload_len;
01325     char *destination_uri_ptr = THREAD_URI_RELAY_RECEIVE;
01326     sckt_data = cb_res;
01327     int ret MAYBE_UNUSED = -1;
01328 
01329     thread_management_server_t *this = thread_management_find_by_sckt_id(sckt_data->socket_id);
01330 
01331     if (!this) {
01332         return;
01333     }
01334 
01335     if (0 !=  thread_management_get_ml16_address(this->interface_id, rloc16)) {
01336         return;
01337     }
01338     // Specification issue needs hack to make one concurrent relay working
01339     if (0 != (ret = thread_commissioning_if_border_router_locator_get(this->interface_id, relay_destination_address))) {
01340         tr_err("invalid commissioner address ret %d", ret);
01341         return;
01342     }
01343 
01344     if (sckt_data->event_type == SOCKET_DATA && sckt_data->d_len > 0) {
01345         data_ptr = ns_dyn_mem_alloc(sckt_data->d_len);
01346         if (!data_ptr) {
01347             tr_err("Out of memory");
01348             return;
01349         }
01350         data_len = socket_read(sckt_data->socket_id, &source_address, data_ptr, sckt_data->d_len);
01351     }
01352     if (!data_ptr || data_len < 1) {
01353         tr_err("No data received");
01354         return;
01355     }
01356 
01357     payload_len = 4 + data_len + 4 + 8 + 4 + 2 + 4 + 2; //Joiner DTLS Encapsulation TLV  Joiner UDP Port TLV Joiner IID TLV Joiner Router Locator TLV
01358     payload_ptr = ns_dyn_mem_alloc(payload_len);
01359 
01360     if (!payload_ptr) {
01361         tr_err("Out of memory");
01362         ns_dyn_mem_free(data_ptr);
01363         return;
01364     }
01365     tr_debug("Relay TX recvfrom addr: %s, port:%d len:%d", trace_ipv6(source_address.address), source_address.identifier, data_len);
01366     thci_trace("joinerrouterJoinerDataRelayedInbound");
01367     ptr = payload_ptr;
01368     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_ENCAPSULATION, data_len, data_ptr);
01369     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_IID, 8, &source_address.address[8]);
01370     ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_JOINER_UDP_PORT, source_address.identifier);
01371     ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_JOINER_ROUTER_LOCATOR, 2, &rloc16[14]);
01372 
01373     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, relay_destination_address, THREAD_MANAGEMENT_PORT,
01374                               COAP_MSG_TYPE_NON_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, destination_uri_ptr, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr, NULL);
01375     ns_dyn_mem_free(payload_ptr);
01376     ns_dyn_mem_free(data_ptr);
01377 }
01378 static int thread_management_server_relay_tx_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
01379 {
01380     thread_management_server_t *this = thread_management_find_by_service(service_id);
01381     ns_address_t destination_address = { .address = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
01382     uint8_t *kek_ptr;
01383     uint8_t *udp_data_ptr;
01384     uint16_t udp_data_len;
01385     uint8_t *iid_ptr;
01386     uint16_t port;
01387     (void)source_address;
01388     (void)source_port;
01389 
01390     if (!this) {
01391         return -1;
01392     }
01393 
01394     // unwrap message and send to joiner socket.
01395     if (8 > thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_IID, &iid_ptr) ||
01396             2 > thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_UDP_PORT, &port) ||
01397             0 == (udp_data_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_ENCAPSULATION, &udp_data_ptr))
01398        ) {
01399         tr_err("Relay TX invalid message");
01400         return -1;
01401     }
01402     memcpy(&destination_address.address[8], iid_ptr, 8);
01403     destination_address.identifier = port;
01404     destination_address.type = ADDRESS_IPV6;
01405     int8_t err = socket_sendto(this->listen_socket_joiner, &destination_address, udp_data_ptr, udp_data_len);
01406     if (err < 0) {
01407         tr_err("Relay TX sendto failed %d", err);
01408     }
01409 
01410     //if KEK present set pairwise key to joiner and send entrust method
01411     if (0 < thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_ROUTER_KEK, &kek_ptr)) {
01412         // KEK present in relay set pairwise key and send entrust
01413         tr_debug("Kek received");
01414         thread_management_server_entrust_send(this, destination_address.address, kek_ptr);
01415     }
01416     tr_debug("Relay TX sendto addr:%s port:%d, length:%d", trace_ipv6(destination_address.address), port, udp_data_len);
01417     thci_trace("joinerrouterJoinerDataRelayedOutbound");
01418 
01419     return -1; // OK no response sent
01420 }
01421 
01422 int thread_management_server_joiner_router_init(int8_t interface_id)
01423 {
01424     thread_management_server_t *this = thread_management_server_find(interface_id);
01425     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
01426     int8_t securityLinkLayer = 0;
01427     bool enable = false;
01428 
01429     if (!this || !cur) {
01430         return -1;
01431     }
01432 
01433     if (cur->thread_info->registered_commissioner.commissioner_valid && cur->thread_info->registered_commissioner.steering_data_len > 0) {
01434         // Thread 1.1 commissioner is present
01435         enable = true;
01436     }
01437     if(this->joiner_router_enabled == enable &&
01438        this->relay_port_joiner == thread_joiner_port) {
01439         // Joiner router is in correct state
01440         return 0;
01441     }
01442     if(this->joiner_router_enabled) {
01443         // Need to disable Joiner router either because port changed or moving to disabled
01444         thread_management_server_joiner_router_deinit(interface_id);
01445     }
01446     if (!enable) {
01447         // Joiner router should be disabled
01448         tr_info("Joiner router Disable joining");
01449         return 0;
01450     }
01451 
01452     tr_info("Joiner router Enable joining");
01453 
01454     if (cur->thread_info->registered_commissioner.commissioner_valid && cur->thread_info->registered_commissioner.steering_data_len > 0) {
01455         // Thread 1.1 commissioner is present
01456         this->relay_port_joiner = thread_joiner_port;
01457 
01458         this->listen_socket_joiner = socket_open(SOCKET_UDP, this->relay_port_joiner, joiner_router_recv_commission_msg);
01459         if (this->listen_socket_joiner < 0) {
01460             // Try other ports
01461             while((this->listen_socket_joiner < 0) && (this->relay_port_joiner < thread_joiner_port + 10)) {
01462                 // We try 10 ports after default port
01463                 this->relay_port_joiner++;
01464                 this->listen_socket_joiner = socket_open(SOCKET_UDP, this->relay_port_joiner, joiner_router_recv_commission_msg);
01465             }
01466         }
01467         if (this->listen_socket_joiner < 0) {
01468             this->joiner_router_enabled = false;
01469             this->relay_port_joiner = 0;
01470             tr_error("Joiner router init failed");
01471             return -2;
01472         }
01473         socket_setsockopt(this->listen_socket_joiner, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
01474         tr_debug("init joiner router port:%d", this->relay_port_joiner);
01475     }
01476 
01477     coap_service_register_uri(this->coap_service_id, THREAD_URI_RELAY_TRANSMIT, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_management_server_relay_tx_cb);
01478     this->joiner_router_enabled = true;
01479     return 0;
01480 }
01481 
01482 void thread_management_server_joiner_router_deinit(int8_t interface_id)
01483 {
01484     thread_management_server_t *this = thread_management_server_find(interface_id);
01485 
01486     if (!this) {
01487         return;
01488     }
01489 
01490     tr_debug("deinit joiner router");
01491     coap_service_unregister_uri(this->coap_service_id, THREAD_URI_RELAY_TRANSMIT);
01492     socket_close(this->listen_socket_joiner);
01493     this->listen_socket_joiner = -1;
01494     this->relay_port_joiner = 0;
01495     this->joiner_router_enabled = false;
01496     return;
01497 }
01498 
01499 int thread_management_server_commisoner_data_get(int8_t interface_id, thread_management_server_data_t *server_data)
01500 {
01501     thread_management_server_t *this = thread_management_server_find(interface_id);
01502 
01503     if (!this) {
01504         return -1;
01505     }
01506 
01507     server_data->joiner_router_enabled = this->joiner_router_enabled;
01508     server_data->joiner_router_port = this->relay_port_joiner;
01509     server_data->commissioner_port = this->external_commissioner_port;
01510     return 0;
01511 }
01512 
01513 bool thread_management_server_source_address_check(int8_t interface_id, uint8_t source_address[16])
01514 {
01515     link_configuration_s *linkConfiguration;
01516     linkConfiguration = thread_joiner_application_get_config(interface_id);
01517 
01518     if (!linkConfiguration) {
01519         tr_error("No link configuration.");
01520         return false;
01521     }
01522 
01523     if (memcmp(source_address, linkConfiguration->mesh_local_ula_prefix, 8) == 0 &&
01524         memcmp(source_address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0 ) {
01525         // Source address is RLOC or ALOC
01526     } else if (memcmp(source_address, linkConfiguration->mesh_local_ula_prefix, 8) == 0) {
01527         // Source address is ML64 TODO this should check that destination address is ALOC or RLOC CoaP Service does not support
01528     } else if (memcmp(ADDR_LINK_LOCAL_PREFIX, source_address, 8)) {
01529         // Source address is from Link local address
01530     } else {
01531         tr_error("Message out of thread network; ML prefix: %s, src addr: %s",
01532                 trace_ipv6_prefix(linkConfiguration->mesh_local_ula_prefix, 64),
01533                 trace_ipv6(source_address));
01534         return false;
01535     }
01536     // TODO: Add other (security) related checks here
01537 
01538     return true;
01539 }
01540 
01541 int thread_management_server_tmf_get_request_handler(int8_t interface_id, int8_t coap_service_id, struct sn_coap_hdr_ *request_ptr)
01542 {
01543     int ret_val = -1;
01544 
01545     if (strncmp(THREAD_URI_ACTIVE_GET, (const char *)request_ptr->uri_path_ptr, request_ptr->uri_path_len) == 0) {
01546         ret_val = thread_management_server_active_get_respond(interface_id, coap_service_id, request_ptr);
01547     } else if (strncmp(THREAD_URI_PENDING_GET,(const char *)request_ptr->uri_path_ptr,request_ptr->uri_path_len) == 0) {
01548         ret_val = thread_management_server_pending_get_respond(interface_id, coap_service_id, request_ptr);
01549     } else if (strncmp(THREAD_URI_MANAGEMENT_GET,(const char *)request_ptr->uri_path_ptr,request_ptr->uri_path_len) == 0) {
01550         ret_val = thread_management_server_management_get_respond(interface_id, coap_service_id, request_ptr);
01551     } else {
01552         // unrecognized message
01553         tr_warn("Unrecognized tmf msg");
01554     }
01555 
01556     return ret_val;
01557 }
01558 
01559 #else // HAVE_THREAD_ROUTER
01560 
01561 int thread_management_server_init(int8_t interface_id)
01562 {
01563     (void) interface_id;
01564     return 0;
01565 }
01566 
01567 void thread_management_server_delete(int8_t interface_id)
01568 {
01569     (void) interface_id;
01570 }
01571 
01572 int thread_management_server_joiner_router_init(int8_t interface_id)
01573 {
01574     (void)interface_id;
01575     return 0;
01576 }
01577 
01578 void thread_management_server_joiner_router_deinit(int8_t interface_id)
01579 {
01580     (void) interface_id;
01581 }
01582 
01583 int thread_management_server_commisoner_data_get(int8_t interface_id, thread_management_server_data_t *server_data)
01584 {
01585     (void) interface_id;
01586     (void) server_data;
01587     return -1;
01588 }
01589 
01590 bool thread_management_server_source_address_check(int8_t interface_id, uint8_t source_address[16])
01591 {
01592     (void)interface_id;
01593     (void)source_address;
01594     return false;
01595 }
01596 
01597 int thread_management_server_tmf_get_request_handler(int8_t interface_id, int8_t coap_service_id, struct sn_coap_hdr_ *request_ptr)
01598 {
01599     (void)interface_id;
01600     (void)coap_service_id;
01601     (void)request_ptr;
01602     return -1;
01603 }
01604 #endif //HAVE_THREAD_ROUTER