Example
Dependencies: FXAS21002 FXOS8700Q
simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_nsdl.c
- Committer:
- maygup01
- Date:
- 2019-11-19
- Revision:
- 0:11cc2b7889af
File content as of revision 0:11cc2b7889af:
/* * Copyright (c) 2011-2015 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * \file sn_nsdl.c * * \brief Nano service device library * */ // Needed for PRIu64 on FreeRTOS #include <stdio.h> // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif // Note: this macro is needed on armcc to get the the PRI*32 macros // from inttypes.h in a C++ code. #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include <string.h> #include <assert.h> #include "ns_types.h" #include "sn_nsdl.h" #include "sn_coap_header.h" #include "sn_coap_protocol.h" #include "source/include/sn_coap_protocol_internal.h" #include "sn_nsdl_lib.h" #include "sn_grs.h" #include "mbed-trace/mbed_trace.h" #include "mbedtls/base64.h" #include "common_functions.h" #include "randLIB.h" #include <stdlib.h> /* Defines */ #define TRACE_GROUP "mClt" #define RESOURCE_DIR_LEN 2 #define EP_NAME_PARAMETERS_LEN 3 #define ET_PARAMETER_LEN 3 #define LT_PARAMETER_LEN 3 #define DOMAIN_PARAMETER_LEN 2 #define RT_PARAMETER_LEN 3 #define IF_PARAMETER_LEN 3 #define NAME_PARAMETER_LEN 5 #define OBS_PARAMETER_LEN 3 #define AOBS_PARAMETER_LEN 5 #define COAP_CON_PARAMETER_LEN 3 #define BS_EP_PARAMETER_LEN 3 #define BS_QUEUE_MODE_PARAMETER_LEN 2 #define RESOURCE_VALUE_PARAMETER_LEN 2 #define FIRMWARE_DOWNLOAD_LEN 2 #define GENERIC_DOWNLOAD_LEN 8 #define SN_NSDL_EP_REGISTER_MESSAGE 1 #define SN_NSDL_EP_UPDATE_MESSAGE 2 #if defined MBED_CONF_MBED_CLIENT_COAP_DISABLE_OBS_FEATURE #define COAP_DISABLE_OBS_FEATURE MBED_CONF_MBED_CLIENT_COAP_DISABLE_OBS_FEATURE #endif #if defined MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE #define MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE #endif /* Constants */ static uint8_t ep_name_parameter_string[] = {'e', 'p', '='}; /* Endpoint name. A unique name for the registering node in a domain. */ static uint8_t resource_path_ptr[] = {'r', 'd'}; /* For resource directory */ static uint8_t resource_type_parameter[] = {'r', 't', '='}; /* Resource type. Only once for registration */ #ifndef COAP_DISABLE_OBS_FEATURE static uint8_t obs_parameter[] = {'o', 'b', 's'}; /* Observable */ static uint8_t aobs_parameter[] = {'a', 'o', 'b', 's', '='}; /* Auto observable */ #endif static uint8_t if_description_parameter[] = {'i', 'f', '='}; /* Interface description. Only once */ static uint8_t ep_lifetime_parameter[] = {'l', 't', '='}; /* Lifetime. Number of seconds that this registration will be valid for. Must be updated within this time, or will be removed. */ static uint8_t ep_domain_parameter[] = {'d', '='}; /* Domain name. If this parameter is missing, a default domain is assumed. */ static uint8_t coap_con_type_parameter[] = {'c', 't', '='}; /* CoAP content type */ static uint8_t resource_value[] = {'v', '='}; /* Resource value */ #ifdef RESOURCE_ATTRIBUTES_LIST static uint8_t name_parameter[] = {'n', 'a', 'm', 'e', '='}; #endif static uint8_t firmware_download_uri[] = {'f', 'w'}; /* Path for firmware update. */ static uint8_t generic_download_uri[] = {'d', 'o', 'w', 'n', 'l', 'o', 'a', 'd'}; /* Path for generic download. */ /* * OMA BS parameters * */ static uint8_t bs_uri[] = {'b', 's'}; static uint8_t bs_ep_name[] = {'e', 'p', '='}; static uint8_t et_parameter[] = {'e', 't', '='}; /* Endpoint type */ static uint8_t bs_queue_mode[] = {'b', '='}; /* Function prototypes */ static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr); static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle); int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration); static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error); static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type, const char *uri_query); static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *parameter_ptr, sn_coap_hdr_s *source_msg_ptr, uint8_t msg_type, const char *uri_query); static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr); static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr); static uint8_t sn_nsdl_itoa_len(uint32_t value); static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint32_t value); static int8_t set_endpoint_info(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr); static bool validateParameters(sn_nsdl_ep_parameters_s *parameter_ptr); static bool validate(uint8_t* ptr, uint32_t len, char illegalChar); static bool sn_nsdl_check_uint_overflow(uint16_t resource_size, uint16_t param_a, uint16_t param_b); static void remove_previous_block_data(struct nsdl_s *handle, sn_nsdl_addr_s *src_ptr, const uint32_t block_number); static bool update_last_block_data(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, bool block1); #if MBED_CONF_MBED_TRACE_ENABLE static const char* sn_nsdl_coap_status_description(sn_coap_status_e status); static const char* sn_nsdl_coap_message_code_desc(int msg_code); static const char* sn_nsdl_coap_message_type_desc(int msg_type); #endif static void sn_nsdl_add_token(struct nsdl_s *handle, uint32_t *token, sn_coap_hdr_s *message_ptr); int8_t sn_nsdl_destroy(struct nsdl_s *handle) { if (handle == NULL) { return SN_NSDL_FAILURE; } if (handle->ep_information_ptr) { handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); handle->sn_nsdl_free(handle->ep_information_ptr->location_ptr); handle->sn_nsdl_free(handle->ep_information_ptr->type_ptr); handle->sn_nsdl_free(handle->ep_information_ptr->lifetime_ptr); handle->sn_nsdl_free(handle->ep_information_ptr); } if (handle->server_address.addr_ptr) { handle->sn_nsdl_free(handle->server_address.addr_ptr); handle->server_address.addr_ptr = NULL; handle->server_address.type = SN_NSDL_ADDRESS_TYPE_NONE; } /* Destroy also libCoap and grs part of libNsdl */ sn_coap_protocol_destroy(handle->grs->coap); sn_grs_destroy(handle->grs); handle->sn_nsdl_free(handle); return SN_NSDL_SUCCESS; } struct nsdl_s *sn_nsdl_init(uint8_t (*sn_nsdl_tx_cb)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *), uint8_t (*sn_nsdl_rx_cb)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), void *(*sn_nsdl_alloc)(uint16_t), void (*sn_nsdl_free)(void *), uint8_t (*sn_nsdl_auto_obs_token_cb)(struct nsdl_s *, const char *, uint8_t *)) { /* Check pointers and define function pointers */ if (!sn_nsdl_alloc || !sn_nsdl_free || !sn_nsdl_tx_cb || !sn_nsdl_rx_cb) { return NULL; } struct nsdl_s *handle = NULL; handle = sn_nsdl_alloc(sizeof(struct nsdl_s)); if (handle == NULL) { return NULL; } memset(handle, 0, sizeof(struct nsdl_s)); /* Define function pointers */ handle->sn_nsdl_alloc = sn_nsdl_alloc; handle->sn_nsdl_free = sn_nsdl_free; handle->sn_nsdl_tx_callback = sn_nsdl_tx_cb; handle->sn_nsdl_rx_callback = sn_nsdl_rx_cb; handle->sn_nsdl_auto_obs_token_callback = sn_nsdl_auto_obs_token_cb; /* Initialize ep parameters struct */ if (!handle->ep_information_ptr) { handle->ep_information_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_ep_parameters_s)); if (!handle->ep_information_ptr) { sn_nsdl_free(handle); return NULL; } memset(handle->ep_information_ptr, 0, sizeof(sn_nsdl_ep_parameters_s)); } handle->grs = sn_grs_init(sn_nsdl_tx_cb, &sn_nsdl_local_rx_function, sn_nsdl_alloc, sn_nsdl_free); /* Initialize GRS */ if (handle->grs == NULL) { handle->sn_nsdl_free(handle->ep_information_ptr); handle->ep_information_ptr = 0; sn_nsdl_free(handle); return NULL; } sn_nsdl_resolve_nsp_address(handle); handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_NOT_REGISTERED; handle->context = NULL; randLIB_get_n_bytes_random(&handle->token_seed, sizeof(handle->token_seed)); if (handle->token_seed == 0) { handle->token_seed++; } return handle; } uint16_t sn_nsdl_register_endpoint(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr, const char *uri_query_parameters) { /* Local variables */ sn_coap_hdr_s *register_message_ptr; uint16_t message_id = 0; if (endpoint_info_ptr == NULL || handle == NULL) { return 0; } // Clear any leftovers from previous registration or bootstrap sn_nsdl_clear_coap_sent_blockwise_messages(handle); sn_nsdl_clear_coap_received_blockwise_messages(handle); sn_nsdl_clear_coap_resending_queue(handle); /*** Build endpoint register message ***/ handle->is_bs_server = false; /* Allocate memory for header struct */ register_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); if (register_message_ptr == NULL) { return 0; } /* Fill message fields -> confirmable post to specified NSP path */ register_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; register_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_POST; /* Allocate memory for the extended options list */ if (sn_coap_parser_alloc_options(handle->grs->coap, register_message_ptr) == NULL) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); register_message_ptr = 0; return 0; } register_message_ptr->uri_path_len = sizeof(resource_path_ptr); register_message_ptr->uri_path_ptr = resource_path_ptr; /* Fill Uri-query options */ if( SN_NSDL_FAILURE == sn_nsdl_fill_uri_query_options(handle, endpoint_info_ptr, register_message_ptr, SN_NSDL_EP_REGISTER_MESSAGE, uri_query_parameters) ){ register_message_ptr->uri_path_ptr = NULL; sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return 0; } if (endpoint_info_ptr->ds_register_mode == REGISTER_WITH_RESOURCES) { /* Built body for message */ if (sn_nsdl_build_registration_body(handle, register_message_ptr, 0) == SN_NSDL_FAILURE) { register_message_ptr->uri_path_ptr = NULL; register_message_ptr->options_list_ptr->uri_host_ptr = NULL; sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return 0; } } tr_info("REGISTER MESSAGE %.*s", register_message_ptr->payload_len, register_message_ptr->payload_ptr); /* Clean (possible) existing and save new endpoint info to handle */ if (set_endpoint_info(handle, endpoint_info_ptr) == -1) { handle->sn_nsdl_free(register_message_ptr->payload_ptr); register_message_ptr->payload_ptr = NULL; register_message_ptr->uri_path_ptr = NULL; register_message_ptr->options_list_ptr->uri_host_ptr = NULL; sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return 0; } sn_nsdl_add_token(handle, &handle->register_token, register_message_ptr); /* Build and send coap message to NSP */ message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, &handle->server_address); handle->sn_nsdl_free(register_message_ptr->payload_ptr); register_message_ptr->payload_ptr = NULL; register_message_ptr->uri_path_ptr = NULL; register_message_ptr->options_list_ptr->uri_host_ptr = NULL; register_message_ptr->token_ptr = NULL; register_message_ptr->token_len = 0; sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return message_id; } int32_t sn_nsdl_unregister_endpoint(struct nsdl_s *handle) { /* Local variables */ sn_coap_hdr_s *unregister_message_ptr; uint8_t *temp_ptr = 0; int32_t message_id = 0; /* Check parameters */ if (handle == NULL) { return 0; } /* Check that EP have been registered */ if (sn_nsdl_is_ep_registered(handle)) { /* Memory allocation for unregister message */ unregister_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); if (!unregister_message_ptr) { return 0; } /* Fill unregister message */ unregister_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; unregister_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_DELETE; if(handle->ep_information_ptr->location_ptr) { unregister_message_ptr->uri_path_len = handle->ep_information_ptr->location_len; unregister_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(unregister_message_ptr->uri_path_len); if (!unregister_message_ptr->uri_path_ptr) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); return 0; } temp_ptr = unregister_message_ptr->uri_path_ptr; memcpy(temp_ptr , handle->ep_information_ptr->location_ptr, handle->ep_information_ptr->location_len); } else { unregister_message_ptr->uri_path_len = (RESOURCE_DIR_LEN + 1 + handle->ep_information_ptr->domain_name_len + 1 + handle->ep_information_ptr->endpoint_name_len); unregister_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(unregister_message_ptr->uri_path_len); if (!unregister_message_ptr->uri_path_ptr) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); return 0; } temp_ptr = unregister_message_ptr->uri_path_ptr; memcpy(temp_ptr, resource_path_ptr, RESOURCE_DIR_LEN); temp_ptr += RESOURCE_DIR_LEN; *temp_ptr++ = '/'; memcpy(temp_ptr , handle->ep_information_ptr->domain_name_ptr, handle->ep_information_ptr->domain_name_len); temp_ptr += handle->ep_information_ptr->domain_name_len; *temp_ptr++ = '/'; memcpy(temp_ptr , handle->ep_information_ptr->endpoint_name_ptr, handle->ep_information_ptr->endpoint_name_len); } sn_nsdl_add_token(handle, &handle->unregister_token, unregister_message_ptr); /* Send message */ message_id = sn_nsdl_internal_coap_send(handle, unregister_message_ptr, &handle->server_address); unregister_message_ptr->token_ptr = NULL; unregister_message_ptr->token_len = 0; /* Free memory */ sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); } return message_id; } int32_t sn_nsdl_update_registration(struct nsdl_s *handle, uint8_t *lt_ptr, uint8_t lt_len) { /* Local variables */ sn_coap_hdr_s *register_message_ptr; uint8_t *temp_ptr; sn_nsdl_ep_parameters_s temp_parameters; int32_t message_id = 0; /* Check parameters */ if (handle == NULL) { return -1; } if (!sn_nsdl_is_ep_registered(handle)){ return -1; } memset(&temp_parameters, 0, sizeof(sn_nsdl_ep_parameters_s)); temp_parameters.lifetime_len = lt_len; temp_parameters.lifetime_ptr = lt_ptr; if (handle->ep_information_ptr) { temp_parameters.type_len = handle->ep_information_ptr->type_len; temp_parameters.type_ptr = handle->ep_information_ptr->type_ptr; } /*** Build endpoint register update message ***/ /* Allocate memory for header struct */ register_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); if (register_message_ptr == NULL) { return -2; } /* Fill message fields -> confirmable post to specified NSP path */ register_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; register_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_POST; if(handle->ep_information_ptr->location_ptr) { register_message_ptr->uri_path_len = handle->ep_information_ptr->location_len; /* = Only location set by Device Server*/ register_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(register_message_ptr->uri_path_len); if (!register_message_ptr->uri_path_ptr) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return -2; } temp_ptr = register_message_ptr->uri_path_ptr; /* location */ memcpy(temp_ptr, handle->ep_information_ptr->location_ptr, handle->ep_information_ptr->location_len); } else { register_message_ptr->uri_path_len = sizeof(resource_path_ptr) + handle->ep_information_ptr->domain_name_len + handle->ep_information_ptr->endpoint_name_len + 2; /* = rd/domain/endpoint */ register_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(register_message_ptr->uri_path_len); if (!register_message_ptr->uri_path_ptr) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return -2; } temp_ptr = register_message_ptr->uri_path_ptr; /* rd/ */ memcpy(temp_ptr, resource_path_ptr, sizeof(resource_path_ptr)); temp_ptr += sizeof(resource_path_ptr); *temp_ptr++ = '/'; /* rd/DOMAIN/ */ memcpy(temp_ptr, handle->ep_information_ptr->domain_name_ptr, handle->ep_information_ptr->domain_name_len); temp_ptr += handle->ep_information_ptr->domain_name_len; *temp_ptr++ = '/'; /* rd/domain/ENDPOINT */ memcpy(temp_ptr, handle->ep_information_ptr->endpoint_name_ptr, handle->ep_information_ptr->endpoint_name_len); } /* Allocate memory for the extended options list */ if (sn_coap_parser_alloc_options(handle->grs->coap, register_message_ptr) == NULL) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return -2; } /* Fill Uri-query options */ sn_nsdl_fill_uri_query_options(handle, &temp_parameters, register_message_ptr, SN_NSDL_EP_UPDATE_MESSAGE, NULL); /* Build payload */ if (handle->ep_information_ptr->ds_register_mode == REGISTER_WITH_RESOURCES) { if (sn_nsdl_build_registration_body(handle, register_message_ptr, 1) == SN_NSDL_FAILURE) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); return -2; } } // Remove previous update reg message from the queue if exists sn_nsdl_remove_msg_from_retransmission(handle, (uint8_t*)&handle->update_register_token, sizeof(handle->update_register_token)); sn_nsdl_add_token(handle, &handle->update_register_token, register_message_ptr); /* Build and send coap message to NSP */ message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, &handle->server_address); register_message_ptr->token_ptr = NULL; register_message_ptr->token_len = 0; handle->sn_nsdl_free(register_message_ptr->payload_ptr); sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); if (message_id == 0) { // Failure when sending return -2; } return message_id; } int8_t sn_nsdl_set_endpoint_location(struct nsdl_s *handle, uint8_t *location_ptr, uint8_t location_len) { if(!handle || !location_ptr || (location_len == 0)) { return -1; } handle->sn_nsdl_free(handle->ep_information_ptr->location_ptr); handle->ep_information_ptr->location_ptr = handle->sn_nsdl_alloc(location_len); memcpy(handle->ep_information_ptr->location_ptr, location_ptr, location_len); handle->ep_information_ptr->location_len = location_len; return 0; } void sn_nsdl_nsp_lost(struct nsdl_s *handle) { /* Check parameters */ if (handle == NULL) { return; } handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_NOT_REGISTERED; } int8_t sn_nsdl_is_ep_registered(struct nsdl_s *handle) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } return handle->sn_nsdl_endpoint_registered; } int32_t sn_nsdl_send_observation_notification(struct nsdl_s *handle, uint8_t *token_ptr, uint8_t token_len, uint8_t *payload_ptr, uint16_t payload_len, sn_coap_observe_e observe, sn_coap_msg_type_e message_type, sn_coap_content_format_e content_format, const int32_t message_id) { sn_coap_hdr_s *notification_message_ptr; int32_t return_msg_id = 0; /* Check parameters */ if (handle == NULL || handle->grs == NULL || token_len == 0) { return 0; } /* Allocate and initialize memory for header struct */ notification_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); if (notification_message_ptr == NULL) { return 0; } if (sn_coap_parser_alloc_options(handle->grs->coap, notification_message_ptr) == NULL) { handle->sn_nsdl_free(notification_message_ptr); return 0; } /* Fill header */ notification_message_ptr->msg_type = message_type; notification_message_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; /* Fill token */ notification_message_ptr->token_len = token_len; notification_message_ptr->token_ptr = token_ptr; /* Fill payload */ notification_message_ptr->payload_len = payload_len; notification_message_ptr->payload_ptr = payload_ptr; /* Fill observe */ notification_message_ptr->options_list_ptr->observe = observe; /* Fill content format */ notification_message_ptr->content_format = content_format; if (message_id != -1) { notification_message_ptr->msg_id = message_id; } /* Send message */ return_msg_id = sn_nsdl_send_coap_message(handle, &handle->server_address, notification_message_ptr); if (return_msg_id >= SN_NSDL_SUCCESS) { return_msg_id = notification_message_ptr->msg_id; } /* Free memory */ notification_message_ptr->payload_ptr = NULL; notification_message_ptr->token_ptr = NULL; sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, notification_message_ptr); return return_msg_id; } /* * * * * * * * * * */ /* ~ OMA functions ~ */ /* * * * * * * * * * */ uint16_t sn_nsdl_oma_bootstrap(struct nsdl_s *handle, sn_nsdl_addr_s *bootstrap_address_ptr, sn_nsdl_ep_parameters_s *endpoint_info_ptr, const char *uri_query_parameters) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE /* Local variables */ sn_coap_hdr_s bootstrap_coap_header; uint8_t *uri_query_tmp_ptr; uint16_t message_id = 0; /* Check parameters */ if (!bootstrap_address_ptr || !endpoint_info_ptr || !handle) { return 0; } if (set_NSP_address(handle, bootstrap_address_ptr->addr_ptr, bootstrap_address_ptr->addr_len, bootstrap_address_ptr->port, bootstrap_address_ptr->type) == SN_NSDL_FAILURE) { return 0; } handle->is_bs_server = true; /* XXX FIX -- Init CoAP header struct */ sn_coap_parser_init_message(&bootstrap_coap_header); if (!sn_coap_parser_alloc_options(handle->grs->coap, &bootstrap_coap_header)) { return 0; } /* Build bootstrap start message */ bootstrap_coap_header.msg_code = COAP_MSG_CODE_REQUEST_POST; bootstrap_coap_header.msg_type = COAP_MSG_TYPE_CONFIRMABLE; bootstrap_coap_header.uri_path_ptr = bs_uri; bootstrap_coap_header.uri_path_len = sizeof(bs_uri); size_t query_len = endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_LEN; size_t optional_params_len = 0; if (uri_query_parameters) { optional_params_len = strlen(uri_query_parameters); } query_len += optional_params_len; if (query_len > MAX_URI_QUERY_LEN) { handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); tr_error("sn_nsdl_oma_bootstrap - max param length reached (%lu)", (unsigned long)query_len); return 0; } uri_query_tmp_ptr = handle->sn_nsdl_alloc(query_len); if (!uri_query_tmp_ptr) { handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); return 0; } memcpy(uri_query_tmp_ptr, bs_ep_name, BS_EP_PARAMETER_LEN); memcpy((uri_query_tmp_ptr + BS_EP_PARAMETER_LEN), endpoint_info_ptr->endpoint_name_ptr, endpoint_info_ptr->endpoint_name_len); if (optional_params_len > 0) { memcpy(uri_query_tmp_ptr + endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_LEN, uri_query_parameters, optional_params_len); } bootstrap_coap_header.options_list_ptr->uri_query_len = query_len; bootstrap_coap_header.options_list_ptr->uri_query_ptr = uri_query_tmp_ptr; /* Save bootstrap server address */ sn_nsdl_add_token(handle, &handle->bootstrap_token, &bootstrap_coap_header); /* Send message */ message_id = sn_nsdl_internal_coap_send(handle, &bootstrap_coap_header, bootstrap_address_ptr); /* Free allocated memory */ handle->sn_nsdl_free(uri_query_tmp_ptr); handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); return message_id; #else return 0; #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } char *sn_nsdl_get_version(void) { #if defined(YOTTA_MBED_CLIENT_C_VERSION_STRING) return YOTTA_MBED_CLIENT_C_VERSION_STRING; #elif defined(VERSION) return VERSION; #else return "0.0.0"; #endif } int8_t sn_nsdl_process_coap(struct nsdl_s *handle, uint8_t *packet_ptr, uint16_t packet_len, sn_nsdl_addr_s *src_ptr) { sn_coap_hdr_s *coap_packet_ptr = NULL; sn_coap_hdr_s *coap_response_ptr = NULL; sn_nsdl_dynamic_resource_parameters_s *resource = NULL; /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } /* Parse CoAP packet */ coap_packet_ptr = sn_coap_protocol_parse(handle->grs->coap, src_ptr, packet_len, packet_ptr, (void *)handle); /* Check if parsing was successfull */ if (coap_packet_ptr == (sn_coap_hdr_s *)NULL) { return SN_NSDL_FAILURE; } sn_nsdl_print_coap_data(coap_packet_ptr, false); #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE // Pass block to application if external_memory_block is set if((coap_packet_ptr->options_list_ptr && coap_packet_ptr->options_list_ptr->block1 != -1) && (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING || coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED)) { // Block 1 handling /* Get resource */ char* path = handle->sn_nsdl_alloc(coap_packet_ptr->uri_path_len + 1); if (!path) { return SN_NSDL_FAILURE; } memcpy(path, coap_packet_ptr->uri_path_ptr, coap_packet_ptr->uri_path_len); path[coap_packet_ptr->uri_path_len] = '\0'; resource = sn_nsdl_get_resource(handle, path); handle->sn_nsdl_free(path); if (coap_packet_ptr->options_list_ptr) { if(resource && resource->static_resource_parameters->external_memory_block && coap_packet_ptr->options_list_ptr->block1) { uint32_t block_number = coap_packet_ptr->options_list_ptr->block1 >> 4; if (block_number) { remove_previous_block_data(handle, src_ptr, block_number); } // Whole message received --> pass only the last block data to application if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { // Get the block size uint8_t temp = (coap_packet_ptr->options_list_ptr->block1 & 0x07); uint16_t block_size = 1u << (temp + 4); uint32_t new_payload_len = coap_packet_ptr->payload_len - block_size; uint8_t *temp_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); if (temp_ptr) { // Skip the second last block data since it's still stored in mbed-coap list! memcpy(temp_ptr, coap_packet_ptr->payload_ptr + block_size, new_payload_len); handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); coap_packet_ptr->payload_ptr = NULL; coap_packet_ptr->payload_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); if (coap_packet_ptr->payload_ptr) { memcpy(coap_packet_ptr->payload_ptr, temp_ptr, new_payload_len); coap_packet_ptr->payload_len = new_payload_len; } handle->grs->coap->sn_coap_protocol_free(temp_ptr); } } } else { resource = NULL; } } else { resource = NULL; } } #endif // Handling of GET responses if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CONTENT) { bool data_updated = false; if (coap_packet_ptr->options_list_ptr && coap_packet_ptr->options_list_ptr->block2 != -1) { uint32_t block_number = coap_packet_ptr->options_list_ptr->block2 >> 4; if (block_number) { remove_previous_block_data(handle, src_ptr, block_number); } // Modify payload to have only last received block data data_updated = update_last_block_data(handle, coap_packet_ptr, false); } handle->sn_nsdl_rx_callback(handle, coap_packet_ptr, src_ptr); if (data_updated) { handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); } #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE // Remove sent blockwise message(GET request) from the linked list. sn_coap_protocol_remove_sent_blockwise_message(handle->grs->coap, coap_packet_ptr->msg_id); #endif sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); return SN_NSDL_SUCCESS; } /* Check, if coap itself sends response, or block receiving is ongoing... */ if (coap_packet_ptr->coap_status != COAP_STATUS_OK && coap_packet_ptr->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr && !resource) { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); return SN_NSDL_SUCCESS; } /* If proxy options added, return not supported */ if (coap_packet_ptr->options_list_ptr) { if (coap_packet_ptr->options_list_ptr->proxy_uri_len) { coap_response_ptr = sn_coap_build_response(handle->grs->coap, coap_packet_ptr, COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED); if (coap_response_ptr) { sn_nsdl_send_coap_message(handle, src_ptr, coap_response_ptr); sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_response_ptr); sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); return SN_NSDL_SUCCESS; } else { sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); return SN_NSDL_FAILURE; } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* If message is response message, call RX callback */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ if (((coap_packet_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE) || (coap_packet_ptr->msg_type >= COAP_MSG_TYPE_ACKNOWLEDGEMENT))) { int8_t retval = sn_nsdl_local_rx_function(handle, coap_packet_ptr, src_ptr); if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { handle->sn_nsdl_free(coap_packet_ptr->payload_ptr); coap_packet_ptr->payload_ptr = 0; } sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); return retval; } #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE /* * If OMA bootstrap message... * */ bool bootstrap_msg = handle->is_bs_server; // Pass bootstrap data to application if (bootstrap_msg) { // If retval is 2 skip the freeing, it will be done in MBED_CLIENT_NSDLINTERFACE_BS_PUT_EVENT event if (handle->sn_nsdl_rx_callback(handle, coap_packet_ptr,src_ptr) != 2) { if (coap_packet_ptr && coap_packet_ptr->options_list_ptr && coap_packet_ptr->coap_status != COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED && coap_packet_ptr->options_list_ptr->block1 != -1) { handle->sn_nsdl_free(coap_packet_ptr->payload_ptr); coap_packet_ptr->payload_ptr = NULL; } sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); } return SN_NSDL_SUCCESS; } #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE /* * * * * * * * * * * * * * * */ /* Other messages are for GRS */ /* * * * * * * * * * * * * * * */ return sn_grs_process_coap(handle, coap_packet_ptr, src_ptr); } int8_t sn_nsdl_exec(struct nsdl_s *handle, uint32_t time) { if(!handle || !handle->grs){ return SN_NSDL_FAILURE; } /* Call CoAP execution function */ return sn_coap_protocol_exec(handle->grs->coap, time); } sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_resource(struct nsdl_s *handle, const char *path_ptr) { /* Check parameters */ if (handle == NULL) { return NULL; } return sn_grs_search_resource(handle->grs, path_ptr, SN_GRS_SEARCH_METHOD); } /** * \fn static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr) * * * \brief To send NSDL messages. Stores message id?s and message description to catch response from NSP server * \param *handle Pointer to nsdl-library handle * \param *coap_header_ptr Pointer to the CoAP message header to be sent * \param *dst_addr_ptr Pointer to the address structure that contains destination address information * \param message_description Message description to be stored to list for waiting response * * \return message id, <=0 if failed */ static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr) { tr_debug("sn_nsdl_internal_coap_send"); uint8_t *coap_message_ptr = NULL; int32_t coap_message_len = 0; #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ int8_t ret_val = prepare_blockwise_message(handle->grs->coap, coap_header_ptr); if( 0 != ret_val ) { return 0; } #endif coap_message_len = sn_coap_builder_calc_needed_packet_data_size_2(coap_header_ptr, handle->grs->coap->sn_coap_block_data_size); tr_debug("sn_nsdl_internal_coap_send - msg len after calc: %" PRId32 "", coap_message_len); if (coap_message_len == 0) { return 0; } coap_message_ptr = handle->sn_nsdl_alloc(coap_message_len); if (!coap_message_ptr) { return 0; } /* Build message */ int16_t ret = sn_coap_protocol_build(handle->grs->coap, dst_addr_ptr, coap_message_ptr, coap_header_ptr, (void *)handle); if (ret < 0) { handle->sn_nsdl_free(coap_message_ptr); return ret; } handle->sn_nsdl_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, coap_message_ptr, coap_message_len, dst_addr_ptr); handle->sn_nsdl_free(coap_message_ptr); return coap_header_ptr->msg_id; } /** * \fn static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle) * * \brief Resolves NSP server address. * * \param *handle Pointer to nsdl-library handle * \note Application must set NSP address with set_nsp_address */ static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle) { memset(&handle->server_address, 0, sizeof(sn_nsdl_addr_s)); handle->server_address.type = SN_NSDL_ADDRESS_TYPE_NONE; } #ifdef RESOURCE_ATTRIBUTES_LIST static char *sn_nsdl_build_resource_attribute_str(char *dst, const sn_nsdl_attribute_item_s *attribute, const char *name, const size_t name_len) { if (attribute != NULL && name != NULL && name_len > 0 && attribute->value) { size_t attribute_len = strlen(attribute->value); *dst++ = ';'; memcpy(dst, name, name_len); dst += name_len; *dst++ = '"'; memcpy(dst, attribute->value, attribute_len); dst += attribute_len; *dst++ = '"'; } return dst; } #endif /** * \fn int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration) * * \brief To build GRS resources to registration message payload * \param *handle Pointer to nsdl-library handle * \param *message_ptr Pointer to CoAP message header * * \return SN_NSDL_SUCCESS = 0, Failed = -1 */ int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration) { tr_debug("sn_nsdl_build_registration_body"); /* Local variables */ uint8_t *temp_ptr; sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr; /* Calculate needed memory and allocate */ int8_t error = 0; uint16_t msg_len = sn_nsdl_calculate_registration_body_size(handle, updating_registeration, &error); if (SN_NSDL_FAILURE == error) { return error; } if (!msg_len) { return SN_NSDL_SUCCESS; } else { message_ptr->payload_len = msg_len; } tr_debug("sn_nsdl_build_registration_body - body size: [%d]", message_ptr->payload_len); message_ptr->payload_ptr = handle->sn_nsdl_alloc(message_ptr->payload_len); if (!message_ptr->payload_ptr) { return SN_NSDL_FAILURE; } /* Build message */ temp_ptr = message_ptr->payload_ptr; resource_temp_ptr = sn_grs_get_first_resource(handle->grs); /* Loop trough all resources */ while (resource_temp_ptr) { /* if resource needs to be registered */ if (resource_temp_ptr->publish_uri) { if (!resource_temp_ptr->always_publish && updating_registeration && resource_temp_ptr->registered == SN_NDSL_RESOURCE_REGISTERED) { resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); continue; } else if (resource_temp_ptr->registered != SN_NDSL_RESOURCE_DELETE) { resource_temp_ptr->registered = SN_NDSL_RESOURCE_REGISTERED; } /* If not first resource, add '.' to separator */ if (temp_ptr != message_ptr->payload_ptr) { *temp_ptr++ = ','; } *temp_ptr++ = '<'; *temp_ptr++ = '/'; size_t path_len = 0; if (resource_temp_ptr->static_resource_parameters->path) { path_len = strlen(resource_temp_ptr->static_resource_parameters->path); } memcpy(temp_ptr, resource_temp_ptr->static_resource_parameters->path, path_len); temp_ptr += path_len; *temp_ptr++ = '>'; /* Resource attributes */ if (resource_temp_ptr->registered == SN_NDSL_RESOURCE_DELETE) { *temp_ptr++ = ';'; *temp_ptr++ = 'd'; } #ifndef RESOURCE_ATTRIBUTES_LIST #ifndef DISABLE_RESOURCE_TYPE size_t resource_type_len = 0; if (resource_temp_ptr->static_resource_parameters->resource_type_ptr) { resource_type_len = strlen(resource_temp_ptr->static_resource_parameters->resource_type_ptr); } if (resource_type_len) { *temp_ptr++ = ';'; memcpy(temp_ptr, resource_type_parameter, RT_PARAMETER_LEN); temp_ptr += RT_PARAMETER_LEN; *temp_ptr++ = '"'; memcpy(temp_ptr, resource_temp_ptr->static_resource_parameters->resource_type_ptr, resource_type_len); temp_ptr += resource_type_len; *temp_ptr++ = '"'; } #endif #ifndef DISABLE_INTERFACE_DESCRIPTION size_t interface_description_len = 0; if (resource_temp_ptr->static_resource_parameters->interface_description_ptr) { interface_description_len = strlen(resource_temp_ptr->static_resource_parameters->interface_description_ptr); } if (interface_description_len) { *temp_ptr++ = ';'; memcpy(temp_ptr, if_description_parameter, IF_PARAMETER_LEN); temp_ptr += IF_PARAMETER_LEN; *temp_ptr++ = '"'; memcpy(temp_ptr, resource_temp_ptr->static_resource_parameters->interface_description_ptr, interface_description_len); temp_ptr += interface_description_len; *temp_ptr++ = '"'; } #endif #else size_t attribute_len = 0; if (resource_temp_ptr->static_resource_parameters->attributes_ptr) { sn_nsdl_attribute_item_s *attribute = resource_temp_ptr->static_resource_parameters->attributes_ptr; while (attribute->attribute_name != ATTR_END) { switch (attribute->attribute_name) { case ATTR_RESOURCE_TYPE: temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, resource_type_parameter, RT_PARAMETER_LEN); break; case ATTR_INTERFACE_DESCRIPTION: temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, if_description_parameter, IF_PARAMETER_LEN); break; case ATTR_ENDPOINT_NAME: temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, name_parameter, NAME_PARAMETER_LEN); break; default: break; } attribute++; } } #endif if (resource_temp_ptr->coap_content_type != 0) { *temp_ptr++ = ';'; memcpy(temp_ptr, coap_con_type_parameter, COAP_CON_PARAMETER_LEN); temp_ptr += COAP_CON_PARAMETER_LEN; *temp_ptr++ = '"'; temp_ptr = sn_nsdl_itoa(temp_ptr, resource_temp_ptr->coap_content_type); *temp_ptr++ = '"'; } /* ;v */ if ((resource_temp_ptr->publish_value > 0) && resource_temp_ptr->resource) { // If the resource is Opaque then do Base64 encoding of data if (resource_temp_ptr->publish_value == 2) { size_t dst_size = (((resource_temp_ptr->resource_len + 2) / 3) << 2) + 1; unsigned char *dst = (unsigned char*)handle->sn_nsdl_alloc(dst_size); size_t olen = 0; if (dst) { if (mbedtls_base64_encode(dst, dst_size, &olen, resource_temp_ptr->resource, resource_temp_ptr->resource_len) == 0) { *temp_ptr++ = ';'; memcpy(temp_ptr, resource_value, RESOURCE_VALUE_PARAMETER_LEN); temp_ptr += RESOURCE_VALUE_PARAMETER_LEN; *temp_ptr++ = '"'; memcpy(temp_ptr, dst, olen); temp_ptr += olen; *temp_ptr++ = '"'; } handle->sn_nsdl_free(dst); } } else { // For resources which does not require Base64 encoding of data *temp_ptr++ = ';'; memcpy(temp_ptr, resource_value, RESOURCE_VALUE_PARAMETER_LEN); temp_ptr += RESOURCE_VALUE_PARAMETER_LEN; *temp_ptr++ = '"'; memcpy(temp_ptr, resource_temp_ptr->resource, resource_temp_ptr->resource_len); temp_ptr += resource_temp_ptr->resource_len; *temp_ptr++ = '"'; } } /* ;aobs / ;obs */ // This needs to be re-visited and may be need an API for maganging obs value for different server implementation #ifndef COAP_DISABLE_OBS_FEATURE if (resource_temp_ptr->auto_observable) { uint8_t token[MAX_TOKEN_SIZE] = {0}; uint8_t len = handle->sn_nsdl_auto_obs_token_callback(handle, resource_temp_ptr->static_resource_parameters->path, (uint8_t*)token); if (len > 0) { *temp_ptr++ = ';'; memcpy(temp_ptr, aobs_parameter, AOBS_PARAMETER_LEN); temp_ptr += AOBS_PARAMETER_LEN; *temp_ptr++ = '"'; uint16_t temp = common_read_16_bit((uint8_t*)token); temp_ptr = sn_nsdl_itoa(temp_ptr, temp); *temp_ptr++ = '"'; } } else if (resource_temp_ptr->observable) { *temp_ptr++ = ';'; memcpy(temp_ptr, obs_parameter, OBS_PARAMETER_LEN); temp_ptr += OBS_PARAMETER_LEN; } #endif } resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); } return SN_NSDL_SUCCESS; } /** * \fn static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error) * * * \brief Calculates registration message payload size * \param *handle Pointer to nsdl-library handle * \param *updating_registeration Pointer to list of GRS resources * \param *error Error code, SN_NSDL_SUCCESS or SN_NSDL_FAILURE * * \return Needed payload size */ static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error) { tr_debug("sn_nsdl_calculate_registration_body_size"); /* Local variables */ uint16_t return_value = 0; *error = SN_NSDL_SUCCESS; const sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr; /* check pointer */ resource_temp_ptr = sn_grs_get_first_resource(handle->grs); while (resource_temp_ptr) { if (resource_temp_ptr->publish_uri) { if (!resource_temp_ptr->always_publish && updating_registeration && resource_temp_ptr->registered == SN_NDSL_RESOURCE_REGISTERED) { resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); continue; } /* If not first resource, then '.' will be added */ if (return_value) { if (sn_nsdl_check_uint_overflow(return_value, 1, 0)) { return_value++; } else { *error = SN_NSDL_FAILURE; break; } } /* Count length for the resource path </path> */ size_t path_len = 0; if (resource_temp_ptr->static_resource_parameters->path) { path_len = strlen(resource_temp_ptr->static_resource_parameters->path); } if (sn_nsdl_check_uint_overflow(return_value, 3, path_len)) { return_value += (3 + path_len); } else { *error = SN_NSDL_FAILURE; break; } /* Count lengths of the attributes */ if (resource_temp_ptr->registered == SN_NDSL_RESOURCE_DELETE) { return_value += 2; } #ifndef RESOURCE_ATTRIBUTES_LIST #ifndef DISABLE_RESOURCE_TYPE /* Resource type parameter */ size_t resource_type_len = 0; if (resource_temp_ptr->static_resource_parameters->resource_type_ptr) { resource_type_len = strlen(resource_temp_ptr->static_resource_parameters->resource_type_ptr); } if (resource_type_len) { /* ;rt="restype" */ if (sn_nsdl_check_uint_overflow(return_value, 6, resource_type_len)) { return_value += (6 + resource_type_len); } else { *error = SN_NSDL_FAILURE; break; } } #endif #ifndef DISABLE_INTERFACE_DESCRIPTION /* Interface description parameter */ size_t interface_description_len = 0; if (resource_temp_ptr->static_resource_parameters->interface_description_ptr) { interface_description_len = strlen(resource_temp_ptr->static_resource_parameters->interface_description_ptr); } if (interface_description_len) { /* ;if="iftype" */ if (sn_nsdl_check_uint_overflow(return_value, 6, interface_description_len)) { return_value += (6 + interface_description_len); } else { *error = SN_NSDL_FAILURE; break; } } #endif #else /* All attributes */ if (resource_temp_ptr->static_resource_parameters->attributes_ptr) { size_t attribute_len = 0; size_t attribute_desc_len = 0; uint8_t success = 1; sn_nsdl_attribute_item_s *item = resource_temp_ptr->static_resource_parameters->attributes_ptr; while (item->attribute_name != ATTR_END) { switch(item->attribute_name) { case ATTR_RESOURCE_TYPE: /* ;rt="restype" */ attribute_desc_len = 6; attribute_len = strlen(item->value); break; case ATTR_INTERFACE_DESCRIPTION: /* ;if="iftype" */ attribute_desc_len = 6; attribute_len = strlen(item->value); break; case ATTR_ENDPOINT_NAME: /* ;name="name" */ attribute_desc_len = 8; attribute_len = strlen(item->value); break; default: break; } if (sn_nsdl_check_uint_overflow(return_value, attribute_desc_len, attribute_len)) { return_value += (attribute_desc_len + attribute_len); } else { success = 0; break; } item++; } if (!success) { *error = SN_NSDL_FAILURE; break; } } #endif if (resource_temp_ptr->coap_content_type != 0) { /* ;if="content" */ uint8_t len = sn_nsdl_itoa_len(resource_temp_ptr->coap_content_type); if (sn_nsdl_check_uint_overflow(return_value, 6, len)) { return_value += (6 + len); } else { *error = SN_NSDL_FAILURE; break; } } if ((resource_temp_ptr->publish_value > 0) && resource_temp_ptr->resource) { /* ;v="" */ uint16_t len = resource_temp_ptr->resource_len; if (resource_temp_ptr->publish_value == 2) { len = (((resource_temp_ptr->resource_len + 2) / 3) << 2); } if (sn_nsdl_check_uint_overflow(return_value, 5, len)) { return_value += 5 + len; } else { *error = SN_NSDL_FAILURE; break; } /* ;v="" */ } #ifndef COAP_DISABLE_OBS_FEATURE // Auto obs will take higher priority // This needs to be re-visited and may be need an API for maganging obs value for different server implementation if (resource_temp_ptr->auto_observable) { /* ;aobs="" */ uint8_t token[MAX_TOKEN_SIZE] = {0}; uint8_t len = handle->sn_nsdl_auto_obs_token_callback(handle, resource_temp_ptr->static_resource_parameters->path, (uint8_t*)token); if (len > 0) { uint16_t temp = common_read_16_bit((uint8_t*)token); uint8_t token_len = sn_nsdl_itoa_len(temp); if (sn_nsdl_check_uint_overflow(return_value, 8, token_len)) { return_value += (8 + token_len); } else { *error = SN_NSDL_FAILURE; break; } } else { *error = SN_NSDL_FAILURE; break; } } else if (resource_temp_ptr->observable) { if (sn_nsdl_check_uint_overflow(return_value, 4, 0)) { return_value += 4; } else { *error = SN_NSDL_FAILURE; break; } } #endif } resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); } return return_value; } /** * \fn static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type) * * * \brief Calculates needed uri query option length * * \param *endpoint_info_ptr Pointer to endpoint info structure * \param msg_type Message type * * \return number of parameters in uri query */ static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type, const char *uri_query) { uint16_t return_value = 0; uint8_t number_of_parameters = 0; if ((endpoint_info_ptr->endpoint_name_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE) && endpoint_info_ptr->endpoint_name_ptr != 0) { return_value += endpoint_info_ptr->endpoint_name_len; return_value += EP_NAME_PARAMETERS_LEN; //ep= number_of_parameters++; } if ((endpoint_info_ptr->type_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE || msg_type == SN_NSDL_EP_UPDATE_MESSAGE) && (endpoint_info_ptr->type_ptr != 0)) { return_value += endpoint_info_ptr->type_len; return_value += ET_PARAMETER_LEN; //et= number_of_parameters++; } if ((endpoint_info_ptr->lifetime_len != 0) && (endpoint_info_ptr->lifetime_ptr != 0)) { return_value += endpoint_info_ptr->lifetime_len; return_value += LT_PARAMETER_LEN; //lt= number_of_parameters++; } if ((endpoint_info_ptr->domain_name_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE) && (endpoint_info_ptr->domain_name_ptr != 0)) { return_value += endpoint_info_ptr->domain_name_len; return_value += DOMAIN_PARAMETER_LEN; //d= number_of_parameters++; } if (((endpoint_info_ptr->binding_and_mode & 0x04) || (endpoint_info_ptr->binding_and_mode & 0x01)) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { return_value += BS_QUEUE_MODE_PARAMETER_LEN; if (endpoint_info_ptr->binding_and_mode & 0x01) { return_value++; } if (endpoint_info_ptr->binding_and_mode & 0x04) { return_value++; } if ((endpoint_info_ptr->binding_and_mode & 0x02) && ((endpoint_info_ptr->binding_and_mode & 0x04) || (endpoint_info_ptr->binding_and_mode & 0x01))) { return_value++; } number_of_parameters++; } if (number_of_parameters != 0) { return_value += (number_of_parameters - 1); } if (uri_query) { return_value += strlen(uri_query); } if (return_value > MAX_URI_QUERY_LEN) { tr_error("sn_nsdl_calculate_uri_query_option_len - max param length reached (%d)", return_value); return_value = 0; } return return_value; } /** * \fn static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *parameter_ptr, sn_coap_hdr_s *source_msg_ptr, uint8_t msg_type) * * * \brief Fills uri-query options to message header struct * \param *handle Pointer to nsdl-library handle * \param *parameter_ptr Pointer to endpoint parameters struct * \param *source_msg_ptr Pointer to CoAP header struct * \param msg_type Message type * * \return SN_NSDL_SUCCESS = 0, Failed = -1 */ static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *parameter_ptr, sn_coap_hdr_s *source_msg_ptr, uint8_t msg_type, const char *uri_query) { uint8_t *temp_ptr = NULL; if( !validateParameters(parameter_ptr) ){ return SN_NSDL_FAILURE; } size_t query_len = sn_nsdl_calculate_uri_query_option_len(parameter_ptr, msg_type, uri_query); if (query_len == 0) { return 0; } source_msg_ptr->options_list_ptr->uri_query_len = query_len; source_msg_ptr->options_list_ptr->uri_query_ptr = handle->sn_nsdl_alloc(query_len); if (source_msg_ptr->options_list_ptr->uri_query_ptr == NULL) { return SN_NSDL_FAILURE; } memset(source_msg_ptr->options_list_ptr->uri_query_ptr, 0, source_msg_ptr->options_list_ptr->uri_query_len); temp_ptr = source_msg_ptr->options_list_ptr->uri_query_ptr; /******************************************************/ /* If endpoint name is configured, fill needed fields */ /******************************************************/ if ((parameter_ptr->endpoint_name_len != 0) && (parameter_ptr->endpoint_name_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { /* fill endpoint name, first ?ep=, then endpoint name */ memcpy(temp_ptr, ep_name_parameter_string, sizeof(ep_name_parameter_string)); temp_ptr += EP_NAME_PARAMETERS_LEN; memcpy(temp_ptr, parameter_ptr->endpoint_name_ptr, parameter_ptr->endpoint_name_len); temp_ptr += parameter_ptr->endpoint_name_len; } /******************************************************/ /* If endpoint type is configured, fill needed fields */ /******************************************************/ if ((parameter_ptr->type_len != 0) && (parameter_ptr->type_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE || msg_type == SN_NSDL_EP_UPDATE_MESSAGE)) { if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { *temp_ptr++ = '&'; } memcpy(temp_ptr, et_parameter, sizeof(et_parameter)); temp_ptr += ET_PARAMETER_LEN; memcpy(temp_ptr, parameter_ptr->type_ptr, parameter_ptr->type_len); temp_ptr += parameter_ptr->type_len; } /******************************************************/ /* If lifetime is configured, fill needed fields */ /******************************************************/ if ((parameter_ptr->lifetime_len != 0) && (parameter_ptr->lifetime_ptr != 0)) { if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { *temp_ptr++ = '&'; } memcpy(temp_ptr, ep_lifetime_parameter, sizeof(ep_lifetime_parameter)); temp_ptr += LT_PARAMETER_LEN; memcpy(temp_ptr, parameter_ptr->lifetime_ptr, parameter_ptr->lifetime_len); temp_ptr += parameter_ptr->lifetime_len; } /******************************************************/ /* If domain is configured, fill needed fields */ /******************************************************/ if ((parameter_ptr->domain_name_len != 0) && (parameter_ptr->domain_name_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { *temp_ptr++ = '&'; } memcpy(temp_ptr, ep_domain_parameter, sizeof(ep_domain_parameter)); temp_ptr += DOMAIN_PARAMETER_LEN; memcpy(temp_ptr, parameter_ptr->domain_name_ptr, parameter_ptr->domain_name_len); temp_ptr += parameter_ptr->domain_name_len; } /******************************************************/ /* If queue-mode is configured, fill needed fields */ /******************************************************/ if (((parameter_ptr->binding_and_mode & 0x01) || (parameter_ptr->binding_and_mode & 0x04)) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { *temp_ptr++ = '&'; } memcpy(temp_ptr, bs_queue_mode, sizeof(bs_queue_mode)); temp_ptr += BS_QUEUE_MODE_PARAMETER_LEN; if (parameter_ptr->binding_and_mode & 0x01) { *temp_ptr++ = 'U'; if (parameter_ptr->binding_and_mode & 0x02) { *temp_ptr++ = 'Q'; } } if (parameter_ptr->binding_and_mode & 0x04) { *temp_ptr++ = 'S'; if ((parameter_ptr->binding_and_mode & 0x02) && !(parameter_ptr->binding_and_mode & 0x01)) { *temp_ptr++ = 'Q'; } } } if (uri_query) { memcpy(temp_ptr, uri_query, strlen(uri_query)); } return SN_NSDL_SUCCESS; } static bool validateParameters(sn_nsdl_ep_parameters_s *parameter_ptr) { if( !validate( parameter_ptr->domain_name_ptr, parameter_ptr->domain_name_len, '&' ) ){ return false; } if( !validate( parameter_ptr->endpoint_name_ptr, parameter_ptr->endpoint_name_len, '&' ) ){ return false; } if( !validate( parameter_ptr->lifetime_ptr, parameter_ptr->lifetime_len, '&' ) ){ return false; } if( !validate( parameter_ptr->type_ptr, parameter_ptr->type_len, '&' ) ){ return false; } return true; } static bool validate(uint8_t* ptr, uint32_t len, char illegalChar) { if( ptr ){ for( uint32_t i=0; i < len; i++ ){ if( ptr[i] == illegalChar ){ return false; } } } return true; } /** * \fn static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr) * * \brief If received message is reply for the message that NSDL has been sent, it is processed here. Else, packet will be sent to application. * \param *handle Pointer to nsdl-library handle * \param *coap_packet_ptr Pointer to received CoAP packet * \param *address_ptr Pointer to source address struct * * \return SN_NSDL_SUCCESS = 0, Failed = -1 */ static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr) { if ((coap_packet_ptr == 0) || (address_ptr == 0)) { return -1; } bool is_reg_msg = false; bool is_update_reg_msg = false; bool is_unreg_msg = false; bool is_bs_msg = false; if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CREATED && coap_packet_ptr->token_len == sizeof(handle->register_token) && memcmp(coap_packet_ptr->token_ptr, &handle->register_token, coap_packet_ptr->token_len) == 0) { handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_IS_REGISTERED; sn_grs_mark_resources_as_registered(handle); is_reg_msg = true; if (sn_nsdl_resolve_ep_information(handle, coap_packet_ptr) != SN_NSDL_SUCCESS) { return SN_NSDL_FAILURE; } } else if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED && coap_packet_ptr->token_len == sizeof(handle->update_register_token) && memcmp(coap_packet_ptr->token_ptr, &handle->update_register_token, coap_packet_ptr->token_len) == 0) { is_update_reg_msg = true; } else if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_DELETED && coap_packet_ptr->token_len == sizeof(handle->unregister_token) && memcmp(coap_packet_ptr->token_ptr, &handle->unregister_token, coap_packet_ptr->token_len) == 0) { is_unreg_msg = true; handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); handle->ep_information_ptr->endpoint_name_ptr = 0; handle->ep_information_ptr->endpoint_name_len = 0; handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); handle->ep_information_ptr->domain_name_ptr = 0; handle->ep_information_ptr->domain_name_len = 0; } else if (coap_packet_ptr->token_len == sizeof(handle->bootstrap_token) && memcmp(coap_packet_ptr->token_ptr, &handle->bootstrap_token, coap_packet_ptr->token_len) == 0) { is_bs_msg = true; } /* Store the current message token so that we can identify if same operation was initiated from callback */ uint32_t temp_token = 0; if (is_reg_msg) { temp_token = handle->register_token; } else if (is_unreg_msg) { temp_token = handle->unregister_token; } else if (is_update_reg_msg) { temp_token = handle->update_register_token; } else if (is_bs_msg) { temp_token = handle->bootstrap_token; } /* No messages to wait for, or message was not response to our request */ int ret = handle->sn_nsdl_rx_callback(handle, coap_packet_ptr, address_ptr); /* If callback initiated same operation then token is updated in handle and temp_token won't match. This means we don't clear the handle token here because we will wait for response to new request. */ if (is_reg_msg && temp_token == handle->register_token) { handle->register_token = 0; } else if (is_unreg_msg && temp_token == handle->unregister_token) { handle->unregister_token = 0; } else if (is_update_reg_msg && temp_token == handle->update_register_token) { handle->update_register_token = 0; } else if (is_bs_msg && temp_token == handle->bootstrap_token) { handle->bootstrap_token = 0; } return ret; } /** * \fn static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr) * * * \brief Resolves endpoint information from received CoAP message * \param *handle Pointer to nsdl-library handle * \param *coap_packet_ptr Pointer to received CoAP message * * \return SN_NSDL_SUCCESS = 0, Failed = -1 */ static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr) { uint8_t *temp_ptr; uint8_t parameter_count = 0; uint16_t parameter_len = 0; if (!coap_packet_ptr || !coap_packet_ptr->options_list_ptr || !coap_packet_ptr->options_list_ptr->location_path_ptr) { return SN_NSDL_FAILURE; } temp_ptr = coap_packet_ptr->options_list_ptr->location_path_ptr; while (temp_ptr <= (coap_packet_ptr->options_list_ptr->location_path_ptr + coap_packet_ptr->options_list_ptr->location_path_len)) { if ((temp_ptr == (coap_packet_ptr->options_list_ptr->location_path_ptr + coap_packet_ptr->options_list_ptr->location_path_len)) || (*temp_ptr == '/')) { parameter_count++; if (parameter_count == 2) { if (!handle->ep_information_ptr->domain_name_ptr) { handle->ep_information_ptr->domain_name_len = parameter_len - 1; handle->ep_information_ptr->domain_name_ptr = handle->sn_nsdl_alloc(handle->ep_information_ptr->domain_name_len); if (!handle->ep_information_ptr->domain_name_ptr) { return SN_NSDL_FAILURE; } memcpy(handle->ep_information_ptr->domain_name_ptr, temp_ptr - handle->ep_information_ptr->domain_name_len, handle->ep_information_ptr->domain_name_len); } } if (parameter_count == 3) { if (!handle->ep_information_ptr->endpoint_name_ptr) { handle->ep_information_ptr->endpoint_name_len = parameter_len - 1; handle->ep_information_ptr->endpoint_name_ptr = handle->sn_nsdl_alloc(handle->ep_information_ptr->endpoint_name_len); if (!handle->ep_information_ptr->endpoint_name_ptr) { if (handle->ep_information_ptr->domain_name_ptr) { handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); handle->ep_information_ptr->domain_name_ptr = NULL; handle->ep_information_ptr->domain_name_len = 0; } return SN_NSDL_FAILURE; } memcpy(handle->ep_information_ptr->endpoint_name_ptr, temp_ptr - handle->ep_information_ptr->endpoint_name_len, handle->ep_information_ptr->endpoint_name_len); } } parameter_len = 0; } parameter_len++; temp_ptr++; } return SN_NSDL_SUCCESS; } extern int8_t set_NSP_address(struct nsdl_s *handle, uint8_t *NSP_address, uint8_t address_length, uint16_t port, sn_nsdl_addr_type_e address_type) { /* Check parameters and source pointers */ if (!handle || !NSP_address) { return SN_NSDL_FAILURE; } handle->server_address.type = address_type; handle->sn_nsdl_free(handle->server_address.addr_ptr); handle->server_address.addr_len = address_length; handle->server_address.addr_ptr = handle->sn_nsdl_alloc(handle->server_address.addr_len); if (!handle->server_address.addr_ptr) { return SN_NSDL_FAILURE; } memcpy(handle->server_address.addr_ptr, NSP_address, handle->server_address.addr_len); handle->server_address.port = port; return SN_NSDL_SUCCESS; } static uint8_t sn_nsdl_itoa_len(uint32_t value) { uint8_t i = 0; do { i++; } while ((value /= 10) > 0); return i; } static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint32_t value) { uint8_t start = 0; uint8_t end = 0; uint8_t i; i = 0; /* ITOA */ do { ptr[i++] = (value % 10) + '0'; } while ((value /= 10) > 0); end = i - 1; /* reverse (part of ITOA) */ while (start < end) { uint8_t chr; chr = ptr[start]; ptr[start] = ptr[end]; ptr[end] = chr; start++; end--; } return (ptr + i); } static int8_t set_endpoint_info(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr) { handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); handle->ep_information_ptr->domain_name_ptr = 0; handle->ep_information_ptr->domain_name_len = 0; handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); handle->ep_information_ptr->endpoint_name_ptr = 0; handle->ep_information_ptr->endpoint_name_len = 0; handle->sn_nsdl_free(handle->ep_information_ptr->type_ptr); handle->ep_information_ptr->type_ptr = 0; handle->ep_information_ptr->type_len = 0; if (endpoint_info_ptr->domain_name_ptr && endpoint_info_ptr->domain_name_len) { handle->ep_information_ptr->domain_name_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->domain_name_len); if (!handle->ep_information_ptr->domain_name_ptr) { return -1; } memcpy(handle->ep_information_ptr->domain_name_ptr, endpoint_info_ptr->domain_name_ptr, endpoint_info_ptr->domain_name_len); handle->ep_information_ptr->domain_name_len = endpoint_info_ptr->domain_name_len; } if (endpoint_info_ptr->endpoint_name_ptr && endpoint_info_ptr->endpoint_name_len) { handle->ep_information_ptr->endpoint_name_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->endpoint_name_len); if (!handle->ep_information_ptr->endpoint_name_ptr) { handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); handle->ep_information_ptr->domain_name_ptr = 0; handle->ep_information_ptr->domain_name_len = 0; return -1; } memcpy(handle->ep_information_ptr->endpoint_name_ptr, endpoint_info_ptr->endpoint_name_ptr, endpoint_info_ptr->endpoint_name_len); handle->ep_information_ptr->endpoint_name_len = endpoint_info_ptr->endpoint_name_len; } if (endpoint_info_ptr->type_ptr && endpoint_info_ptr->type_len) { handle->ep_information_ptr->type_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->type_len); if (handle->ep_information_ptr->type_ptr) { memcpy(handle->ep_information_ptr->type_ptr, endpoint_info_ptr->type_ptr, endpoint_info_ptr->type_len); handle->ep_information_ptr->type_len = endpoint_info_ptr->type_len; } } handle->ep_information_ptr->binding_and_mode = endpoint_info_ptr->binding_and_mode; handle->ep_information_ptr->ds_register_mode = endpoint_info_ptr->ds_register_mode; return 0; } extern int8_t sn_nsdl_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } int8_t ret = sn_grs_send_coap_message(handle, address_ptr, coap_hdr_ptr); return ret; } extern int8_t sn_nsdl_handle_block2_response_internally(struct nsdl_s *handle, uint8_t build_response) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_coap_protocol_handle_block2_response_internally(handle->grs->coap, build_response); } extern int8_t sn_nsdl_clear_coap_sent_blockwise_messages(struct nsdl_s *handle) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } // Enable function once new CoAP API is released to mbed-os sn_coap_protocol_clear_sent_blockwise_messages(handle->grs->coap); return SN_NSDL_SUCCESS; } extern int8_t sn_nsdl_clear_coap_received_blockwise_messages(struct nsdl_s *handle) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } // Enable function once new CoAP API is released to mbed-os // sn_coap_protocol_clear_received_blockwise_messages(handle->grs->coap); /* Loop all stored Blockwise messages in Linked list */ ns_list_foreach_safe(coap_blockwise_payload_s, removed_payload_ptr, &handle->grs->coap->linked_list_blockwise_received_payloads) { ns_list_remove(&handle->grs->coap->linked_list_blockwise_received_payloads, removed_payload_ptr); /* Free memory of stored payload */ handle->grs->coap->sn_coap_protocol_free(removed_payload_ptr->addr_ptr); handle->grs->coap->sn_coap_protocol_free(removed_payload_ptr->payload_ptr); handle->grs->coap->sn_coap_protocol_free(removed_payload_ptr->token_ptr); handle->grs->coap->sn_coap_protocol_free(removed_payload_ptr); } return SN_NSDL_SUCCESS; } extern int32_t sn_nsdl_send_request(struct nsdl_s *handle, const sn_coap_msg_code_e msg_code, const char *uri_path, const uint32_t token, const size_t offset, const uint16_t payload_len, uint8_t* payload_ptr, DownloadType type) { sn_coap_hdr_s req_message; int32_t message_id; if (handle == NULL || uri_path == NULL) { return 0; } memset(&req_message, 0, sizeof(sn_coap_hdr_s)); // Fill message fields req_message.msg_type = COAP_MSG_TYPE_CONFIRMABLE; req_message.msg_code = msg_code; // In GET we use hardcoded uri path('fw' or 'download') since the actual binary path will be part of // proxy uri option if (req_message.msg_code == COAP_MSG_CODE_REQUEST_GET) { if (type == FIRMWARE_DOWNLOAD) { req_message.uri_path_len = FIRMWARE_DOWNLOAD_LEN; req_message.uri_path_ptr = firmware_download_uri; } else { req_message.uri_path_len = GENERIC_DOWNLOAD_LEN; req_message.uri_path_ptr = generic_download_uri; } } else { req_message.uri_path_len = (uint16_t)strlen(uri_path); req_message.uri_path_ptr = (uint8_t*)uri_path; } req_message.token_ptr = (uint8_t*)&token; req_message.token_len = sizeof(token); if (msg_code == COAP_MSG_CODE_REQUEST_POST || msg_code == COAP_MSG_CODE_REQUEST_PUT) { // Use payload only if POST or PUT request req_message.payload_ptr = payload_ptr; req_message.payload_len = payload_len; } if (sn_coap_parser_alloc_options(handle->grs->coap, &req_message) == NULL) { handle->grs->coap->sn_coap_protocol_free(req_message.options_list_ptr); return 0; } if (msg_code == COAP_MSG_CODE_REQUEST_GET) { req_message.options_list_ptr->proxy_uri_len = (uint16_t)strlen(uri_path); req_message.options_list_ptr->proxy_uri_ptr = (uint8_t*)uri_path; } // Skip block options if feature is not enabled #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE // Add block number req_message.options_list_ptr->block2 = 0; if (offset > 0) { req_message.options_list_ptr->block2 = ((offset / handle->grs->coap->sn_coap_block_data_size) << 4); } // Add block size req_message.options_list_ptr->block2 |= sn_coap_convert_block_size(handle->grs->coap->sn_coap_block_data_size); #else (void)offset; #endif // Build and send coap message message_id = sn_nsdl_internal_coap_send(handle, &req_message, &handle->server_address); handle->grs->coap->sn_coap_protocol_free(req_message.options_list_ptr); return message_id; } extern int8_t sn_nsdl_put_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) { if (!handle) { return SN_NSDL_FAILURE; } return sn_grs_put_resource(handle->grs, res); } extern int8_t sn_nsdl_pop_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) { if (!handle) { return SN_NSDL_FAILURE; } return sn_grs_pop_resource(handle->grs, res); } extern int8_t sn_nsdl_delete_resource(struct nsdl_s *handle, const char *path) { /* Check parameters */ if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_grs_delete_resource(handle->grs, path); } extern const sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_first_resource(struct nsdl_s *handle) { /* Check parameters */ if (handle == NULL) { return NULL; } return sn_grs_get_first_resource(handle->grs); } extern const sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_next_resource(struct nsdl_s *handle, const sn_nsdl_dynamic_resource_parameters_s *resource) { /* Check parameters */ if (handle == NULL) { return NULL; } return sn_grs_get_next_resource(handle->grs, resource); } extern sn_coap_hdr_s *sn_nsdl_build_response(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) { if (handle == NULL) { return NULL; } return sn_coap_build_response(handle->grs->coap, coap_packet_ptr, msg_code); } extern sn_coap_options_list_s *sn_nsdl_alloc_options_list(struct nsdl_s *handle, sn_coap_hdr_s *coap_msg_ptr) { if (handle == NULL || coap_msg_ptr == NULL) { return NULL; } return sn_coap_parser_alloc_options(handle->grs->coap, coap_msg_ptr); } extern void sn_nsdl_release_allocated_coap_msg_mem(struct nsdl_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr) { if (handle == NULL) { return; } sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, freed_coap_msg_ptr); } extern int8_t sn_nsdl_set_retransmission_parameters(struct nsdl_s *handle, uint8_t resending_count, uint8_t resending_interval) { if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_coap_protocol_set_retransmission_parameters(handle->grs->coap, resending_count,resending_interval); } extern int8_t sn_nsdl_set_retransmission_buffer(struct nsdl_s *handle, uint8_t buffer_size_messages, uint16_t buffer_size_bytes) { if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_coap_protocol_set_retransmission_buffer(handle->grs->coap, buffer_size_messages, buffer_size_bytes); } extern int8_t sn_nsdl_set_block_size(struct nsdl_s *handle, uint16_t block_size) { if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_coap_protocol_set_block_size(handle->grs->coap, block_size); } extern int8_t sn_nsdl_set_duplicate_buffer_size(struct nsdl_s *handle, uint8_t message_count) { if (handle == NULL) { return SN_NSDL_FAILURE; } return sn_coap_protocol_set_duplicate_buffer_size(handle->grs->coap, message_count); } bool sn_nsdl_check_uint_overflow(uint16_t resource_size, uint16_t param_a, uint16_t param_b) { uint16_t first_check = param_a + param_b; if (first_check < param_b) { return false; } else { uint16_t total = resource_size + first_check; if (total < first_check) { return false; } else { return true; } } } extern int8_t sn_nsdl_set_context(struct nsdl_s * const handle, void * const context) { if (handle == NULL) { return SN_NSDL_FAILURE; } handle->context = context; return SN_NSDL_SUCCESS; } extern void *sn_nsdl_get_context(const struct nsdl_s * const handle) { if (handle == NULL) { return NULL; } return handle->context; } int8_t sn_nsdl_clear_coap_resending_queue(struct nsdl_s *handle) { if (handle == NULL || handle->grs == NULL) { tr_err("sn_nsdl_clear_coap_resending_queue failed."); return SN_NSDL_FAILURE; } sn_coap_protocol_clear_retransmission_buffer(handle->grs->coap); return SN_NSDL_SUCCESS; } int8_t sn_nsdl_remove_msg_from_retransmission(struct nsdl_s *handle, uint8_t *token, uint8_t token_len) { if (handle == NULL || handle->grs == NULL || handle->grs->coap == NULL || token == NULL || token_len == 0) { tr_err("sn_nsdl_remove_msg_from_retransmission failed."); return SN_NSDL_FAILURE; } #if ENABLE_RESENDINGS // Workaround until new "sn_coap_protocol_delete_retransmission_by_token" API is released // return sn_coap_protocol_delete_retransmission_by_token(handle->grs->coap, token, token_len); ns_list_foreach(coap_send_msg_s, stored_msg, &handle->grs->coap->linked_list_resent_msgs) { uint8_t stored_token_len = (stored_msg->send_msg_ptr->packet_ptr[0] & 0x0F); if (stored_token_len == token_len) { uint8_t stored_token[8]; memcpy(stored_token, &stored_msg->send_msg_ptr->packet_ptr[4], stored_token_len); if (memcmp(stored_token, token, stored_token_len) == 0) { uint16_t temp_msg_id = (stored_msg->send_msg_ptr->packet_ptr[2] << 8); temp_msg_id += (uint16_t)stored_msg->send_msg_ptr->packet_ptr[3]; tr_debug("sn_nsdl_remove_msg_from_retransmission - removed msg_id: %d", temp_msg_id); ns_list_remove(&handle->grs->coap->linked_list_resent_msgs, stored_msg); --handle->grs->coap->count_resent_msgs; handle->grs->coap->sn_coap_protocol_free(stored_msg->send_msg_ptr); handle->grs->coap->sn_coap_protocol_free(stored_msg); return 0; } } } #endif return SN_NSDL_FAILURE; } #ifdef RESOURCE_ATTRIBUTES_LIST static void sn_nsdl_free_attribute_value(sn_nsdl_attribute_item_s *attribute) { switch (attribute->attribute_name) { case ATTR_RESOURCE_TYPE: case ATTR_INTERFACE_DESCRIPTION: case ATTR_ENDPOINT_NAME: free(attribute->value); attribute->value = NULL; break; case ATTR_NOP: case ATTR_END: default: break; } } void sn_nsdl_free_resource_attributes_list(sn_nsdl_static_resource_parameters_s *params) { if (params == NULL || params->free_on_delete == false) { return; } sn_nsdl_attribute_item_s *item = params->attributes_ptr; if (item) { while (item->attribute_name != ATTR_END) { sn_nsdl_free_attribute_value(item); item++; } free(params->attributes_ptr); params->attributes_ptr = NULL; } } bool sn_nsdl_set_resource_attribute(sn_nsdl_static_resource_parameters_s *params, const sn_nsdl_attribute_item_s *attribute) { if (params == NULL || params->free_on_delete == false) { return false; } unsigned int item_count = 0; sn_nsdl_attribute_item_s *item = params->attributes_ptr; // Count the number of attributes for reallocation, update in place though // if the attribute already existed while (item != NULL) { item_count++; if (item->attribute_name == ATTR_END) { break; } // Check if attribute already exists or if there is NOP we can overwrite if (item->attribute_name == attribute->attribute_name || item->attribute_name == ATTR_NOP) { // Found attribute or NOP, overwrite it sn_nsdl_free_attribute_value(item); item->attribute_name = attribute->attribute_name; item->value = attribute->value; return true; } item++; } // Attribute did not yet exist (ptr was null or ATTR_END was first one) if (item_count > 0) { // List already had some attributes, so reallocate size_t new_size = (item_count + 1) * sizeof(sn_nsdl_attribute_item_s); item = params->attributes_ptr; params->attributes_ptr = realloc(item, new_size); if (params->attributes_ptr == NULL) { // realloc failed, put back original pointer and return false params->attributes_ptr = item; return false; } // And move item ptr to ATTR_END to update that and last attribute item = &(params->attributes_ptr[item_count - 1]); } else { // No attributes, so allocate first time (1 struct for attribute and 1 struct for ATTR_END) params->attributes_ptr = (char*)malloc(2 * sizeof(sn_nsdl_attribute_item_s)); if (params->attributes_ptr == NULL) { return false; } item = params->attributes_ptr; } item->attribute_name = attribute->attribute_name; item->value = attribute->value; item++; item->attribute_name = ATTR_END; item->value = NULL; return true; } const char *sn_nsdl_get_resource_attribute(const sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute_name) { char *value = NULL; if (params != NULL) { sn_nsdl_attribute_item_s *item = params->attributes_ptr; while (item != NULL && item->attribute_name != ATTR_END) { if (item->attribute_name == attribute_name) { value = item->value; break; } item++; } } return value; } bool sn_nsdl_remove_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute_name) { if (params == NULL || params->free_on_delete == false) { return false; } bool found = false; sn_nsdl_attribute_item_s *item = params->attributes_ptr; while (item != NULL) { if (item->attribute_name == ATTR_END) { break; } // Remove if attribute name matches if (item->attribute_name == attribute_name) { // Currently only pointer values, need to free and set as NOP sn_nsdl_free_attribute_value(item); item->attribute_name = ATTR_NOP; found = true; break; } item++; } return found; } #endif void sn_nsdl_print_coap_data(sn_coap_hdr_s *coap_header_ptr, bool outgoing) { #if MBED_CONF_MBED_TRACE_ENABLE if (!coap_header_ptr) { return; } if (outgoing) { tr_info("======== Outgoing CoAP package ========"); } else { tr_info("======== Incoming CoAP package ========"); } if (coap_header_ptr->uri_path_len > 0 && coap_header_ptr->uri_path_ptr) { tr_info("Uri-Path:\t\t%.*s", coap_header_ptr->uri_path_len, coap_header_ptr->uri_path_ptr); } tr_info("Status:\t\t%s", sn_nsdl_coap_status_description(coap_header_ptr->coap_status)); tr_info("Code:\t\t%s", sn_nsdl_coap_message_code_desc(coap_header_ptr->msg_code)); tr_info("Type:\t\t%s", sn_nsdl_coap_message_type_desc(coap_header_ptr->msg_type)); tr_info("Id:\t\t%d", coap_header_ptr->msg_id); if (coap_header_ptr->token_ptr && coap_header_ptr->token_len > 0) { tr_info("Token:\t\t%s", tr_array(coap_header_ptr->token_ptr, coap_header_ptr->token_len)); } if (coap_header_ptr->content_format != -1) { tr_info("Content-type:\t%d", coap_header_ptr->content_format); } tr_info("Payload len:\t%d", coap_header_ptr->payload_len); #ifdef MBED_CLIENT_PRINT_COAP_PAYLOAD if (coap_header_ptr->payload_ptr && coap_header_ptr->payload_len > 0) { int i = 0; int row_len = 40; int max_length = 2048; while (i < coap_header_ptr->payload_len && i < max_length) { if (i + row_len > coap_header_ptr->payload_len) { row_len = coap_header_ptr->payload_len - i; } tr_info("Payload:\t\t%s", tr_array( coap_header_ptr->payload_ptr + i, row_len)); i += row_len; } if (i >= max_length) tr_info("Payload:\t\t....."); } #endif if (coap_header_ptr->options_list_ptr) { if (coap_header_ptr->options_list_ptr->etag_ptr && coap_header_ptr->options_list_ptr->etag_len > 0) { tr_info("E-tag:\t%s", tr_array(coap_header_ptr->options_list_ptr->etag_ptr, coap_header_ptr->options_list_ptr->etag_len)); } if (coap_header_ptr->options_list_ptr->proxy_uri_ptr && coap_header_ptr->options_list_ptr->proxy_uri_len > 0) { tr_info("Proxy uri:\t%.*s", coap_header_ptr->options_list_ptr->proxy_uri_len, coap_header_ptr->options_list_ptr->proxy_uri_ptr); } if (coap_header_ptr->options_list_ptr->uri_host_ptr && coap_header_ptr->options_list_ptr->uri_host_len > 0) { tr_info("Uri host:\t%.*s", coap_header_ptr->options_list_ptr->uri_host_len, coap_header_ptr->options_list_ptr->uri_host_ptr); } if (coap_header_ptr->options_list_ptr->location_path_ptr && coap_header_ptr->options_list_ptr->location_path_len > 0) { tr_info("Location path:\t%.*s", coap_header_ptr->options_list_ptr->location_path_len, coap_header_ptr->options_list_ptr->location_path_ptr); } if (coap_header_ptr->options_list_ptr->location_query_ptr && coap_header_ptr->options_list_ptr->location_query_len > 0) { tr_info("Location query:\t%.*s", coap_header_ptr->options_list_ptr->location_query_len, coap_header_ptr->options_list_ptr->location_query_ptr); } if (coap_header_ptr->options_list_ptr->uri_query_ptr && coap_header_ptr->options_list_ptr->uri_query_len > 0) { tr_info("Uri query:\t%.*s", coap_header_ptr->options_list_ptr->uri_query_len, coap_header_ptr->options_list_ptr->uri_query_ptr); } tr_info("Max-age:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->max_age); if (coap_header_ptr->options_list_ptr->use_size1) { tr_info("Size 1:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->size1); } if (coap_header_ptr->options_list_ptr->use_size2) { tr_info("Size 2:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->size2); } if (coap_header_ptr->options_list_ptr->accept != -1) { tr_info("Accept:\t\t%d", coap_header_ptr->options_list_ptr->accept); } if (coap_header_ptr->options_list_ptr->uri_port != -1) { tr_info("Uri port:\t%" PRId32"", coap_header_ptr->options_list_ptr->uri_port); } if (coap_header_ptr->options_list_ptr->observe != -1) { tr_info("Observe:\t\t%" PRId32"", coap_header_ptr->options_list_ptr->observe); } if (coap_header_ptr->options_list_ptr->block1 != -1) { tr_info("Block1 number:\t%" PRId32"", coap_header_ptr->options_list_ptr->block1 >> 4); uint8_t temp = (coap_header_ptr->options_list_ptr->block1 & 0x07); uint16_t block_size = 1u << (temp + 4); tr_info("Block1 size:\t%d", block_size); tr_info("Block1 more:\t%d", (coap_header_ptr->options_list_ptr->block1) & 0x08 ? true : false); } if (coap_header_ptr->options_list_ptr->block2 != -1) { tr_info("Block2 number:\t%" PRId32"", coap_header_ptr->options_list_ptr->block2 >> 4); uint8_t temp = (coap_header_ptr->options_list_ptr->block2 & 0x07); uint16_t block_size = 1u << (temp + 4); tr_info("Block2 size:\t%d", block_size); tr_info("Block2 more:\t%d", (coap_header_ptr->options_list_ptr->block2) & 0x08 ? true : false); } } tr_info("======== End of CoAP package ========"); #else (void) coap_header_ptr; (void) outgoing; #endif } #if MBED_CONF_MBED_TRACE_ENABLE const char *sn_nsdl_coap_status_description(sn_coap_status_e status) { switch(status) { case COAP_STATUS_OK: return "COAP_STATUS_OK"; case COAP_STATUS_PARSER_ERROR_IN_HEADER: return "COAP_STATUS_PARSER_ERROR_IN_HEADER"; case COAP_STATUS_PARSER_DUPLICATED_MSG: return "COAP_STATUS_PARSER_DUPLICATED_MSG"; case COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING: return "COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING"; case COAP_STATUS_PARSER_BLOCKWISE_ACK: return "COAP_STATUS_PARSER_BLOCKWISE_ACK"; case COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED: return "COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED"; case COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED: return "COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED"; case COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED: return "COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED"; default: return ""; } } const char *sn_nsdl_coap_message_code_desc(int msg_code) { switch(msg_code) { case COAP_MSG_CODE_EMPTY: return "COAP_MSG_CODE_EMPTY"; case COAP_MSG_CODE_REQUEST_GET: return "COAP_MSG_CODE_REQUEST_GET"; case COAP_MSG_CODE_REQUEST_POST: return "COAP_MSG_CODE_REQUEST_POST"; case COAP_MSG_CODE_REQUEST_PUT: return "COAP_MSG_CODE_REQUEST_PUT"; case COAP_MSG_CODE_REQUEST_DELETE: return "COAP_MSG_CODE_REQUEST_DELETE"; case COAP_MSG_CODE_RESPONSE_CREATED: return "COAP_MSG_CODE_RESPONSE_CREATED"; case COAP_MSG_CODE_RESPONSE_DELETED: return "COAP_MSG_CODE_RESPONSE_DELETED"; case COAP_MSG_CODE_RESPONSE_VALID: return "COAP_MSG_CODE_RESPONSE_VALID"; case COAP_MSG_CODE_RESPONSE_CHANGED: return "COAP_MSG_CODE_RESPONSE_CHANGED"; case COAP_MSG_CODE_RESPONSE_CONTENT: return "COAP_MSG_CODE_RESPONSE_CONTENT"; case COAP_MSG_CODE_RESPONSE_CONTINUE: return "COAP_MSG_CODE_RESPONSE_CONTINUE"; case COAP_MSG_CODE_RESPONSE_BAD_REQUEST: return "COAP_MSG_CODE_RESPONSE_BAD_REQUEST"; case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED: return "COAP_MSG_CODE_RESPONSE_UNAUTHORIZED"; case COAP_MSG_CODE_RESPONSE_BAD_OPTION: return "COAP_MSG_CODE_RESPONSE_BAD_OPTION"; case COAP_MSG_CODE_RESPONSE_FORBIDDEN: return "COAP_MSG_CODE_RESPONSE_FORBIDDEN"; case COAP_MSG_CODE_RESPONSE_NOT_FOUND: return "COAP_MSG_CODE_RESPONSE_NOT_FOUND"; case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED: return "COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"; case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE: return "COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE"; case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE: return "COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE"; case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED: return "COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED"; case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE: return "COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE"; case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT: return "COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT"; case COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR: return "COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR"; case COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED: return "COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED"; case COAP_MSG_CODE_RESPONSE_BAD_GATEWAY: return "COAP_MSG_CODE_RESPONSE_BAD_GATEWAY"; case COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE: return "COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE"; case COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT: return "COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT"; case COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED: return "COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED"; default: return ""; } } const char *sn_nsdl_coap_message_type_desc(int msg_type) { switch(msg_type) { case COAP_MSG_TYPE_CONFIRMABLE: return "COAP_MSG_TYPE_CONFIRMABLE"; case COAP_MSG_TYPE_NON_CONFIRMABLE: return "COAP_MSG_TYPE_NON_CONFIRMABLE"; case COAP_MSG_TYPE_ACKNOWLEDGEMENT: return "COAP_MSG_TYPE_ACKNOWLEDGEMENT"; case COAP_MSG_TYPE_RESET: return "COAP_MSG_TYPE_RESET"; default: return ""; } } #endif void remove_previous_block_data(struct nsdl_s *handle, sn_nsdl_addr_s *src_ptr, const uint32_t block_number) { #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->grs->coap->linked_list_blockwise_received_payloads) { uint32_t stored_number = stored_payload_info_ptr->block_number; // Remove the previous block data if (block_number - 1 == stored_number) { sn_coap_protocol_block_remove(handle->grs->coap, src_ptr, stored_payload_info_ptr->payload_len, stored_payload_info_ptr->payload_ptr); break; } } #endif } bool update_last_block_data(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, bool block1) { bool data_updated = false; // Whole message received --> pass only the last block data to application if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { // Get the block size uint8_t temp = 0; if (block1) { temp = (coap_packet_ptr->options_list_ptr->block1 & 0x07); } else { temp = (coap_packet_ptr->options_list_ptr->block2 & 0x07); } uint16_t block_size = 1u << (temp + 4); uint32_t new_payload_len = coap_packet_ptr->payload_len - block_size; uint8_t *temp_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); if (temp_ptr) { // Skip the second last block data since it's still stored in mbed-coap list! memcpy(temp_ptr, coap_packet_ptr->payload_ptr + block_size, new_payload_len); handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); coap_packet_ptr->payload_ptr = temp_ptr; coap_packet_ptr->payload_len = new_payload_len; data_updated = true; } } return data_updated; } static void sn_nsdl_add_token(struct nsdl_s *handle, uint32_t *token, sn_coap_hdr_s *message_ptr) { handle->token_seed++; if (handle->token_seed == 0) { handle->token_seed++; } *token = handle->token_seed; message_ptr->token_ptr = (uint8_t*)token; message_ptr->token_len = sizeof(*token); } uint16_t sn_nsdl_get_block_size(const struct nsdl_s *handle) { if (handle == NULL) { return 0; } return handle->grs->coap->sn_coap_block_data_size; } extern uint8_t sn_nsdl_get_retransmission_count(struct nsdl_s *handle) { #if ENABLE_RESENDINGS if (handle == NULL) { return 0; } return handle->grs->coap->sn_coap_resending_count; #else (void) handle; return 0; #endif } int32_t sn_nsdl_send_coap_ping(struct nsdl_s *handle) { assert(handle); assert(handle->grs); sn_coap_hdr_s coap_ping = {0}; int32_t return_msg_id = 0; /* Fill header */ coap_ping.msg_type = COAP_MSG_TYPE_CONFIRMABLE; coap_ping.msg_code = COAP_MSG_CODE_EMPTY; coap_ping.content_format = COAP_CT_NONE; /* Send message */ return_msg_id = sn_nsdl_send_coap_message(handle, &handle->server_address, &coap_ping); if (return_msg_id >= SN_NSDL_SUCCESS) { return_msg_id = coap_ping.msg_id; } return return_msg_id; }