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

thread_management_client.c

00001 /*
00002  * Copyright (c) 2014-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 
00030 
00031 #include "nsconfig.h"
00032 #ifdef HAVE_THREAD
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 "thread_tmfcop_lib.h"
00039 
00040 #include "coap_service_api.h"
00041 
00042 #include "thread_common.h"
00043 #include "thread_config.h"
00044 #include "thread_management_if.h"
00045 #include "6LoWPAN/Thread/thread_constants.h"
00046 #include "6LoWPAN/Thread/thread_tmfcop_lib.h"
00047 #include "6LoWPAN/Thread/thread_management_internal.h"
00048 #include "6LoWPAN/Thread/thread_management_server.h"
00049 #include "6LoWPAN/Thread/thread_joiner_application.h"
00050 #include "6LoWPAN/Thread/thread_network_data_lib.h"
00051 #include "6LoWPAN/Thread/thread_bootstrap.h"
00052 #include "6LoWPAN/Thread/thread_management_client.h"
00053 #include "NWK_INTERFACE/Include/protocol.h"
00054 
00055 #define TRACE_GROUP TRACE_GROUP_THREAD_MANAGEMENT_CLIENT
00056 
00057 typedef struct thread_management {
00058     thread_management_client_router_id_cb *router_id_cb_ptr;
00059     thread_management_client_router_id_cb *router_id_release_cb_ptr;
00060     thread_management_client_network_data_set_cb *network_data_set_cb_ptr;
00061     thread_management_client_network_data_set_cb *neighbor_discovery_cb_ptr;
00062     int8_t interface_id;
00063     int8_t coap_service_id; // COAP service ID from Management server
00064     ns_list_link_t link;
00065 } thread_management_t;
00066 
00067 static NS_LIST_DEFINE(instance_list, thread_management_t, link);
00068 
00069 static thread_management_t *thread_management_find(int8_t interface_id)
00070 {
00071     thread_management_t *this = NULL;
00072     ns_list_foreach(thread_management_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 static thread_management_t *thread_management_find_by_service(int8_t service_id)
00081 {
00082     thread_management_t *this = NULL;
00083     ns_list_foreach(thread_management_t, cur_ptr, &instance_list) {
00084         if (cur_ptr->coap_service_id == service_id) {
00085             this = cur_ptr;
00086             break;
00087         }
00088     }
00089     return this;
00090 }
00091 
00092 static int thread_management_client_get_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00093 {
00094     thread_management_t *this = thread_management_find_by_service(service_id);
00095     uint8_t *router_id_mask_ptr;
00096     uint16_t router_id;
00097     uint8_t *ptr;
00098     int8_t status = 0;
00099     (void)source_address;
00100     (void)source_port;
00101 
00102     tr_debug("Thread router id client cb");
00103     if (!this) {
00104         return -1;
00105     }
00106 
00107     if ((!response_ptr) || 9 > thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, TMFCOP_TLV_ROUTER_MASK, &router_id_mask_ptr) ||
00108             2 > thread_meshcop_tlv_data_get_uint16(response_ptr->payload_ptr, response_ptr->payload_len, TMFCOP_TLV_RLOC16, &router_id) ||
00109             1 > thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, TMFCOP_TLV_STATUS, &ptr) || *ptr != 0) {
00110         // Failure in message
00111         status = -1;
00112         router_id_mask_ptr = NULL;
00113         router_id = 0xfffe;
00114     }
00115 
00116     if (this->router_id_cb_ptr) {
00117         this->router_id_cb_ptr(this->interface_id, status, router_id, router_id_mask_ptr);
00118     }
00119 
00120     return 0;
00121 }
00122 
00123 static int thread_management_client_release_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00124 {
00125     thread_management_t *this = thread_management_find_by_service(service_id);
00126     (void) source_address;
00127     (void) source_port;
00128     (void) response_ptr;
00129     if (this && this->router_id_release_cb_ptr) {
00130         this->router_id_release_cb_ptr(this->interface_id, 0, 0xfffe, NULL);
00131     }
00132     return 0;
00133 }
00134 
00135 /**
00136  * Public Api functions
00137  */
00138 void thread_management_client_init(int8_t interface_id)
00139 {
00140     thread_management_t *this = thread_management_find(interface_id);
00141     if (this) {
00142         return;
00143     }
00144 
00145     this = ns_dyn_mem_alloc(sizeof(thread_management_t));
00146 
00147     if (this) {
00148         this->network_data_set_cb_ptr = NULL;
00149         this->router_id_release_cb_ptr = NULL;
00150         this->neighbor_discovery_cb_ptr = NULL;
00151         this->router_id_cb_ptr = NULL;
00152         this->interface_id = interface_id;
00153         //TODO: Check if to use ephemeral port here
00154 
00155         this->coap_service_id = thread_management_server_service_id_get(interface_id);
00156         if (this->coap_service_id < 0) {
00157             tr_error("Failed to init COAP service");
00158         }
00159         ns_list_add_to_start(&instance_list, this);
00160     }
00161     return;
00162 }
00163 
00164 void thread_management_client_delete(int8_t interface_id)
00165 {
00166     thread_management_t *this = thread_management_find(interface_id);
00167     if (!this) {
00168         return;
00169     }
00170 
00171     ns_list_remove(&instance_list, this);
00172     ns_dyn_mem_free(this);
00173     return;
00174 }
00175 
00176 int thread_management_client_router_id_get(int8_t interface_id, uint8_t mac[8], uint16_t router_id, thread_management_client_router_id_cb *id_cb, uint8_t status)
00177 {
00178     thread_management_t *this = thread_management_find(interface_id);
00179     uint8_t payload[30];//!< max length 4 + 2, 4 + 8,  4 + 8,
00180     uint8_t destination[16];
00181     uint8_t *ptr;
00182     protocol_interface_info_entry_t *cur;
00183 
00184     if (!this || !mac || !id_cb) {
00185         return -1;
00186     }
00187 
00188     if (0 != thread_management_get_leader_address(interface_id, destination)) {
00189         return -2;
00190     }
00191 
00192     cur = protocol_stack_interface_info_get_by_id(interface_id);
00193     if (!cur || !cur->thread_info) {
00194         return -3;
00195     }
00196 
00197     this->router_id_cb_ptr = id_cb;
00198     ptr = payload;
00199     if (router_id < 0xfffe) {
00200         ptr = thread_tmfcop_tlv_data_write_uint16(ptr, TMFCOP_TLV_RLOC16, router_id);
00201     }
00202     ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_MAC_ADDRESS, 8, mac);
00203 
00204     tr_debug("thread router id get id: %d, mac %s", router_id, trace_array(mac, 8));
00205 
00206     ptr = thread_tmfcop_tlv_data_write_uint8(ptr, TMFCOP_TLV_STATUS, status);
00207 
00208     return coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT,
00209                                      COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_ROUTER_ID_ASSIGNMENT, COAP_CT_OCTET_STREAM, payload, ptr - payload, thread_management_client_get_cb);
00210 }
00211 
00212 int thread_management_client_router_id_release(int8_t interface_id, uint8_t mac[8], uint16_t router_id, thread_management_client_router_id_cb *id_cb)
00213 {
00214     thread_management_t *this = thread_management_find(interface_id);
00215     uint8_t payload[30];//!< max length 4 + 2, 4 + 8,  4 + 8,
00216     uint8_t destination[16];
00217     uint8_t *ptr;
00218 
00219     if (!this || !mac || router_id >= 0xfffe) {
00220         return -1;
00221     }
00222 
00223     if (0 != thread_management_get_leader_address(interface_id, destination)) {
00224         return -2;
00225     }
00226 
00227     this->router_id_release_cb_ptr = id_cb;
00228     ptr = payload;
00229     ptr = thread_tmfcop_tlv_data_write_uint16(ptr, TMFCOP_TLV_RLOC16, router_id);
00230     ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_MAC_ADDRESS, 8, mac);
00231 
00232     tr_debug("thread router id release id: %d, mac %s", router_id, trace_array(mac, 8));
00233 
00234     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT,
00235                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_ROUTER_ID_RELEASE, COAP_CT_OCTET_STREAM, payload, ptr - payload, thread_management_client_release_cb);
00236     return 0;
00237 }
00238 
00239 static int thread_management_client_register_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00240 {
00241     thread_management_t *this = thread_management_find_by_service(service_id);
00242     (void) source_address;
00243     (void) source_port;
00244     if (!this) {
00245         return -1;
00246     }
00247 
00248     if (this->network_data_set_cb_ptr) {
00249         if (response_ptr) {
00250             // If we get response status is OK
00251             this->network_data_set_cb_ptr(this->interface_id, 0, response_ptr->payload_ptr, response_ptr->payload_len);
00252         } else {
00253             this->network_data_set_cb_ptr(this->interface_id, -1, NULL, 0);
00254         }
00255     }
00256 
00257     return 0;
00258 }
00259 
00260 int thread_management_client_network_data_register(int8_t interface_id, uint8_t *data_ptr, uint16_t data_len, thread_management_client_network_data_set_cb *set_cb)
00261 {
00262     thread_management_t *this = thread_management_find(interface_id);
00263     uint8_t destination[16];
00264 
00265     if (!this) {
00266         return -1;
00267     }
00268 
00269     if (thread_management_get_leader_address(interface_id, destination)) {
00270         return -2;
00271     }
00272 
00273     this->network_data_set_cb_ptr = set_cb;
00274     tr_debug("thread network data send to %s", trace_ipv6(destination));
00275 
00276     return coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT,
00277                                      COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, data_ptr, data_len, thread_management_client_register_cb);
00278 }
00279 
00280 int thread_management_client_network_data_unregister(int8_t interface_id, uint16_t rloc16)
00281 {
00282     thread_management_t *this = thread_management_find(interface_id);
00283     uint8_t payload[4];
00284     uint8_t *ptr;
00285     uint8_t destination[16];
00286 
00287     if (!this) {
00288         return -1;
00289     }
00290 
00291     if (thread_management_get_leader_address(interface_id, destination)) {
00292         return -2;
00293     }
00294     ptr = payload;
00295     ptr = thread_tmfcop_tlv_data_write_uint16(ptr, TMFCOP_TLV_RLOC16, rloc16);
00296 
00297     tr_debug("thread network data unregister");
00298 
00299     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT,
00300                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, payload, ptr - payload, thread_management_client_register_cb);
00301     return 0;
00302 }
00303 
00304 static int thread_management_client_neighbor_discovery_data_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00305 {
00306     thread_management_t *this = thread_management_find_by_service(service_id);
00307     uint8_t *nd_data_options_ptr = NULL;
00308     int8_t status = -1;
00309     uint16_t nd_data_options_len = 0;
00310     (void) source_address;
00311     (void) source_port;
00312     if (!this) {
00313         return -1;
00314     }
00315 
00316     if (response_ptr) {
00317         status = 0; // If we get response status is OK
00318         nd_data_options_len = thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, TMFCOP_TLV_ND_DATA, &nd_data_options_ptr);
00319     }
00320 
00321     if (this->neighbor_discovery_cb_ptr) {
00322         this->neighbor_discovery_cb_ptr(this->interface_id, status, nd_data_options_ptr, nd_data_options_len);
00323     }
00324 
00325     return 0;
00326 }
00327 
00328 int thread_management_client_get_interface_id_by_service_id(int8_t service_id)
00329 {
00330     thread_management_t *this = thread_management_find_by_service(service_id);
00331     if (!this) {
00332         return -1;
00333     }
00334     return this->interface_id;
00335 }
00336 
00337 int thread_management_client_neighbor_discovery_data_request(int8_t interface_id, const uint8_t destination[16],  const uint8_t *options, uint8_t options_len, thread_management_client_network_data_set_cb *set_cb)
00338 {
00339     thread_management_t *this = thread_management_find(interface_id);
00340     uint8_t payload[2 + options_len]; //type + length + num of options
00341     uint8_t *ptr = &payload[2];
00342     uint8_t payload_len;
00343 
00344     if (!this || !options || options_len == 0) {
00345         return -1;
00346     }
00347 
00348     this->neighbor_discovery_cb_ptr = set_cb;
00349     tr_debug("thread neighbor discovery data request");
00350 
00351     memcpy(ptr, options, options_len);
00352     thread_tmfcop_tlv_data_write_header(payload, TMFCOP_TLV_ND_OPTION, options_len);
00353     payload_len = 2 + options_len; //type + length + options
00354 
00355     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT,
00356                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NEIGHBOR_DISCOVERY_DATA_REQ, COAP_CT_OCTET_STREAM, payload, payload_len, thread_management_client_neighbor_discovery_data_cb);
00357     return 0;
00358 }
00359 
00360 static int thread_management_client_active_set_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00361 {
00362     thread_management_t *this = thread_management_find_by_service(service_id);
00363     (void)source_address;
00364     (void)source_port;
00365     uint8_t state;
00366 
00367     tr_debug("Receiving active set response from leader");
00368 
00369     if (!this) {
00370         return -1;
00371     }
00372 
00373     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00374 
00375     if (!cur || !cur->thread_info) {
00376         return -2;
00377     }
00378 
00379     if (!response_ptr || response_ptr->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || !response_ptr->payload_ptr) {
00380         tr_error("active set failed");
00381         goto getout;
00382     }
00383     if (1 > thread_meshcop_tlv_data_get_uint8(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &state) || state != 1) {
00384         tr_error("active set rejected");
00385         goto getout;
00386     }
00387     // TODO this is problematic we can not advertise before leader distributes the data
00388     // Current approach is to wait for leader
00389     // Spec says we could form own partition or just learn the older ones
00390     // We could then just clear timestamp from active set and learn new one.
00391     // thread_active_configuration_dataset_query_done(cur);
00392     return 0;
00393 
00394 getout:
00395 
00396     return 0;
00397 }
00398 
00399 int8_t thread_management_client_active_set(int8_t interface_id, uint8_t *dst_address)
00400 {
00401     thread_management_t *this = thread_management_find(interface_id);
00402     uint16_t response_len;
00403     uint8_t *response_ptr, *ptr;
00404     tr_debug("Sending active set to leader");
00405 
00406     response_len = thread_joiner_application_next_active_config_length(interface_id);
00407     if (!this || response_len < 1) {
00408         return -1;
00409     }
00410 
00411     response_ptr = ns_dyn_mem_alloc(response_len);
00412     if (!response_ptr) {
00413         tr_warn("Out of mem");
00414         return -2;
00415     }
00416     ptr = thread_joiner_application_next_active_config_write(interface_id, response_ptr);
00417 
00418     if (0 == coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, dst_address, THREAD_MANAGEMENT_PORT,
00419                                        COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_ACTIVE_SET, COAP_CT_OCTET_STREAM, response_ptr, (uint16_t)(ptr - response_ptr), thread_management_client_active_set_response_cb)) {
00420         tr_warn("request send failed");
00421     }
00422     ns_dyn_mem_free(response_ptr);
00423     return 0;
00424 }
00425 
00426 
00427 static int thread_management_client_pending_set_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00428 {
00429     thread_management_t *this = thread_management_find_by_service(service_id);
00430     (void)source_address;
00431     (void)source_port;
00432     uint8_t state;
00433 
00434     tr_debug("Receiving pending set response from leader");
00435 
00436     if (!this) {
00437         return -1;
00438     }
00439 
00440     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00441 
00442     if (!cur || !cur->thread_info) {
00443         return -2;
00444     }
00445 
00446     if (!response_ptr || response_ptr->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || !response_ptr->payload_ptr) {
00447         tr_error("pending set failed");
00448         goto getout;
00449     }
00450     if (1 > thread_meshcop_tlv_data_get_uint8(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &state) || state != 1) {
00451         tr_error("pending set rejected");
00452         goto getout;
00453     }
00454 
00455     return 0;
00456 
00457 getout:
00458     return 0;
00459 }
00460 
00461 int8_t thread_management_client_pending_set(int8_t interface_id, uint8_t *dst_address)
00462 {
00463     thread_management_t *this = thread_management_find(interface_id);
00464     uint16_t response_len;
00465     uint8_t *response_ptr, *ptr;
00466     tr_debug("Sending Pending set to leader");
00467 
00468     if (!this) {
00469         return -1;
00470     }
00471 
00472     response_len = thread_joiner_application_next_pending_config_length(interface_id);
00473 
00474     response_ptr = ns_dyn_mem_alloc(response_len);
00475     if (!response_ptr) {
00476         tr_warn("Out of mem");
00477         return -2;
00478     }
00479     ptr = thread_joiner_application_next_pending_config_build(interface_id, response_ptr);
00480 
00481     if (0 == coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, dst_address, THREAD_MANAGEMENT_PORT,
00482                                        COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_PENDING_SET, COAP_CT_OCTET_STREAM, response_ptr, (uint16_t)(ptr - response_ptr), thread_management_client_pending_set_response_cb)) {
00483         tr_warn("request send failed");
00484     }
00485     ns_dyn_mem_free(response_ptr);
00486     return 0;
00487 }
00488 
00489 static int thread_management_client_provision_request_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00490 {
00491     thread_management_t *this = thread_management_find_by_service(service_id);
00492     (void)source_address;
00493     (void)source_port;
00494     uint8_t state;
00495 
00496     tr_debug("Thread provisioning Received");
00497 
00498     if (!this) {
00499         return 0;
00500     }
00501 
00502     thread_joiner_application_provisioning_set(this->interface_id, PROVISIONING_STATUS_NOT_DONE);
00503 
00504     // CoAP request timed out
00505     if (!response_ptr) {
00506         return 0;
00507     }
00508 
00509     if (response_ptr->msg_code != COAP_MSG_CODE_RESPONSE_CHANGED) {
00510         tr_error("Provisioning failed");
00511         thread_joiner_application_provisioning_set(this->interface_id, PROVISIONING_STATUS_REJECTED);
00512         return 0;
00513     }
00514 
00515     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id);
00516 
00517     if (!cur || !cur->thread_info || 1 > thread_meshcop_tlv_data_get_uint8(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_STATE, &state)) {
00518         tr_error("provisioning response failed");
00519         return 0;
00520     }
00521     tr_debug("Thread provisioning status %d", state);
00522 
00523     if (state == 1) {
00524         thread_joiner_application_provisioning_set(this->interface_id, PROVISIONING_STATUS_DONE);
00525     } else {
00526         thread_joiner_application_provisioning_set(this->interface_id, PROVISIONING_STATUS_REJECTED);
00527     }
00528 
00529     return 0;
00530 }
00531 
00532 int thread_management_client_provision_request(int8_t interface_id, uint8_t *dst_address, uint16_t port)
00533 {
00534     thread_management_t *this;
00535     uint8_t *ptr, *data_ptr;
00536     uint16_t length;
00537 
00538     if (thread_joiner_application_provisioning_get(interface_id) == PROVISIONING_STATUS_ONGOING) {
00539         // wait for response to to the message
00540         return 0;
00541     }
00542 
00543     tr_debug("Thread provisioning start send");
00544     this = thread_management_find(interface_id);
00545     device_configuration_s *device_configuration_ptr = thread_joiner_application_get_device_config(interface_id);
00546 
00547     if (!this || !device_configuration_ptr) {
00548         return -1;
00549     }
00550     length = thread_joiner_application_device_configuration_length(device_configuration_ptr);
00551     length += 3;// State
00552 
00553     data_ptr = ptr = ns_dyn_mem_alloc(length);
00554     if (!ptr) {
00555         tr_error("Failed to start Commissioning");
00556         return -1;
00557     }
00558     ptr = thread_joiner_application_device_configuration_build(ptr, device_configuration_ptr);
00559     ptr = thread_tmfcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, 1);
00560 
00561 
00562     thread_joiner_application_provisioning_set(interface_id, PROVISIONING_STATUS_ONGOING);
00563 
00564     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, dst_address, port,
00565                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_JOINER_APPLICATION_REQUEST, COAP_CT_OCTET_STREAM,
00566                               data_ptr, ptr - data_ptr, thread_management_client_provision_request_cb);
00567 
00568     ns_dyn_mem_free(data_ptr);
00569 
00570     return 0;
00571 }
00572 
00573 static int thread_management_client_proactive_an_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00574 {
00575     (void) service_id;
00576     (void) source_address;
00577     (void) source_port;
00578     (void) response_ptr;
00579     return 0;
00580 }
00581 
00582 void thread_management_client_proactive_an(int8_t interface_id, const uint8_t address[16], const uint16_t rloc, const uint8_t ml_eid[8], const uint8_t dst_addr[16])
00583 {
00584     thread_management_t *this = thread_management_find(interface_id);
00585     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00586 
00587     if (!this || !cur) {
00588         tr_warn("No resolution client or protocol info!");
00589         return;
00590     }
00591 
00592     tr_debug("Thread resolution client; proactive address notification");
00593 
00594     uint8_t payload[2 + 16 + 2 + 2 + 2 + 8];
00595     uint8_t *ptr;
00596 
00597     ptr = payload;
00598     ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_TARGET_EID, 16, address);
00599     ptr = thread_tmfcop_tlv_data_write_uint16(ptr, TMFCOP_TLV_RLOC16, rloc);
00600     ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_ML_EID, 8, ml_eid);
00601 
00602     coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE,
00603                               dst_addr, THREAD_MANAGEMENT_PORT,
00604                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST,
00605                               THREAD_URI_ADDRESS_NOTIFICATION, COAP_CT_OCTET_STREAM,
00606                               payload, ptr - payload, thread_management_client_proactive_an_cb);
00607 }
00608 void thread_management_client_coap_message_delete(int8_t interface_id, uint16_t coap_message_id)
00609 {
00610     thread_management_t *this = thread_management_find(interface_id);
00611 
00612     if (!this) {
00613         return;
00614     }
00615 
00616     coap_service_request_delete(this->coap_service_id, coap_message_id);
00617 }
00618 
00619 void thread_management_client_old_partition_data_clean(int8_t interface_id)
00620 {
00621     thread_management_t *this = thread_management_find(interface_id);
00622     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00623 
00624     if (!this || !cur) {
00625         return;
00626     }
00627 
00628     cur->thread_info->localServerDataBase.publish_coap_req_id = 0;
00629     cur->thread_info->routerIdRequested = false;
00630     coap_service_request_delete_by_service_id(this->coap_service_id);
00631 }
00632 
00633 #ifdef HAVE_THREAD_V2
00634 void thread_management_client_addr_ntf_send(int8_t interface_id, uint8_t *destination_address, const uint8_t *addr_data_ptr, uint8_t bbr_status)
00635 {
00636     uint8_t payload[16 + 1]; // Target eid + Status
00637     uint8_t *ptr;
00638     uint8_t br_ml_addr[16];
00639     uint8_t seq;
00640     uint32_t delay_timer;
00641     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00642 
00643     if (!cur) {
00644         return;
00645     }
00646 
00647     if (!thread_bootstrap_is_domain_prefix(cur, addr_data_ptr)) {
00648         return;
00649     }
00650 
00651     if (0 != thread_common_primary_bbr_get(cur, br_ml_addr, &seq, &delay_timer, NULL)) {
00652         // No pBBR present
00653         return;
00654     }
00655 
00656     ptr = payload;
00657     ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_TARGET_EID, 16, addr_data_ptr);
00658     ptr = thread_tmfcop_tlv_data_write_uint8(ptr, TMFCOP_TLV_STATUS, bbr_status);
00659 
00660     coap_service_request_send(thread_management_server_service_id_get(cur->id), COAP_REQUEST_OPTIONS_ADDRESS_SHORT,
00661                               destination_address, THREAD_MANAGEMENT_PORT,
00662                               COAP_MSG_TYPE_NON_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST,
00663                               THREAD_URI_BBR_DOMAIN_ADDRESS_NOTIFICATION, COAP_CT_OCTET_STREAM,
00664                               payload, ptr - payload, NULL);
00665     return;
00666 }
00667 static int thread_bootstrap_mlr_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr)
00668 {
00669     (void) service_id;
00670     (void) source_address;
00671     (void) source_port;
00672     (void) response_ptr;
00673 
00674     tr_debug("Thread MLR callback");
00675     return 0;
00676 }
00677 
00678 int thread_management_client_mlr_req_send(int8_t interface_id, const uint8_t br_addr[16], const uint8_t *address, uint8_t address_len)
00679 {
00680     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00681 
00682     if (!cur || !br_addr || !address) {
00683         return -1;
00684     }
00685     tr_debug("thread MLR.req send");
00686 
00687     coap_service_request_send(thread_management_server_service_id_get(cur->id), COAP_REQUEST_OPTIONS_NONE, br_addr, THREAD_MANAGEMENT_PORT,
00688                               COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_BBR_MCAST_LISTENER_REPORT, COAP_CT_OCTET_STREAM, address, address_len, thread_bootstrap_mlr_cb);
00689     return 0;
00690 }
00691 #endif
00692 #endif