Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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