Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_diagnostic.c Source File

thread_diagnostic.c

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