mbed client on ethernet with LWIP
Dependencies: mbed Socket lwip-eth lwip-sys lwip
Fork of mbed-client-classic-example-lwip by
Diff: mbed-client-c/source/libNsdl/src/sn_nsdl.c
- Revision:
- 11:cada08fc8a70
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-client-c/source/libNsdl/src/sn_nsdl.c Thu Jun 09 17:08:36 2016 +0000 @@ -0,0 +1,2345 @@ +/* + * 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 + * + */ + +#include <string.h> + +#include "ns_types.h" +#include "sn_nsdl.h" +#include "sn_coap_header.h" +#include "sn_coap_protocol.h" +#include "sn_nsdl_lib.h" +#include "sn_grs.h" + +/* Defines */ +#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 OBS_PARAMETER_LEN 3 +#define AOBS_PARAMETER_LEN 8 +#define COAP_CON_PARAMETER_LEN 3 +#define BS_EP_PARAMETER_LEN 3 +#define BS_QUEUE_MODE_PARAMATER_LEN 2 + +#define SN_NSDL_EP_REGISTER_MESSAGE 1 +#define SN_NSDL_EP_UPDATE_MESSAGE 2 + +#define SN_NSDL_MSG_UNDEFINED 0 +#define SN_NSDL_MSG_REGISTER 1 +#define SN_NSDL_MSG_UNREGISTER 2 +#define SN_NSDL_MSG_UPDATE 3 + +/* 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 */ +static uint8_t obs_parameter[] = {'o', 'b', 's'}; /* Observable */ +//static uint8_t aobs_parameter[] = {'a','o','b','s',';','i','d','='}; /* Auto-observable - TBD */ +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 */ +/* * 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 uint16_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description); +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); +static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type); +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); +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(uint8_t value); +static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint8_t value); +static int32_t sn_nsdl_atoi(uint8_t *ptr, uint8_t len); +static uint32_t sn_nsdl_ahextoi(uint8_t *ptr, uint8_t len); +static int8_t sn_nsdl_resolve_lwm2m_address(struct nsdl_s *handle, uint8_t *uri, uint16_t uri_len); +static int8_t sn_nsdl_process_oma_tlv(struct nsdl_s *handle, uint8_t *data_ptr, uint16_t data_len); +static void sn_nsdl_check_oma_bs_status(struct nsdl_s *handle); +static int8_t sn_nsdl_create_oma_device_object_base(struct nsdl_s *handle, sn_nsdl_oma_device_t *oma_device_setup_ptr, sn_nsdl_oma_binding_and_mode_t binding_and_mode); +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); + +int8_t sn_nsdl_destroy(struct nsdl_s *handle) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + if (handle->ep_information_ptr) { + if (handle->ep_information_ptr->endpoint_name_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); + handle->ep_information_ptr->endpoint_name_ptr = 0; + } + 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 = 0; + handle->ep_information_ptr->domain_name_len = 0; + } + if (handle->ep_information_ptr->location_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->location_ptr); + handle->ep_information_ptr->location_ptr = 0; + handle->ep_information_ptr->location_len = 0; + } + if (handle->ep_information_ptr->type_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->type_ptr); + handle->ep_information_ptr->type_ptr = 0; + } + + if (handle->ep_information_ptr->lifetime_ptr) + + { + handle->sn_nsdl_free(handle->ep_information_ptr->lifetime_ptr); + handle->ep_information_ptr->lifetime_ptr = 0; + } + + handle->sn_nsdl_free(handle->ep_information_ptr); + handle->ep_information_ptr = 0; + } + + if (handle->nsp_address_ptr) { + if (handle->nsp_address_ptr->omalw_address_ptr) { + if (handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = 0; + } + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr); + } + + handle->sn_nsdl_free(handle->nsp_address_ptr); + handle->nsp_address_ptr = 0; + } + + if (handle->oma_bs_address_ptr) { + handle->sn_nsdl_free(handle->oma_bs_address_ptr); + } + + /* 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 *)) +{ + /* 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; + + /* 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; + + return handle; +} + +uint16_t sn_nsdl_register_endpoint(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr) +{ + /* Local variables */ + sn_coap_hdr_s *register_message_ptr; + uint16_t message_id = 0; + + if (endpoint_info_ptr == NULL || handle == NULL) { + return 0; + } + + /*** Build endpoint register message ***/ + + /* Allocate memory for header struct */ + register_message_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_hdr_s)); + if (register_message_ptr == NULL) { + return 0; + } + + memset(register_message_ptr, 0, sizeof(sn_coap_hdr_s)); + + /* 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 */ + register_message_ptr->options_list_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_options_list_s)); + if (register_message_ptr->options_list_ptr == NULL) { + handle->sn_nsdl_free(register_message_ptr); + register_message_ptr = 0; + return 0; + } + + memset(register_message_ptr->options_list_ptr, 0, sizeof(sn_coap_options_list_s)); + + 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) ){ + 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; + } + } + + /* Clean (possible) existing and save new endpoint info to handle */ + if (set_endpoint_info(handle, endpoint_info_ptr) == -1) { + if (register_message_ptr->payload_ptr) { + 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; + } + + /* Build and send coap message to NSP */ + message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_REGISTER); + + if (register_message_ptr->payload_ptr) { + 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 message_id; +} + +uint16_t sn_nsdl_unregister_endpoint(struct nsdl_s *handle) +{ + /* Local variables */ + sn_coap_hdr_s *unregister_message_ptr; + uint8_t *temp_ptr = 0; + uint16_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 = handle->sn_nsdl_alloc(sizeof(sn_coap_hdr_s)); + if (!unregister_message_ptr) { + return 0; + } + + memset(unregister_message_ptr, 0, sizeof(sn_coap_hdr_s)); + + /* 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); + } + + /* Send message */ + message_id = sn_nsdl_internal_coap_send(handle, unregister_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_UNREGISTER); + + /* Free memory */ + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); + + } + + return message_id; +} + +uint16_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; + uint16_t message_id = 0; + + /* Check parameters */ + if (handle == NULL) { + return 0; + } + + if (!sn_nsdl_is_ep_registered(handle)){ + return 0; + } + + memset(&temp_parameters, 0, sizeof(sn_nsdl_ep_parameters_s)); + + temp_parameters.lifetime_len = lt_len; + temp_parameters.lifetime_ptr = lt_ptr; + + /*** Build endpoint register update message ***/ + + /* Allocate memory for header struct */ + register_message_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_hdr_s)); + if (register_message_ptr == NULL) { + return 0; + } + + memset(register_message_ptr, 0, sizeof(sn_coap_hdr_s)); + + /* 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 0; + } + + 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 0; + } + + 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 */ + register_message_ptr->options_list_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_options_list_s)); + if (register_message_ptr->options_list_ptr == NULL) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + + memset(register_message_ptr->options_list_ptr, 0, sizeof(sn_coap_options_list_s)); + + /* Fill Uri-query options */ + sn_nsdl_fill_uri_query_options(handle, &temp_parameters, register_message_ptr, SN_NSDL_EP_UPDATE_MESSAGE); + + /* 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 0; + } + } + + /* Build and send coap message to NSP */ + message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_UPDATE); + + if (register_message_ptr->payload_ptr) { + handle->sn_nsdl_free(register_message_ptr->payload_ptr); + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + + 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->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; +} + +uint16_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, + uint8_t *observe_ptr, uint8_t observe_len, + sn_coap_msg_type_e message_type, uint8_t content_type) +{ + sn_coap_hdr_s *notification_message_ptr; + uint16_t return_msg_id = 0; + + /* Check parameters */ + if (handle == NULL) { + return 0; + } + + /* Allocate and initialize memory for header struct */ + notification_message_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_hdr_s)); + if (notification_message_ptr == NULL) { + return 0; + } + + memset(notification_message_ptr, 0, sizeof(sn_coap_hdr_s)); + + notification_message_ptr->options_list_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_options_list_s)); + if (notification_message_ptr->options_list_ptr == NULL) { + handle->sn_nsdl_free(notification_message_ptr); + return 0; + } + + memset(notification_message_ptr->options_list_ptr , 0, sizeof(sn_coap_options_list_s)); + + /* 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_len = observe_len; + notification_message_ptr->options_list_ptr->observe_ptr = observe_ptr; + + /* Fill content type */ + if (content_type) { + notification_message_ptr->content_type_len = 1; + notification_message_ptr->content_type_ptr = &content_type; + } + + /* Send message */ + if (sn_nsdl_send_coap_message(handle, handle->nsp_address_ptr->omalw_address_ptr, notification_message_ptr) == SN_NSDL_FAILURE) { + return_msg_id = 0; + } else { + return_msg_id = notification_message_ptr->msg_id; + } + + /* Free memory */ + + notification_message_ptr->payload_ptr = NULL; + notification_message_ptr->options_list_ptr->observe_ptr = NULL; + notification_message_ptr->token_ptr = NULL; + notification_message_ptr->content_type_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, sn_nsdl_bs_ep_info_t *bootstrap_endpoint_info_ptr) +{ + + /* 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 || !bootstrap_endpoint_info_ptr || !endpoint_info_ptr || !handle) { + return 0; + } + + /* Create device object */ + if (sn_nsdl_create_oma_device_object_base(handle, bootstrap_endpoint_info_ptr->device_object, endpoint_info_ptr->binding_and_mode) < 0) { + return 0; + } + + handle->sn_nsdl_oma_bs_done_cb = bootstrap_endpoint_info_ptr->oma_bs_status_cb; + + /* Init CoAP header struct */ + memset(&bootstrap_coap_header, 0, sizeof(sn_coap_hdr_s)); + + bootstrap_coap_header.options_list_ptr = handle->sn_nsdl_alloc(sizeof(sn_coap_options_list_s)); + if (!bootstrap_coap_header.options_list_ptr) { + return 0; + } + + memset(bootstrap_coap_header.options_list_ptr, 0, sizeof(sn_coap_options_list_s)); + + /* 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); + + uri_query_tmp_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_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); + + bootstrap_coap_header.options_list_ptr->uri_query_len = endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_LEN; + bootstrap_coap_header.options_list_ptr->uri_query_ptr = uri_query_tmp_ptr; + + /* Save bootstrap server address */ + handle->oma_bs_address_len = bootstrap_address_ptr->addr_len; /* Length.. */ + handle->oma_bs_address_ptr = handle->sn_nsdl_alloc(handle->oma_bs_address_len); /* Address.. */ + if (!handle->oma_bs_address_ptr) { + handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); + handle->sn_nsdl_free(uri_query_tmp_ptr); + return 0; + } + memcpy(handle->oma_bs_address_ptr, bootstrap_address_ptr->addr_ptr, handle->oma_bs_address_len); + handle->oma_bs_port = bootstrap_address_ptr->port; /* And port */ + + /* Send message */ + message_id = sn_nsdl_internal_coap_send(handle, &bootstrap_coap_header, bootstrap_address_ptr, SN_NSDL_MSG_UNDEFINED); + + /* Free allocated memory */ + handle->sn_nsdl_free(uri_query_tmp_ptr); + handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); + + return message_id; +} + +omalw_certificate_list_t *sn_nsdl_get_certificates(struct nsdl_s *handle) +{ + sn_nsdl_resource_info_s *resource_ptr = 0;; + omalw_certificate_list_t *certi_list_ptr = 0; + + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + certi_list_ptr = handle->sn_nsdl_alloc(sizeof(omalw_certificate_list_t)); + + if (!certi_list_ptr) { + return NULL; + } + + /* Get private key resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/5"); + if (!resource_ptr) { + handle->sn_nsdl_free(certi_list_ptr); + return NULL; + } + certi_list_ptr->own_private_key_ptr = resource_ptr->resource; + certi_list_ptr->own_private_key_len = resource_ptr->resourcelen; + + /* Get client certificate resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/4"); + if (!resource_ptr) { + handle->sn_nsdl_free(certi_list_ptr); + return NULL; + } + certi_list_ptr->certificate_ptr[0] = resource_ptr->resource; + certi_list_ptr->certificate_len[0] = resource_ptr->resourcelen; + + /* Get root certificate resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/3"); + if (!resource_ptr) { + handle->sn_nsdl_free(certi_list_ptr); + return NULL; + } + certi_list_ptr->certificate_ptr[1] = resource_ptr->resource; + certi_list_ptr->certificate_len[1] = resource_ptr->resourcelen; + + /* return filled list */ + return certi_list_ptr; + +} + +int8_t sn_nsdl_update_certificates(struct nsdl_s *handle, omalw_certificate_list_t *certificate_ptr, uint8_t certificate_chain) +{ + (void)certificate_chain; + + /* Check pointers */ + if (!certificate_ptr || !handle) { + return SN_NSDL_FAILURE; + } + + sn_nsdl_resource_info_s *resource_ptr = 0;; + + /* Get private key resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/5"); + if (!resource_ptr) { + return SN_NSDL_FAILURE; + } + handle->sn_nsdl_free(resource_ptr->resource); + resource_ptr->resource = certificate_ptr->own_private_key_ptr; + resource_ptr->resourcelen = certificate_ptr->own_private_key_len; + + /* Get client certificate resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/4"); + if (!resource_ptr) { + return SN_NSDL_FAILURE; + } + handle->sn_nsdl_free(resource_ptr->resource); + resource_ptr->resource = certificate_ptr->certificate_ptr[0]; + resource_ptr->resourcelen = certificate_ptr->certificate_len[0]; + + /* Get root certificate resource */ + resource_ptr = sn_nsdl_get_resource(handle, 5, (void *)"0/0/3"); + if (!resource_ptr) { + return SN_NSDL_FAILURE; + } + handle->sn_nsdl_free(resource_ptr->resource); + resource_ptr->resource = certificate_ptr->certificate_ptr[1]; + resource_ptr->resourcelen = certificate_ptr->certificate_len[1]; + + return SN_NSDL_SUCCESS; +} + +int8_t sn_nsdl_create_oma_device_object(struct nsdl_s *handle, sn_nsdl_oma_device_t *device_object_ptr) +{ + sn_nsdl_resource_info_s *resource_temp = 0; + uint8_t path[8] = "3/0/11/0"; + + if (!device_object_ptr || !handle) { + return SN_NSDL_FAILURE; + } + + /* * Error code * */ + + /* Get first error message */ + resource_temp = sn_grs_search_resource(handle->grs, 8, path, SN_GRS_SEARCH_METHOD); + + while (resource_temp) { + if (resource_temp->resource) { + /* If no error code set */ + if (*resource_temp->resource == 0) { + /* Set error code */ + *resource_temp->resource = (uint8_t)device_object_ptr->error_code; + resource_temp->resourcelen = 1; + + sn_nsdl_update_resource(handle, resource_temp); + return SN_NSDL_SUCCESS; + } + break; + } + + if (path[7] == '9') { + return SN_NSDL_FAILURE; + } + + path[7]++; + resource_temp = sn_grs_search_resource(handle->grs, 8, path, SN_GRS_SEARCH_METHOD); + } + + /* Create new resource for this error */ + resource_temp = handle->sn_nsdl_alloc(sizeof(sn_nsdl_resource_info_s)); + if (!resource_temp) { + return SN_NSDL_FAILURE; + } + + memset(resource_temp, 0, sizeof(sn_nsdl_resource_info_s)); + + resource_temp->access = SN_GRS_GET_ALLOWED; + resource_temp->mode = SN_GRS_DYNAMIC; + + resource_temp->path = path; + resource_temp->pathlen = 8; + + resource_temp->resource = handle->sn_nsdl_alloc(1); + if (!resource_temp->resource) { + handle->sn_nsdl_free(resource_temp); + return SN_NSDL_FAILURE; + } + + *resource_temp->resource = (uint8_t)device_object_ptr->error_code; + resource_temp->resourcelen = 1; + + resource_temp->resource_parameters_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_resource_parameters_s)); + + if (!resource_temp->resource_parameters_ptr) { + handle->sn_nsdl_free(resource_temp->resource); + handle->sn_nsdl_free(resource_temp); + + return SN_NSDL_FAILURE; + } + + memset(resource_temp->resource_parameters_ptr, 0, sizeof(sn_nsdl_resource_parameters_s)); + + sn_nsdl_create_resource(handle, resource_temp); + + handle->sn_nsdl_free(resource_temp->resource); + handle->sn_nsdl_free(resource_temp->resource_parameters_ptr); + handle->sn_nsdl_free(resource_temp); + + return SN_NSDL_SUCCESS; +} + +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; + + /* 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; + } + + /* 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) { + 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; + } + + /* * If OMA bootstrap message... * */ + if (src_ptr && (handle->oma_bs_address_len == src_ptr->addr_len) && (handle->oma_bs_port == src_ptr->port) && !memcmp(handle->oma_bs_address_ptr, src_ptr->addr_ptr, handle->oma_bs_address_len)) { + /* TLV message. Parse message and check status of the OMA bootstrap */ + /* process. If ok, call cb function and return. Otherwise send error */ + /* and return failure. */ + + if (coap_packet_ptr->content_type_len == 1) { //todo check message type + if (*coap_packet_ptr->content_type_ptr == 99) { + /* TLV parsing failed. Send response to get non-tlv messages */ + if (sn_nsdl_process_oma_tlv(handle, coap_packet_ptr->payload_ptr, coap_packet_ptr->payload_len) == SN_NSDL_FAILURE) { + coap_response_ptr = sn_coap_build_response(handle->grs->coap, coap_packet_ptr, COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE); + 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); + } else { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + } + /* Success TLV parsing */ + else { + coap_response_ptr = sn_coap_build_response(handle->grs->coap, coap_packet_ptr, COAP_MSG_CODE_RESPONSE_CREATED); + 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); + + } else { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + sn_nsdl_check_oma_bs_status(handle); + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } + + /* Non - TLV message */ + else if (*coap_packet_ptr->content_type_ptr == 97) { + sn_grs_process_coap(handle, coap_packet_ptr, src_ptr); + + /* Todo: move this copying to sn_nsdl_check_oma_bs_status(), also from TLV parser */ + /* Security mode */ + if (*(coap_packet_ptr->uri_path_ptr + (coap_packet_ptr->uri_path_len - 1)) == '2') { + handle->nsp_address_ptr->omalw_server_security = (omalw_server_security_t)sn_nsdl_atoi(coap_packet_ptr->payload_ptr, coap_packet_ptr->payload_len); + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + } + + /* NSP address */ + else if (*(coap_packet_ptr->uri_path_ptr + (coap_packet_ptr->uri_path_len - 1)) == '0') { + sn_nsdl_resolve_lwm2m_address(handle, coap_packet_ptr->payload_ptr, coap_packet_ptr->payload_len); + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + } + + sn_nsdl_check_oma_bs_status(handle); + } else { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + } else { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + + + return SN_NSDL_SUCCESS; + } + + + /* * * * * * * * * * * * * * * */ + /* 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_resource_info_s *sn_nsdl_get_resource(struct nsdl_s *handle, uint16_t pathlen, uint8_t *path_ptr) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_search_resource(handle->grs, pathlen, path_ptr, SN_GRS_SEARCH_METHOD); +} + + +/** + * \fn static uint16_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description) + * + * + * \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 uint16_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description) +{ + uint8_t *coap_message_ptr = NULL; + uint16_t coap_message_len = 0; + + coap_message_len = sn_coap_builder_calc_needed_packet_data_size(coap_header_ptr); + + 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 */ + if (sn_coap_protocol_build(handle->grs->coap, dst_addr_ptr, coap_message_ptr, coap_header_ptr, (void *)handle) < 0) { + handle->sn_nsdl_free(coap_message_ptr); + return 0; + } + + /* If mesage type is confirmable, save it to list to wait for reply */ + if (coap_header_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + if (message_description == SN_NSDL_MSG_REGISTER) { + handle->register_msg_id = coap_header_ptr->msg_id; + } + if (message_description == SN_NSDL_MSG_UNREGISTER) { + handle->unregister_msg_id = coap_header_ptr->msg_id; + } + + } + + 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) +{ + /* Local variables */ + if (!handle->nsp_address_ptr) { + //allocate only if previously not allocated + handle->nsp_address_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_oma_server_info_t)); + } + + if (handle->nsp_address_ptr) { + handle->nsp_address_ptr->omalw_server_security = SEC_NOT_SET; + handle->nsp_address_ptr->omalw_address_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_addr_s)); + if (handle->nsp_address_ptr->omalw_address_ptr) { + memset(handle->nsp_address_ptr->omalw_address_ptr, 0, sizeof(sn_nsdl_addr_s)); + handle->nsp_address_ptr->omalw_address_ptr->type = SN_NSDL_ADDRESS_TYPE_NONE; + } + } +} + +static int8_t sn_nsdl_create_oma_device_object_base(struct nsdl_s *handle, sn_nsdl_oma_device_t *oma_device_setup_ptr, sn_nsdl_oma_binding_and_mode_t binding_and_mode) +{ + sn_nsdl_resource_info_s new_resource; + uint8_t object_path[8] = "3/0/11/0"; + uint8_t resource_temp[3]; + uint8_t x = 0; + + if (!oma_device_setup_ptr) { + return SN_NSDL_FAILURE; + } + + /* * Create resources. * */ + + /* These resources can be created multiple times. */ + memset(&new_resource, 0, sizeof(sn_nsdl_resource_info_s)); + new_resource.resource_parameters_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_resource_parameters_s)); + if (!new_resource.resource_parameters_ptr) { + return SN_NSDL_FAILURE; + } + + memset(new_resource.resource_parameters_ptr, 0, sizeof(sn_nsdl_resource_parameters_s)); + + /* Create error - resource */ + new_resource.mode = SN_GRS_STATIC; + new_resource.access = SN_GRS_GET_ALLOWED; + + new_resource.path = object_path; + new_resource.pathlen = 8; + + sn_nsdl_itoa(resource_temp, (uint8_t)oma_device_setup_ptr->error_code); + + new_resource.resource = resource_temp; + new_resource.resourcelen = 1; + + if (sn_nsdl_create_resource(handle, &new_resource) != SN_NSDL_SUCCESS) { + handle->sn_nsdl_free(new_resource.resource_parameters_ptr); + return SN_NSDL_FAILURE; + } + + /* These resources can be only once, during OMA bootstrap.. */ + /* Create supported binding and modes */ + object_path[5] = '6'; + new_resource.path = object_path; + new_resource.pathlen = 6; + + if (binding_and_mode & 0x01) { + resource_temp[x] = 'U'; + x++; + if (binding_and_mode & 0x02) { + resource_temp[x] = 'Q'; + x++; + } + } + if (binding_and_mode & 0x04) { + resource_temp[x] = 'S'; + x++; + if ((binding_and_mode & 0x02) && !(binding_and_mode & 0x01)) { + resource_temp[x] = 'Q'; + x++; + } + } + + new_resource.resourcelen = x; + + if (new_resource.resourcelen) { + new_resource.resource = resource_temp; + } else { + new_resource.resource = 0; + } + + + if (sn_nsdl_create_resource(handle, &new_resource) != SN_NSDL_SUCCESS) { + handle->sn_nsdl_free(new_resource.resource_parameters_ptr); + return SN_NSDL_FAILURE; + } + + + /* Create dynamic reboot object */ + new_resource.mode = SN_GRS_DYNAMIC; + + new_resource.access = SN_GRS_POST_ALLOWED; + + object_path[4] = '4'; + + new_resource.path = object_path; + new_resource.pathlen = 5; + + new_resource.resourcelen = 0; + new_resource.resource = 0; + + new_resource.sn_grs_dyn_res_callback = oma_device_setup_ptr->sn_oma_device_boot_callback; + + if (sn_nsdl_create_resource(handle, &new_resource) != SN_NSDL_SUCCESS) { + handle->sn_nsdl_free(new_resource.resource_parameters_ptr); + return SN_NSDL_FAILURE; + } + + handle->sn_nsdl_free(new_resource.resource_parameters_ptr); + return SN_NSDL_SUCCESS; +} + +/** + * \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) +{ + /* Local variables */ + uint8_t *temp_ptr; + const sn_nsdl_resource_info_s *resource_temp_ptr; + + + /* Calculate needed memory and allocate */ + message_ptr->payload_len = sn_nsdl_calculate_registration_body_size(handle, updating_registeration); + + /* If no resources to be registered, return SN_NSDL_SUCCESS */ + if (!message_ptr->payload_len) { + return SN_NSDL_SUCCESS; + } + + 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->resource_parameters_ptr) { + if (updating_registeration && resource_temp_ptr->resource_parameters_ptr->registered == SN_NDSL_RESOURCE_REGISTERED) { + resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); + continue; + } else { + resource_temp_ptr->resource_parameters_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++ = '/'; + memcpy(temp_ptr, resource_temp_ptr->path, resource_temp_ptr->pathlen); + temp_ptr += resource_temp_ptr->pathlen; + *temp_ptr++ = '>'; + + /* Resource attributes */ + if (resource_temp_ptr->resource_parameters_ptr->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->resource_parameters_ptr->resource_type_ptr, resource_temp_ptr->resource_parameters_ptr->resource_type_len); + temp_ptr += resource_temp_ptr->resource_parameters_ptr->resource_type_len; + *temp_ptr++ = '"'; + } + + if (resource_temp_ptr->resource_parameters_ptr->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->resource_parameters_ptr->interface_description_ptr, resource_temp_ptr->resource_parameters_ptr->interface_description_len); + temp_ptr += resource_temp_ptr->resource_parameters_ptr->interface_description_len; + *temp_ptr++ = '"'; + } + + if (resource_temp_ptr->resource_parameters_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->resource_parameters_ptr->coap_content_type); + *temp_ptr++ = '"'; + } + + /* ;obs */ + if (resource_temp_ptr->resource_parameters_ptr->observable) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, obs_parameter, OBS_PARAMETER_LEN); + temp_ptr += OBS_PARAMETER_LEN; + } + + /* ;aobs;id= */ + /* todo: aosb not supported ATM */ + /* + if((resource_temp_ptr->resource_parameters_ptr->auto_obs_len > 0 && resource_temp_ptr->resource_parameters_ptr->auto_obs_len <= 8) && + resource_temp_ptr->resource_parameters_ptr->auto_obs_ptr) + { + uint8_t i = 0; + + *temp_ptr++ = ';'; + memcpy(temp_ptr, aobs_parameter, AOBS_PARAMETER_LEN); + temp_ptr += AOBS_PARAMETER_LEN; + + while(i < resource_temp_ptr->resource_parameters_ptr->auto_obs_len) + { + temp_ptr = sn_nsdl_itoa(temp_ptr, *(resource_temp_ptr->resource_parameters_ptr->auto_obs_ptr + i)); + i++; + } + } + */ + + } + + 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) + * + * + * \brief Calculates registration message payload size + * \param *handle Pointer to nsdl-library handle + * \param *grs_resources_list_ptr Pointer to list of GRS resources + * + * \return Needed payload size + */ +static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration) +{ + /* Local variables */ + uint16_t return_value = 0; + const sn_nsdl_resource_info_s *resource_temp_ptr; + + /* check pointer */ + + resource_temp_ptr = sn_grs_get_first_resource(handle->grs); + + while (resource_temp_ptr) { + if (resource_temp_ptr->resource_parameters_ptr) { + if (updating_registeration && resource_temp_ptr->resource_parameters_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) { + return_value++; + } + + /* Count length for the resource path </path> */ + return_value += (3 + resource_temp_ptr->pathlen); + + /* Count lengths of the attributes */ + + /* Resource type parameter */ + if (resource_temp_ptr->resource_parameters_ptr->resource_type_len) { + /* ;rt="restype" */ + return_value += (6 + resource_temp_ptr->resource_parameters_ptr->resource_type_len); + } + + /* Interface description parameter */ + if (resource_temp_ptr->resource_parameters_ptr->interface_description_len) { + /* ;if="iftype" */ + return_value += (6 + resource_temp_ptr->resource_parameters_ptr->interface_description_len); + } + + if (resource_temp_ptr->resource_parameters_ptr->coap_content_type != 0) { + /* ;if="content" */ + return_value += 6; // all but not content + return_value += sn_nsdl_itoa_len(resource_temp_ptr->resource_parameters_ptr->coap_content_type); + } + + if (resource_temp_ptr->resource_parameters_ptr->observable) { + /* ;obs */ + return_value += 4; + } + /*todo: aobs not supported ATM */ + /* + if((resource_temp_ptr->resource_parameters_ptr->auto_obs_len > 0 && resource_temp_ptr->resource_parameters_ptr->auto_obs_len <= 8) && + resource_temp_ptr->resource_parameters_ptr->auto_obs_ptr) + { + uint8_t i = resource_temp_ptr->resource_parameters_ptr->auto_obs_len; + // ;aobs;id= + return_value += 9; + while(i--) + { + return_value += sn_nsdl_itoa_len(*(resource_temp_ptr->resource_parameters_ptr->auto_obs_ptr + i)); + } + } + */ + + } + + 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) +{ + uint8_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) && (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_PARAMATER_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); + } + + 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) +{ + uint8_t *temp_ptr = NULL; + if( !validateParameters(parameter_ptr) ){ + return SN_NSDL_FAILURE; + } + source_msg_ptr->options_list_ptr->uri_query_len = sn_nsdl_calculate_uri_query_option_len(parameter_ptr, msg_type); + if (source_msg_ptr->options_list_ptr->uri_query_len == 0) { + return 0; + } + + source_msg_ptr->options_list_ptr->uri_query_ptr = handle->sn_nsdl_alloc(source_msg_ptr->options_list_ptr->uri_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)) { + 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_PARAMATER_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'; + } + } + } + + 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( int 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; + } + + if (coap_packet_ptr->msg_id == handle->register_msg_id) { + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CREATED) { + handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_IS_REGISTERED; + sn_grs_mark_resources_as_registered(handle); + if (sn_nsdl_resolve_ep_information(handle, coap_packet_ptr) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + + handle->register_msg_id = 0; + } + } + + if (coap_packet_ptr->msg_id == handle->unregister_msg_id) { + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_DELETED) { + if (handle->ep_information_ptr->endpoint_name_ptr) { + 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; + } + 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 = 0; + handle->ep_information_ptr->domain_name_len = 0; + } + + handle->unregister_msg_id = 0; + } + } + + /* No messages to wait for, or message was not response to our request */ + return handle->sn_nsdl_rx_callback(handle, coap_packet_ptr, address_ptr); +} + +/** + * \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; +} + +int8_t set_NSP_address(struct nsdl_s *handle, uint8_t *NSP_address, uint16_t port, sn_nsdl_addr_type_e address_type) +{ + + /* Check parameters and source pointers */ + if (!handle || !handle->nsp_address_ptr || !handle->nsp_address_ptr->omalw_address_ptr || !NSP_address) { + return SN_NSDL_FAILURE; + } + + handle->nsp_address_ptr->omalw_address_ptr->type = address_type; + handle->nsp_address_ptr->omalw_server_security = SEC_NOT_SET; + + if (address_type == SN_NSDL_ADDRESS_TYPE_IPV4) { + if (handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + } + + handle->nsp_address_ptr->omalw_address_ptr->addr_len = 4; + + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(handle->nsp_address_ptr->omalw_address_ptr->addr_len); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + memcpy(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr, NSP_address, handle->nsp_address_ptr->omalw_address_ptr->addr_len); + handle->nsp_address_ptr->omalw_address_ptr->port = port; + } + + else if (address_type == SN_NSDL_ADDRESS_TYPE_IPV6) { + if (handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + } + + handle->nsp_address_ptr->omalw_address_ptr->addr_len = 16; + + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(handle->nsp_address_ptr->omalw_address_ptr->addr_len); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + memcpy(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr, NSP_address, handle->nsp_address_ptr->omalw_address_ptr->addr_len); + handle->nsp_address_ptr->omalw_address_ptr->port = port; + } + return SN_NSDL_SUCCESS; +} + + +static uint8_t sn_nsdl_itoa_len(uint8_t value) +{ + uint8_t i = 0; + + do { + i++; + } while ((value /= 10) > 0); + + return i; +} + +static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint8_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 int32_t sn_nsdl_atoi(uint8_t *ptr, uint8_t len) +{ + + int32_t result = 0; + + while (len--) { + + if (result) { + result *= 10; + } + + if (*ptr >= '0' && *ptr <= '9') { + result += *ptr - '0'; + } else{ + return -1; + } + + ptr++; + + } + return result; + +} + +static uint32_t sn_nsdl_ahextoi(uint8_t *ptr, uint8_t len) +{ + + uint32_t result = 0; + + while (len--) { + + if (result) { + result *= 16; + } + + if (*ptr >= '0' && *ptr <= '9') { + result += *ptr - '0'; + } else if (*ptr >= 'a' && *ptr <= 'f') { + result += *ptr - 87; + } else if (*ptr >= 'A' && *ptr <= 'F') { + result += *ptr - 55; + } + + ptr++; + + } + return result; + +} + +static int8_t sn_nsdl_resolve_lwm2m_address(struct nsdl_s *handle, uint8_t *uri, uint16_t uri_len) +{ + if( uri_len < 2 ){ + return SN_NSDL_FAILURE; + } + uint8_t *temp_ptr = uri+2; + uint16_t i = 0; + uint8_t char_cnt = 0; + + /* jump over coap// */ + while ((*(temp_ptr - 2) != '/') || (*(temp_ptr - 1) != '/')) { + temp_ptr++; + if (temp_ptr - uri >= uri_len) { + return SN_NSDL_FAILURE; + } + } + + /* Resolve address type */ + /* Count semicolons */ + + int8_t endPos = -1; + + while (i < (uri_len - (temp_ptr - uri))) { + if (*(temp_ptr + i) == ':') { + char_cnt++; + }else if(*(temp_ptr + i) == ']'){ + endPos = i; + } + i++; + } + + uint8_t *temp_pos = temp_ptr; //store starting point in case of IPv4 parsing fails + + /* IPv6 */ + if (char_cnt > 2) { + i = 0; + + if( handle->nsp_address_ptr->omalw_address_ptr->addr_ptr ){ + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + } + + handle->nsp_address_ptr->omalw_address_ptr->type = SN_NSDL_ADDRESS_TYPE_IPV6; + handle->nsp_address_ptr->omalw_address_ptr->addr_len = 16; + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(16); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + memset(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr, 0, 16); + if (*temp_ptr == '[' && endPos > 0 && (temp_ptr - uri) + endPos < uri_len && *(temp_ptr + endPos + 1) == ':') { + temp_ptr++; + endPos--; + }else{ + /* return failure, because port is mandatory */ + return SN_NSDL_FAILURE; + } + + int8_t loopbackPos = -1; + if( char_cnt != 8 ){ + i = 0; + char_cnt -= 1; + while( i+1 < endPos ){ + if(*(temp_ptr + i) == ':' && *(temp_ptr + i+1) == ':') { + loopbackPos = i; + break; + } + i++; + } + } + i = 0; + + uint8_t numberOfZeros = 8 - char_cnt; + if(loopbackPos == 0){ + numberOfZeros++; + } + + if(loopbackPos == endPos-2){ + numberOfZeros++; + } + + /* Resolve address */ + int8_t pos = loopbackPos == 0?0:-1; + while (i < 16 && ((temp_ptr - uri) + char_cnt) < uri_len) { + char_cnt = 0; + if( pos == loopbackPos ){ + for( int k=0; k < numberOfZeros; k++ ){ + i+=2; + } + pos+=2; + temp_ptr += 2; + if( numberOfZeros == 8 ){ + temp_ptr++; + } + continue; + } + while (*(temp_ptr + char_cnt) != ':' && *(temp_ptr + char_cnt) != ']') { + char_cnt++; + pos++; + } + pos++; + + if (char_cnt <= 2) { + i++; + } + + while (char_cnt) { + if (char_cnt % 2) { + *(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr + i) = (uint8_t)sn_nsdl_ahextoi(temp_ptr, 1); + temp_ptr++; + char_cnt --; + } else { + *(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr + i) = (uint8_t)sn_nsdl_ahextoi(temp_ptr, 2); + temp_ptr += 2; + char_cnt -= 2; + } + i++; + } + temp_ptr++; + } + + temp_ptr++; + uint16_t handled = (temp_ptr - uri); + if( handled < uri_len ){ + if( *(temp_ptr + (uri_len - (temp_ptr - uri) -1)) == '/' ){ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri) - 1); + }else{ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri)); + } + } + } + /* IPv4 or Hostname */ + else if (char_cnt == 1) { + char_cnt = 0; + i = 0; + + if( handle->nsp_address_ptr->omalw_address_ptr->addr_ptr ){ + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + } + + /* Check address type */ + while (i < (uri_len - (temp_ptr - uri))) { + if (*(temp_ptr + i) == '.') { + char_cnt++; + } + i++; + } + + bool parseOk = true; + + /* Try IPv4 first */ + if (char_cnt == 3) { + i = 0; + char_cnt = 0; + + handle->nsp_address_ptr->omalw_address_ptr->type = SN_NSDL_ADDRESS_TYPE_IPV4; + handle->nsp_address_ptr->omalw_address_ptr->addr_len = 4; + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(4); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + while (parseOk && ((temp_ptr - uri) < uri_len) && *(temp_ptr - 1) != ':') { + i++; + + if (*(temp_ptr + i) == ':' || *(temp_ptr + i) == '.') { + int8_t value = (int8_t)sn_nsdl_atoi(temp_ptr, i); + if( value == -1 ){ + parseOk = false; + char_cnt = 3; + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = NULL; + break; + } + *(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr + char_cnt) = value; + temp_ptr = temp_ptr + i + 1; + char_cnt++; + i = 0; + } + } + if(parseOk) { + if( *(temp_ptr + (uri_len - (temp_ptr - uri) -1)) == '/' ){ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri) - 1); + }else{ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri)); + } + } + }else{ + parseOk = false; + } + + /* Then try Hostname */ + if(!parseOk) { + i = 0; + temp_ptr = temp_pos; + + handle->nsp_address_ptr->omalw_address_ptr->type = SN_NSDL_ADDRESS_TYPE_HOSTNAME; + + /* Resolve address length */ + if (uri_len > 0xff) { + return SN_NSDL_FAILURE; + } + + while (((temp_ptr - uri) + i < uri_len) && *(temp_ptr + i) != ':') { + i++; + } + + handle->nsp_address_ptr->omalw_address_ptr->addr_len = i; + + /* Copy address */ + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(i); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + memcpy(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr, temp_ptr, i); + + temp_ptr += i + 1; + + /* Set port */ + if( *(temp_ptr + (uri_len - (temp_ptr - uri) - 1)) == '/' ){ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri) - 1); + }else{ + handle->nsp_address_ptr->omalw_address_ptr->port = sn_nsdl_atoi(temp_ptr, uri_len - (temp_ptr - uri)); + } + } + } else { + return SN_NSDL_FAILURE; + } + + return SN_NSDL_SUCCESS; +} + + +int8_t sn_nsdl_process_oma_tlv(struct nsdl_s *handle, uint8_t *data_ptr, uint16_t data_len) +{ + uint8_t *temp_ptr = data_ptr; + uint8_t type = 0; + uint16_t identifier = 0; + uint32_t length = 0; + uint8_t path_temp[5] = "0/0/x"; + + sn_nsdl_resource_info_s resource_temp = { + .resource_parameters_ptr = 0, + .mode = SN_GRS_STATIC, + .pathlen = 5, + .path = path_temp, + .resourcelen = 0, + .resource = 0, + .access = (sn_grs_resource_acl_e) 0x0f, /* All allowed */ + .sn_grs_dyn_res_callback = 0 + }; + + while ((temp_ptr - data_ptr) < data_len) { + /* Save type for future use */ + type = *temp_ptr++; + + /* * Bit 5: Indicates the Length of the Identifier. * */ + if (type & 0x20) { + /* 1=The Identifier field of this TLV is 16 bits long */ + identifier = (uint8_t)(*temp_ptr++) << 8; + identifier += (uint8_t) * temp_ptr++; + } else { + /* 0=The Identifier field of this TLV is 8 bits long */ + identifier = (uint8_t) * temp_ptr++; + } + + /* * Bit 4-3: Indicates the type of Length. * */ + if ((type & 0x18) == 0) { + /* 00 = No length field, the value immediately follows the Identifier field in is of the length indicated by Bits 2-0 of this field */ + length = (type & 0x07); + } else if ((type & 0x18) == 0x08) { + /* 01 = The Length field is 8-bits and Bits 2-0 MUST be ignored */ + length = *temp_ptr++; + } else if ((type & 0x18) == 0x10) { + /* 10 = The Length field is 16-bits and Bits 2-0 MUST be ignored */ + length = (uint8_t)(*temp_ptr++) << 8; + length += (uint8_t) * temp_ptr++; + } else if ((type & 0x18) == 0x18) { + /* 11 = The Length field is 24-bits and Bits 2-0 MUST be ignored */ + length = (uint8_t)(*temp_ptr++); + length = length << 16; + length += (uint8_t)(*temp_ptr++) << 8; + length += (uint8_t) * temp_ptr++; + } + + /* * Bits 7-6: Indicates the type of Identifier. * */ + if ((type & 0xC0) == 0x00) { + /* 00 = Object Instance in which case the Value contains one or more Resource TLVs */ + /* Not implemented, return failure */ + } else if ((type & 0xC0) == 0xC0) { + /* 11 = Resource with Value */ + switch (identifier) { + case 0: + /* Resolve LWM2M Server URI */ + sn_nsdl_resolve_lwm2m_address(handle, temp_ptr, length); + path_temp[4] = '0'; + resource_temp.resource = temp_ptr; + resource_temp.resourcelen = length; + if (sn_nsdl_create_resource(handle, &resource_temp) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + break; + case 2: + /* Resolve security Mode */ + handle->nsp_address_ptr->omalw_server_security = (omalw_server_security_t)sn_nsdl_atoi(temp_ptr, length); + path_temp[4] = '2'; + resource_temp.resource = temp_ptr; + resource_temp.resourcelen = length; + if (sn_nsdl_create_resource(handle, &resource_temp) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + + break; + case 3: + /* Public Key or Identity */ + path_temp[4] = '3'; + resource_temp.resource = temp_ptr; + resource_temp.resourcelen = length; + if (sn_nsdl_create_resource(handle, &resource_temp) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + break; + case 4: + /* Server Public Key or Identity */ + ; + path_temp[4] = '4'; + resource_temp.resource = temp_ptr; + resource_temp.resourcelen = length; + if (sn_nsdl_create_resource(handle, &resource_temp) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + + break; + case 5: + /* Secret Key */ + path_temp[4] = '5'; + resource_temp.resource = temp_ptr; + resource_temp.resourcelen = length; + if (sn_nsdl_create_resource(handle, &resource_temp) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + break; + default: + break; + } + + /* Move pointer to next TLV message */ + temp_ptr += length; + } + } + + return SN_NSDL_SUCCESS; +} + +static void sn_nsdl_check_oma_bs_status(struct nsdl_s *handle) +{ + /* Check OMA BS status */ + if ((handle->nsp_address_ptr->omalw_server_security == PSK) && (handle->nsp_address_ptr->omalw_address_ptr->type != SN_NSDL_ADDRESS_TYPE_NONE)) { + /* call cb that oma bootstrap is done */ + if(handle->sn_nsdl_oma_bs_done_cb != 0){ + handle->sn_nsdl_oma_bs_done_cb(handle->nsp_address_ptr); + } + } else if ((handle->nsp_address_ptr->omalw_server_security == CERTIFICATE) && (handle->nsp_address_ptr->omalw_address_ptr->type != SN_NSDL_ADDRESS_TYPE_NONE) && + ((sn_nsdl_get_resource(handle, 5, (void *)"0/0/5") != 0) && + (sn_nsdl_get_resource(handle, 5, (void *)"0/0/4") != 0) && + (sn_nsdl_get_resource(handle, 5, (void *)"0/0/3") != 0))) { + if( handle->sn_nsdl_oma_bs_done_cb ){ + handle->sn_nsdl_oma_bs_done_cb(handle->nsp_address_ptr); + } + } +} + +static int8_t set_endpoint_info(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_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 = 0; + handle->ep_information_ptr->domain_name_len = 0; + } + + if (handle->ep_information_ptr->endpoint_name_ptr) { + 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; + } + + 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) { + 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 = 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; + } + + 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; + + handle->ep_information_ptr->location_ptr = 0; + handle->ep_information_ptr->location_len = 0; + + return 0; +} + +/* Wrapper */ +sn_grs_resource_list_s *sn_nsdl_list_resource(struct nsdl_s *handle, uint16_t pathlen, uint8_t *path) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_list_resource(handle->grs, pathlen, path); +} + +void sn_nsdl_free_resource_list(struct nsdl_s *handle, sn_grs_resource_list_s *list) +{ + /* Check parameters */ + if (handle == NULL) { + return; + } + + sn_grs_free_resource_list(handle->grs, list); +} + +extern int8_t sn_nsdl_update_resource(struct nsdl_s *handle, sn_nsdl_resource_info_s *res) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return sn_grs_update_resource(handle->grs, res); +} + +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; + } + + return sn_grs_send_coap_message(handle, address_ptr, coap_hdr_ptr); +} + +extern int8_t sn_nsdl_create_resource(struct nsdl_s *handle, sn_nsdl_resource_info_s *res) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return sn_grs_create_resource(handle->grs, res); +} + +extern int8_t sn_nsdl_delete_resource(struct nsdl_s *handle, uint16_t pathlen, uint8_t *path) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return sn_grs_delete_resource(handle->grs, pathlen, path); +} +extern const sn_nsdl_resource_info_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_resource_info_s *sn_nsdl_get_next_resource(struct nsdl_s *handle, const sn_nsdl_resource_info_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 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); +} +