takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_diagnostic.c Source File

thread_diagnostic.c

00001 /*
00002  * Copyright (c) 2016-2018, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: BSD-3-Clause
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holder nor the
00014  *    names of its contributors may be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 #include "nsconfig.h"
00030 #ifdef HAVE_THREAD
00031 #include <string.h>
00032 #include <ns_types.h>
00033 #include <ns_list.h>
00034 #include <ns_trace.h>
00035 #include "nsdynmemLIB.h"
00036 #include "net_interface.h"
00037 #include "thread_management_if.h"
00038 #include "thread_common.h"
00039 #include "thread_joiner_application.h"
00040 #include "thread_leader_service.h"
00041 #include "thread_router_bootstrap.h"
00042 #include "6LoWPAN/Thread/thread_neighbor_class.h"
00043 #include "MLE/mle.h"
00044 #include "6LoWPAN/Thread/thread_router_bootstrap.h"
00045 #include "thread_config.h"
00046 #include "thread_network_data_storage.h"
00047 #include "NWK_INTERFACE/Include/protocol.h"
00048 #include "thread_diagcop_lib.h"
00049 #include "common_functions.h"
00050 #include "6LoWPAN/MAC/mac_helper.h"
00051 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
00052 #include "mac_api.h"
00053 
00054 
00055 #define TRACE_GROUP "TdiaC"
00056 
00057 
00058 #include "coap_service_api.h"
00059 
00060 
00061 typedef struct thread_diagnostic_command {
00062     int8_t interface_id;
00063     int8_t coap_service_id;
00064     ns_list_link_t link;
00065 } thread_diagnostic_command_t;
00066 
00067 static NS_LIST_DEFINE(instance_list, thread_diagnostic_command_t, link);
00068 
00069 static thread_diagnostic_command_t *thread_diagnostic_command_find(int8_t interface_id)
00070 {
00071     thread_diagnostic_command_t *this = NULL;
00072     ns_list_foreach(thread_diagnostic_command_t, cur_ptr, &instance_list) {
00073         if (cur_ptr->interface_id == interface_id) {
00074             this = cur_ptr;
00075             break;
00076         }
00077     }
00078     return this;
00079 }
00080 
00081 static thread_diagnostic_command_t *thread_diagnostic_find_by_service(int8_t service_id)
00082 {
00083     thread_diagnostic_command_t *this = NULL;
00084     ns_list_foreach(thread_diagnostic_command_t, cur_ptr, &instance_list) {
00085         if (cur_ptr->coap_service_id == service_id) {
00086             this = cur_ptr;
00087             break;
00088         }
00089     }
00090     return this;
00091 }
00092 
00093 static uint8_t *thread_diagnostic_child_table_tlv_build(uint8_t *data_ptr, protocol_interface_info_entry_t *cur)
00094 {
00095     uint8_t child_count = 0;
00096     uint8_t calculated_timeout;
00097 
00098     mac_neighbor_table_list_t *mac_table_list = &mac_neighbor_info(cur)->neighbour_list;
00099 
00100     child_count = thread_router_bootstrap_child_count_get(cur);
00101 
00102     *data_ptr++ = DIAGCOP_TLV_CHILD_TABLE;  // Type
00103     *data_ptr++ = (3 * child_count);        // Length
00104 
00105     ns_list_foreach(mac_neighbor_table_entry_t, cur_entry, mac_table_list) {
00106         if (thread_router_addr_from_addr(cur_entry->mac16) == mac_helper_mac16_address_get(cur)){
00107             /* |0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3| */
00108             /* |Timeout  |Rsv|  Child ID       |      Mode     | */
00109             calculated_timeout = thread_log2_aprx(cur_entry->link_lifetime - 1) + 4;
00110             uint8_t mode = 0;
00111             mode |= mle_mode_write_from_mac_entry(cur_entry);
00112             mode |= thread_neighbor_class_mode_write_from_entry(&cur->thread_info->neighbor_class, cur_entry->index);
00113             tr_debug("Write child table TLV entry: %d - %d - %d", calculated_timeout, cur_entry->mac16, mode);
00114             *data_ptr = 0x00; //reserved bytes to zero
00115             *data_ptr = calculated_timeout << 3;
00116 
00117             if(cur_entry->mac16 & 0x0100){
00118                *data_ptr = *data_ptr | 0x01;
00119             }
00120             data_ptr++;
00121             *data_ptr++ = (uint8_t)(cur_entry->mac16 & 0x00ff);
00122             *data_ptr++ = mode;
00123         }
00124     }
00125 
00126     return data_ptr;
00127 }
00128 
00129 uint8_t thread_diag_mode_get_by_interface_ptr(protocol_interface_info_entry_t *cur)
00130 {
00131     uint8_t mle_mode = 0;
00132     if (!thread_info(cur)) {
00133         return 0;
00134     }
00135     if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
00136         mle_mode |= MLE_RX_ON_IDLE;
00137     }
00138 
00139     if (thread_info(cur)->requestFullNetworkData) {
00140         mle_mode |= (MLE_THREAD_REQ_FULL_DATA_SET);
00141     }
00142 
00143     /* We always send secured data requests */
00144     mle_mode |= MLE_THREAD_SECURED_DATA_REQUEST;
00145 
00146     switch (thread_info(cur)->thread_device_mode) {
00147         case THREAD_DEVICE_MODE_ROUTER:
00148         case THREAD_DEVICE_MODE_FULL_END_DEVICE:
00149             mle_mode |= MLE_FFD_DEV;
00150             break;
00151 
00152         default:
00153             break;
00154     }
00155 
00156 
00157     return mle_mode;
00158 }
00159 
00160 static int thread_diagnostic_configuration_calc(protocol_interface_info_entry_t *cur, uint8_t *tlv_list, uint16_t list_len)
00161 {
00162     int payload_len = 0;
00163     uint16_t address_count = 0;
00164 
00165     if(!tlv_list || list_len < 1) {
00166         return 0;
00167     }
00168 
00169     while(list_len --){
00170         switch (*tlv_list){
00171         case DIAGCOP_TLV_EXTENDED_MAC_ADDRESS:
00172             payload_len += 2 + 8;
00173             break;
00174 
00175         case DIAGCOP_TLV_ADDRESS16:
00176             payload_len += 2 + 2;
00177             break;
00178 
00179         case DIAGCOP_TLV_MODE:
00180             payload_len += 2 + 1;
00181             break;
00182 
00183         case DIAGCOP_TLV_TIMEOUT:
00184             if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE ||
00185                 cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE ) {
00186                 payload_len += 2 + 4;
00187             }
00188             break;
00189 
00190         case DIAGCOP_TLV_CONNECTIVITY:
00191             payload_len += 2 + 10;
00192             break;
00193 
00194         case DIAGCOP_TLV_ROUTE64:
00195             payload_len += thread_route_option_size(cur);
00196             break;
00197 
00198         case DIAGCOP_TLV_LEADER_DATA:
00199             payload_len += 2 + 8; // TLV header + uint16 pan id
00200             break;
00201 
00202         case DIAGCOP_TLV_NETWORK_DATA:
00203             payload_len += 2; // TLV header
00204             payload_len += thread_network_data_tlv_size(cur,1);
00205             break;
00206 
00207         case DIAGCOP_TLV_IPV6_ADDRESS_LIST:
00208             arm_net_interface_address_list_size(cur->id, &address_count);
00209             payload_len += 2 + (address_count * 16);
00210             break;
00211 
00212         case DIAGCOP_TLV_MAC_COUNTERS:
00213             payload_len += 2+36;
00214             break;
00215         case DIAGCOP_TLV_BATTERY_LEVEL:
00216             payload_len += 2 + 1;
00217             break;
00218 
00219         case DIAGCOP_TLV_SUPPLY_VOLTAGE:
00220             payload_len += 2 + 2;
00221             break;
00222 
00223         case DIAGCOP_TLV_CHILD_TABLE:
00224             /* Value length = Type + Length + 3 * child count */
00225             payload_len += 2 + (3 * thread_router_bootstrap_child_count_get(cur));
00226             break;
00227 
00228         case DIAGCOP_TLV_CHANNEL_PAGES:
00229             payload_len += 2+1;
00230             break;
00231 
00232         default:
00233             // todo: Other TLV's not supported atm
00234             break;
00235         }
00236 
00237         tlv_list++;
00238     }
00239     return payload_len;
00240 }
00241 
00242 static uint8_t *thread_diagnostic_get_build(protocol_interface_info_entry_t *cur, uint8_t *response_ptr, uint8_t *tlv_list, uint16_t list_len)
00243 {
00244 
00245     if(!tlv_list || list_len < 1) {
00246         // Request all
00247         return response_ptr;
00248     }
00249     if (!thread_info(cur)) {
00250         return response_ptr;
00251     }
00252     // the following are some tlvs that need to be implemented correctly, this is only dummy data for the moment
00253     uint8_t dummy_data[36] = {0};
00254     uint8_t *ptr;
00255     int written_address_count = 0;
00256     uint16_t ipv6_address_count = 0;
00257     uint8_t extended_address[8] = {0};
00258 
00259     arm_net_interface_address_list_size(cur->id, &ipv6_address_count);
00260 
00261     // 16 bytes for each ipv6 address
00262     uint8_t ipv6_address_list[ipv6_address_count * 16];
00263 
00264     tr_debug("tlv list length %d", list_len);
00265     while(list_len --){
00266         switch (*tlv_list){
00267 
00268         case DIAGCOP_TLV_EXTENDED_MAC_ADDRESS:
00269             if (cur->mac_api) {
00270                 //Read dynamicaly generated current extented address from MAC.
00271                 cur->mac_api->mac64_get(cur->mac_api,MAC_EXTENDED_DYNAMIC, extended_address);
00272             }
00273             response_ptr = thread_diagcop_tlv_data_write(response_ptr, DIAGCOP_TLV_EXTENDED_MAC_ADDRESS, 8, extended_address);
00274             break;
00275 
00276         case DIAGCOP_TLV_ADDRESS16:
00277             response_ptr = thread_diagcop_tlv_data_write_uint16(response_ptr, DIAGCOP_TLV_ADDRESS16, mac_helper_mac16_address_get(cur));
00278             break;
00279 
00280         case DIAGCOP_TLV_MODE:
00281             response_ptr = thread_diagcop_tlv_data_write_uint8(response_ptr, DIAGCOP_TLV_MODE, thread_diag_mode_get_by_interface_ptr(cur));
00282             break;
00283 
00284         case DIAGCOP_TLV_TIMEOUT:
00285             //must be sleeping poll rate
00286             if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE ||
00287                 cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE ) {
00288                 response_ptr = thread_diagcop_tlv_data_write_uint32(response_ptr, DIAGCOP_TLV_TIMEOUT, cur->thread_info->host_link_timeout);
00289             }
00290             break;
00291 
00292         case DIAGCOP_TLV_CONNECTIVITY:
00293             ptr = response_ptr;
00294             response_ptr = thread_connectivity_tlv_write(response_ptr, cur, 0x0f);
00295             if (ptr != response_ptr) {
00296                 ptr[0]=DIAGCOP_TLV_CONNECTIVITY;
00297             }
00298             break;
00299 
00300         case DIAGCOP_TLV_ROUTE64:
00301             ptr = response_ptr;
00302             response_ptr = thread_route_option_write(cur,response_ptr);
00303             if (ptr != response_ptr) {
00304                 ptr[0]=DIAGCOP_TLV_ROUTE64;
00305             }
00306             break;
00307 
00308         case DIAGCOP_TLV_LEADER_DATA:
00309             ptr = response_ptr;
00310             response_ptr = thread_leader_data_tlv_write(response_ptr,cur);
00311             if (ptr != response_ptr) {
00312                 ptr[0]=DIAGCOP_TLV_LEADER_DATA;
00313             }
00314             break;
00315 
00316         case DIAGCOP_TLV_NETWORK_DATA:
00317             ptr = response_ptr;
00318             response_ptr = thread_network_data_tlv_write(cur, response_ptr, true);
00319             if (ptr != response_ptr) {
00320                 ptr[0]=DIAGCOP_TLV_NETWORK_DATA;
00321             }
00322             break;
00323 
00324         case DIAGCOP_TLV_IPV6_ADDRESS_LIST:
00325             arm_net_address_list_get(cur->id, ipv6_address_count * 16,ipv6_address_list,&written_address_count);
00326             response_ptr = thread_diagcop_tlv_data_write(response_ptr, DIAGCOP_TLV_IPV6_ADDRESS_LIST, ipv6_address_count*16, ipv6_address_list);
00327             break;
00328 
00329         case DIAGCOP_TLV_MAC_COUNTERS:
00330             /* The following elements from [RFC 2863] are included in this order:
00331              * ifInUnknownProtos (4), ifInErrors (4), ifOutErrors (4), ifInUcastPkts (4),
00332              * ifInBroadcastPkts (4), ifInDiscards (4), ifOutUcastPkts (4), ifOutBroadcastPkts (4), ifOutDiscards (4) */
00333             response_ptr = thread_diagcop_tlv_data_write(response_ptr, DIAGCOP_TLV_MAC_COUNTERS, 36, dummy_data);
00334             break;
00335 
00336         case DIAGCOP_TLV_BATTERY_LEVEL:
00337             response_ptr = thread_diagcop_tlv_data_write_uint8(response_ptr, DIAGCOP_TLV_BATTERY_LEVEL, 0);
00338             break;
00339 
00340         case DIAGCOP_TLV_SUPPLY_VOLTAGE:
00341             response_ptr = thread_diagcop_tlv_data_write_uint16(response_ptr, DIAGCOP_TLV_SUPPLY_VOLTAGE, 0);
00342             break;
00343 
00344         case DIAGCOP_TLV_CHILD_TABLE:
00345             if (thread_router_bootstrap_child_count_get(cur)) {
00346                 response_ptr = thread_diagnostic_child_table_tlv_build(response_ptr, cur);
00347             }
00348             break;
00349 
00350         case DIAGCOP_TLV_CHANNEL_PAGES:
00351             // Only supporting channel page 0
00352             response_ptr = thread_diagcop_tlv_data_write_uint8(response_ptr, DIAGCOP_TLV_CHANNEL_PAGES, 0);
00353             break;
00354 
00355         default:
00356 
00357             break;
00358         }
00359 
00360         tlv_list++;
00361     }
00362     return response_ptr;
00363 }
00364 /**
00365  * Thread diagnostics request d/dg
00366  */
00367 static int thread_diagnostic_command_request_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00368 {
00369     (void) source_address;
00370     (void) source_port;
00371 
00372     thread_diagnostic_command_t *this = thread_diagnostic_find_by_service(service_id);
00373     protocol_interface_info_entry_t *cur;
00374     uint8_t *ptr = NULL;
00375      uint8_t *request_tlv_ptr = NULL;
00376     uint16_t request_tlv_len;
00377     int response_len;
00378     uint8_t *response_ptr = NULL;
00379     sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00380 
00381     if (!this) {//check if there is request
00382         return -1;
00383     }
00384     cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00385     if (!cur) {
00386         return -1;
00387     }
00388 
00389     tr_debug("Thread diagnostic command get request");
00390 
00391     request_tlv_len = thread_diagcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, DIAGCOP_TLV_TYPE_LIST, &request_tlv_ptr);
00392 
00393     // the following function calculates the total memory that is needed to be allocated for response.
00394     // If the request_tlv_len is 0 then the memory allocated is for all the diagnostic command tlvs
00395     response_len = thread_diagnostic_configuration_calc(cur,request_tlv_ptr, request_tlv_len);
00396     if(response_len < 1){
00397         if (request_tlv_len > 0) {
00398             // TLV was ommitted but ok request. respond with ok status
00399             goto send_response;
00400         }
00401         goto failure;
00402     }
00403     ptr = response_ptr = ns_dyn_mem_alloc(response_len);
00404     if (!response_ptr) {
00405         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00406         goto failure;
00407     }
00408 
00409     ptr = thread_diagnostic_get_build(cur, ptr, request_tlv_ptr,
00410             request_tlv_len);
00411 
00412 send_response:
00413     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE,
00414             request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM,
00415             response_ptr,ptr - response_ptr );
00416     ns_dyn_mem_free(response_ptr);
00417     return 0;
00418 
00419 failure:
00420     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_NONE, NULL, 0);
00421     return 0;
00422 }
00423 /**
00424  * Thread diagnostics reset d/dr
00425  */
00426 static int thread_diagnostic_command_reset_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00427 {
00428     (void) source_address;
00429     (void) source_port;
00430 
00431     thread_diagnostic_command_t *this = thread_diagnostic_find_by_service(service_id);
00432     if (!this) {//check if there is request
00433         return -1;
00434     }
00435 
00436     tr_debug("Thread diagnostic command reset request");
00437 
00438     coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE,
00439             request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_TEXT_PLAIN, NULL, 0);
00440     return 0;
00441 }
00442 
00443 /**
00444  * Thread diagnostics query d/dq
00445  */
00446 static int thread_diagnostic_command_query_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr)
00447 {
00448     uint8_t address_copy[16];
00449     protocol_interface_info_entry_t *cur;
00450     uint8_t *response_ptr = NULL;
00451     uint8_t *ptr = NULL;
00452     uint8_t *request_tlv_ptr;
00453     uint16_t response_len;
00454     uint16_t request_tlv_len;
00455     sn_coap_msg_code_e return_code = COAP_MSG_CODE_EMPTY;
00456     int8_t response = -1;
00457 
00458     /* Source_address is freed when calling coap_service_response_send().
00459      * Anyhow, We need to use it when sending request, so let's make a copy! */
00460     memcpy(address_copy, source_address, 16);
00461 
00462     thread_diagnostic_command_t *this = thread_diagnostic_find_by_service(service_id);
00463     if (!this) {//check if there is request
00464         return -1;
00465     }
00466     cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00467     if (!cur) {
00468         return -1;
00469     }
00470 
00471     tr_debug("Thread diagnostic command query request from %s:%d", trace_array(source_address, 16), source_port);
00472     // build response
00473     request_tlv_len = thread_diagcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, DIAGCOP_TLV_TYPE_LIST, &request_tlv_ptr);
00474 
00475     // the following function calculates the total memory that is needed to be allocated for response.
00476     // If the request_tlv_len is 0 then the memory allocated is for all the diagnostic command tlvs
00477     response_len = thread_diagnostic_configuration_calc(cur, request_tlv_ptr, request_tlv_len);
00478     if(response_len < 1){
00479         if (request_tlv_len > 0) {
00480             // TLV was ommitted but ok request. respond with ok status
00481             goto send_response;
00482         }
00483         return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00484         goto failure;
00485     }
00486     ptr = response_ptr = ns_dyn_mem_alloc(response_len);
00487     if (!response_ptr) {
00488         return_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00489         goto failure;
00490     }
00491 
00492     ptr = thread_diagnostic_get_build(cur, response_ptr, request_tlv_ptr, request_tlv_len);
00493 
00494     /* Send ACK to confirmable request */
00495     if(request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE){
00496         coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_NONE, NULL, 0);
00497         response = 0;
00498     }
00499 
00500     /* Send reply to d/da */
00501 send_response:
00502     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, address_copy, source_port, COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST,
00503             THREAD_URI_DIAGNOSTIC_ANSWER, COAP_CT_OCTET_STREAM, response_ptr, ptr - response_ptr, NULL);
00504 
00505     ns_dyn_mem_free(response_ptr);
00506 
00507     return response;
00508 
00509 failure:
00510     if(request_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE){
00511         coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_NONE, NULL, 0);
00512         response = 0;
00513     }
00514     return response;
00515 }
00516 
00517 /**
00518  * Public interface functions
00519  */
00520 int thread_diagnostic_init(int8_t interface_id)
00521 {
00522 
00523     thread_diagnostic_command_t *this = thread_diagnostic_command_find(interface_id);
00524     if (this) {
00525         return 0;
00526     }
00527 
00528     this = ns_dyn_mem_alloc(sizeof(thread_diagnostic_command_t));
00529     if (!this) {
00530         return -2;
00531     }
00532 
00533     this->interface_id = interface_id;
00534 
00535     this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL);
00536     if (this->coap_service_id < 0) {
00537         tr_error("Thread diagnostic init failed");
00538         ns_dyn_mem_free(this);
00539         return -3;
00540     }
00541     /**
00542      * Thread Management uri registration
00543      */
00544     coap_service_register_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_REQUEST, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_diagnostic_command_request_cb);
00545     coap_service_register_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_RESET, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_diagnostic_command_reset_cb);
00546     coap_service_register_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_QUERY, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_diagnostic_command_query_cb);
00547     ns_list_add_to_start(&instance_list, this);
00548 
00549     return 0;
00550 }
00551 
00552 int thread_diagnostic_delete(int8_t interface_id)
00553 {
00554     thread_diagnostic_command_t *this = thread_diagnostic_command_find(interface_id);
00555 
00556     if (!this) {
00557         return -1;
00558     }
00559 
00560     coap_service_delete(this->coap_service_id);
00561     ns_list_remove(&instance_list, this);
00562     ns_dyn_mem_free(this);
00563     return 0;
00564 }
00565 
00566 #endif