![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Example
Dependencies: FXAS21002 FXOS8700Q
Diff: simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_nsdl.c
- Revision:
- 0:11cc2b7889af
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_nsdl.c Tue Nov 19 09:49:38 2019 +0000 @@ -0,0 +1,2689 @@ +/* + * 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; +}