hello

Dependents:   nespresso_demo nespresso_endpoint EnvoyNespressoEndpointColorDetectorV2

Fork of nsdl by Robert Taylor

Revision:
0:f6e4e1bbb3fe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sn_grs.c	Wed Jun 04 15:38:26 2014 +0000
@@ -0,0 +1,1461 @@
+/**
+ *
+ * \file sn_grs.c
+ * \brief General resource server for Sensinode NanoService platforms
+ *
+ *
+ *
+ */
+#include "nsdl_types.h"
+#include "sn_linked_list.h"
+#include "sn_nsdl.h"
+
+#if(SN_NSDL_HAVE_HTTPS_CAPABILITY&&SN_NSDL_HAVE_HTTP_CAPABILITY)
+#include "sn_http.h"
+#endif
+
+#if(SN_NSDL_HAVE_COAP_CAPABILITY)
+#include "sn_coap_header.h"
+#include "sn_coap_protocol.h"
+#endif
+
+#include "sn_nsdl_lib.h"
+#include "sn_grs.h"
+
+#include <stdlib.h>
+#include <string.h>			// for memcomp
+
+/* Defines */
+#define WELLKNOWN_PATH_LEN				16
+#define WELLKNOWN_PATH					(".well-known/core")
+
+/* Local static function prototypes */
+static sn_nsdl_resource_info_s *	sn_grs_search_resource				(uint16_t pathlen, uint8_t *path, uint8_t search_method);
+static int8_t 						sn_grs_resource_info_free			(sn_nsdl_resource_info_s *resource_ptr);
+static uint8_t *					sn_grs_convert_uri					(uint16_t *uri_len, uint8_t *uri_ptr);
+static int8_t 						sn_grs_add_resource_to_list			(sn_linked_list_t *list_ptr, sn_nsdl_resource_info_s *resource_ptr);
+#ifdef CC8051_PLAT
+void 								copy_code_nsdl						(uint8_t * ptr, prog_uint8_t * code_ptr, uint16_t len);
+#endif
+static uint8_t 						sn_grs_compare_code					(uint8_t * ptr, prog_uint8_t * code_ptr, uint8_t len);
+
+/* Extern function prototypes */
+extern int8_t 						sn_nsdl_build_registration_body		(sn_coap_hdr_s *message_ptr, uint8_t updating_registeration);
+
+
+/* Local global variables */
+SN_MEM_ATTR_GRS_DECL static sn_linked_list_t *resource_root_list = NULL;
+
+
+/* Local global function pointers */
+static void 	*(*sn_grs_alloc)(uint16_t);
+static void 	(*sn_grs_free)(void*);
+static uint8_t (*sn_grs_tx_callback)(sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *);
+static int8_t (*sn_grs_rx_callback)(sn_coap_hdr_s *, sn_nsdl_addr_s *);
+
+/**
+ * \fn int8_t sn_grs_destroy(void)
+ * \brief This function may be used to flush GRS related stuff when a program exits.
+ * @return always 0.
+ */
+SN_MEM_ATTR_GRS_FUNC extern int8_t sn_grs_destroy(void)
+{
+	if(resource_root_list)
+	{
+		uint16_t size =  sn_linked_list_count_nodes(resource_root_list);
+		uint16_t i = 0;
+		sn_nsdl_resource_info_s*tmp;
+
+		for(i=0;i<size;i++)
+		{
+			tmp = sn_linked_list_get_first_node(resource_root_list);
+
+			if(tmp)
+			{
+				if(tmp->resource_parameters_ptr->resource_type_ptr)
+				{
+					sn_grs_free(tmp->resource_parameters_ptr->resource_type_ptr);
+					tmp->resource_parameters_ptr->resource_type_ptr = 0;
+				}
+
+				if(tmp->resource_parameters_ptr->interface_description_ptr)
+				{
+					sn_grs_free(tmp->resource_parameters_ptr->interface_description_ptr);
+					tmp->resource_parameters_ptr->interface_description_ptr = 0;
+				}
+
+				if(tmp->resource_parameters_ptr)
+				{
+					sn_grs_free(tmp->resource_parameters_ptr);
+					tmp->resource_parameters_ptr = 0;
+				}
+				if(tmp->path)
+				{
+					sn_grs_free(tmp->path);
+					tmp->path = 0;
+				}
+				if(tmp->resource)
+				{
+					sn_grs_free(tmp->resource);
+					tmp->resource = 0;
+				}
+				sn_linked_list_remove_current_node(resource_root_list);
+				sn_grs_free(tmp);
+				tmp = 0;
+			}
+		}
+
+		if(!sn_linked_list_count_nodes(resource_root_list))
+		{
+			sn_linked_list_free(resource_root_list);
+		}
+
+	}
+	return 0;
+}
+
+
+/**
+ * \fn int8_t sn_grs_init	(uint8_t (*sn_grs_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t,
+ *		sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *), sn_nsdl_mem_s *sn_memory)
+ *
+ * \brief GRS library initialize function.
+ *
+ * This function initializes GRS and CoAP libraries.
+ *
+ * \param 	sn_grs_tx_callback 		A function pointer to a transmit callback function.
+ * \param  *sn_grs_rx_callback_ptr A function pointer to a receiving callback function. If received packet is not for GRS, it will be passed to
+ *									upper level (NSDL) to be proceed.
+ * \param 	sn_memory 				A pointer to a structure containing the platform specific functions for memory allocation and free.
+ *
+ * \return success = 0, failure = -1
+ *
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_init	(uint8_t (*sn_grs_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t,
+		sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *), sn_nsdl_mem_s *sn_memory)
+{
+	/* If application tries to init GRS more than once.. */
+	if(!resource_root_list)
+	{
+		/* if sn_memory struct is NULL or , return failure */
+		if(!sn_memory)
+			return SN_NSDL_FAILURE;
+
+		if (sn_memory->sn_nsdl_alloc == NULL ||
+			sn_memory->sn_nsdl_free == NULL ||
+			sn_grs_tx_callback_ptr == NULL)
+		{
+			/* There was a null pointer as a parameter */
+			return SN_NSDL_FAILURE;
+		}
+
+		/* Alloc and free - function pointers  */
+		sn_grs_alloc = sn_memory->sn_nsdl_alloc;
+		sn_grs_free = sn_memory->sn_nsdl_free;
+
+		/* TX callback function pointer */
+		sn_grs_tx_callback = sn_grs_tx_callback_ptr;
+		sn_grs_rx_callback = sn_grs_rx_callback_ptr;
+
+		/* Initialize linked list */
+		sn_linked_list_init(sn_memory->sn_nsdl_alloc, sn_memory->sn_nsdl_free);
+
+		/* Initialize HTTP protocol library, if implemented to library*/
+#if	(SN_NSDL_HAVE_HTTP_CAPABILITY || SN_NSDL_HAVE_HTTPS_CAPABILITY)
+		sn_http_init(sn_memory->sn_nsdl_alloc, sn_memory->sn_grs_free);
+#endif
+
+		/* Initialize CoAP protocol library, if implemented to library */
+
+		/* Initialize list for resources */
+		resource_root_list = sn_linked_list_create();
+		if (!resource_root_list)
+		{
+			return SN_NSDL_FAILURE;
+		}
+
+#if	SN_NSDL_HAVE_COAP_CAPABILITY
+		sn_coap_builder_and_parser_init(sn_memory->sn_nsdl_alloc, sn_memory->sn_nsdl_free);
+
+		if(sn_coap_protocol_init(sn_memory->sn_nsdl_alloc, sn_memory->sn_nsdl_free, sn_grs_tx_callback, sn_grs_rx_callback))
+		{
+			sn_linked_list_free(resource_root_list);
+			return SN_NSDL_FAILURE;
+		}
+#endif
+
+		return SN_NSDL_SUCCESS;
+	}
+
+	return SN_NSDL_FAILURE;
+}
+
+/**
+ * \fn extern int8_t sn_grs_exec(uint32_t time)
+ *
+ * \brief CoAP retransmission function.
+ *
+ *	Used to give execution time for the GRS (CoAP) library for retransmissions. The GRS library
+ *	will call the exec functions of all enabled protocol modules.
+ *
+ *	\param 	time	Time in seconds.
+ *
+ *	\return  0 = success, -1 = failure
+ *
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_exec(uint32_t time)
+{
+#if(SN_NSDL_HAVE_COAP_CAPABILITY)
+	/* Call CoAP execution function */
+	return sn_coap_protocol_exec(time);
+#endif
+	return SN_NSDL_SUCCESS;
+}
+
+/**
+ * \fn extern sn_grs_resource_list_s *sn_grs_list_resource(uint16_t pathlen, uint8_t *path)
+ *
+ * \brief Resource list function
+ *
+ * \param pathlen	Contains the length of the target path (excluding possible trailing '\0').
+ *					The length value is not examined if the path itself is a NULL pointer.
+ *
+ * \param *path		A pointer to an array containing the path or a NULL pointer.
+ *
+ * \return !NULL 	A pointer to a sn_grs_resource_list structure containing the resource listing.\n
+ *          NULL 	failure with an unspecified error
+ */
+SN_MEM_ATTR_GRS_FUNC
+extern sn_grs_resource_list_s *sn_grs_list_resource(uint16_t pathlen, uint8_t *path)
+{
+	/* Local variables */
+	uint8_t i = 0;
+	sn_grs_resource_list_s 	*grs_resource_list_ptr 	= NULL;
+	sn_nsdl_resource_info_s 	*grs_resource_ptr 		= NULL;
+
+	/* Allocate memory for the resource list to be filled */
+	grs_resource_list_ptr = (sn_grs_resource_list_s *)sn_grs_alloc(sizeof(sn_grs_resource_list_s));
+	if(!grs_resource_list_ptr)
+	{
+		return (sn_grs_resource_list_s *)NULL;
+	}
+
+	/* Count resources to the resource list struct */
+	grs_resource_list_ptr->res_count = sn_linked_list_count_nodes(resource_root_list);
+
+	/**************************************/
+	/* Fill resource structs to the table */
+	/**************************************/
+
+	/* If resources in list */
+	if(grs_resource_list_ptr->res_count)
+	{
+		/* Allocate memory for resources */
+		grs_resource_list_ptr->res = sn_grs_alloc(grs_resource_list_ptr->res_count*(sizeof(sn_grs_resource_s)));
+		if(!grs_resource_list_ptr->res)
+		{
+			sn_grs_free(grs_resource_list_ptr);
+			return (sn_grs_resource_list_s *)NULL;
+		}
+
+		/* Get first resource */
+		grs_resource_ptr = sn_linked_list_get_first_node(resource_root_list);
+
+		for(i = 0; i < grs_resource_list_ptr->res_count; i++)
+		{
+			/* Copy pathlen to resource list */
+			grs_resource_list_ptr->res[i].pathlen = grs_resource_ptr->pathlen;
+
+			/* Allocate memory for path string */
+			grs_resource_list_ptr->res[i].path = sn_grs_alloc(grs_resource_list_ptr->res[i].pathlen);
+			if(!grs_resource_list_ptr->res[i].path)
+				//todo: free struct
+				return (sn_grs_resource_list_s *)NULL;
+
+			/* Move pathstring to resource list */
+			memmove(grs_resource_list_ptr->res[i].path,grs_resource_ptr->path, grs_resource_ptr->pathlen);
+
+			/* move to next node */
+			grs_resource_ptr = sn_linked_list_get_next_node(resource_root_list);
+		}
+	}
+	return grs_resource_list_ptr;
+}
+
+SN_MEM_ATTR_GRS_FUNC
+extern sn_nsdl_resource_info_s *sn_grs_get_first_resource(void)
+{
+
+	return sn_linked_list_get_first_node(resource_root_list);
+
+}
+
+SN_MEM_ATTR_GRS_FUNC
+extern sn_nsdl_resource_info_s *sn_grs_get_next_resource(void)
+{
+
+	return sn_linked_list_get_next_node(resource_root_list);
+
+}
+
+/**
+ * \fn extern sn_grs_resource_info_s *sn_grs_get_resource(uint16_t pathlen, uint8_t *path)
+ *
+ * \brief Resource get function.
+ *
+ *	Used to get a resource.
+ *
+ *	\param pathlen	Contains the length of the path that is to be returned (excluding possible trailing '\\0').
+ *
+ *	\param *path	A pointer to an array containing the path.
+ *
+ *	\return 		!NULL success, pointer to a sn_grs_resource_info_t that contains the resource information\n
+ *					NULL failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern sn_nsdl_resource_info_s *sn_grs_get_resource(uint16_t pathlen, uint8_t *path)
+{
+
+	/* Search for resource */
+	return sn_grs_search_resource(pathlen, path, SN_GRS_SEARCH_METHOD);
+
+}
+
+
+
+/**
+ * \fn 	extern int8_t sn_grs_delete_resource(uint16_t pathlen, uint8_t *path_ptr)
+ *
+ * \brief Resource delete function.
+ *
+ *	Used to delete a resource. If resource has a subresources, these all must also be removed.
+ *
+ *	\param 	pathlen		Contains the length of the path that is to be deleted (excluding possible trailing �\0�).
+ *
+ *	\param 	*path_ptr	A pointer to an array containing the path.
+ *
+ *	\return 		0 = success, -1 = failure (No such resource)
+*/
+
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_delete_resource(uint16_t pathlen, uint8_t *path_ptr)
+{
+	/* Local variables */
+	sn_nsdl_resource_info_s 	*resource_temp 	= NULL;
+
+	/* Search if resource found */
+	resource_temp = sn_grs_search_resource(pathlen, path_ptr, SN_GRS_SEARCH_METHOD);
+
+	/* If not found */
+	if(resource_temp == (sn_nsdl_resource_info_s *)NULL)
+		return SN_NSDL_FAILURE;
+
+	/* If found, delete it and delete also subresources, if there is any */
+	while (resource_temp != (sn_nsdl_resource_info_s *)NULL)
+	{
+		/* Remove from list */
+		resource_temp = (sn_nsdl_resource_info_s *)sn_linked_list_remove_current_node(resource_root_list);
+
+		/* Free */
+		sn_grs_resource_info_free(resource_temp);
+
+		/* Search for subresources */
+		resource_temp = sn_grs_search_resource(pathlen, path_ptr, SN_GRS_DELETE_METHOD);
+	}
+	return SN_NSDL_SUCCESS;
+}
+
+
+
+/**
+ * \fn 	extern int8_t sn_grs_update_resource(sn_grs_resource_info_s *res)
+ *
+ * \brief Resource updating function.
+ *
+ *	Used to update the direct value of a static resource, the callback function pointer of a dynamic resource
+ *	and access rights of the recource.
+ *
+ *	\param 	*res	Pointer to a structure of type sn_grs_resource_info_t that contains the information
+ *					about the resource. Only the pathlen and path elements are evaluated along with
+ *					either resourcelen and resource or the function pointer.
+ *
+ *	\return			0 = success, -1 = failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_update_resource(sn_nsdl_resource_info_s *res)
+{
+	/* Local variables */
+	sn_nsdl_resource_info_s 	*resource_temp 	= NULL;
+
+	/* Search resource */
+	resource_temp = sn_grs_search_resource(res->pathlen, res->path, SN_GRS_SEARCH_METHOD);
+	if(!resource_temp)
+		return SN_NSDL_FAILURE;
+
+	/* If there is payload on resource, free it */
+	if(resource_temp->resource != NULL)
+	{
+		sn_grs_free(resource_temp->resource);
+		resource_temp->resource = 0;
+	}
+	/* Update resource len */
+	resource_temp->resourcelen = res->resourcelen;
+
+	/* If resource len >0, allocate memory and copy payload */
+	if(res->resourcelen)
+	{
+		resource_temp->resource = sn_grs_alloc(res->resourcelen);
+		if(resource_temp->resource == NULL)
+		{
+
+			resource_temp->resourcelen = 0;
+			return SN_NSDL_FAILURE;
+
+		}
+
+		memcpy(resource_temp->resource, res->resource, resource_temp->resourcelen);
+	}
+
+	/* Update access rights and callback address */
+	resource_temp->access = res->access;
+	resource_temp->sn_grs_dyn_res_callback = res->sn_grs_dyn_res_callback;
+
+	/* TODO: resource_parameters_ptr not copied */
+
+	return SN_NSDL_SUCCESS;
+}
+
+
+
+/**
+ * \fn 	extern int8_t sn_grs_create_resource(sn_grs_resource_info_t *res)
+ *
+ * \brief Resource creating function.
+ *
+ *	Used to create a static or dynamic HTTP(S) or CoAP resource.
+ *
+ *	\param 	*res	Pointer to a structure of type sn_grs_resource_info_t that contains the information
+ *					about the resource.
+ *
+ *	\return 		 0 success
+ *					-1 Failure
+ *					-2 Resource already exists
+ *					-3 Invalid path
+ *					-4 List adding failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_create_resource(sn_nsdl_resource_info_s *res)
+{
+
+	if(!res)
+		return SN_NSDL_FAILURE;
+
+	/* Check path validity */
+	if(!res->pathlen || !res->path)
+		return SN_GRS_INVALID_PATH;
+
+	/* Check if resource already exists */
+	if(sn_grs_search_resource(res->pathlen, res->path, SN_GRS_SEARCH_METHOD) != (sn_nsdl_resource_info_s *)NULL)
+	{
+		return SN_GRS_RESOURCE_ALREADY_EXISTS;
+	}
+
+	if(res->resource_parameters_ptr)
+	{
+		res->resource_parameters_ptr->registered = SN_NDSL_RESOURCE_NOT_REGISTERED;
+	}
+
+	/* Create resource */
+	if(sn_grs_add_resource_to_list(resource_root_list, res) == SN_NSDL_SUCCESS)
+	{
+		return SN_NSDL_SUCCESS;
+	}
+	return SN_GRS_LIST_ADDING_FAILURE;
+}
+
+
+
+/**
+ * \fn 	extern int8_t sn_grs_process_http(uint8_t *packet, uint16_t *packet_len, sn_grs_addr_t *src)
+ *
+ * \brief To push HTTP packet to GRS library
+ *
+ *	Used to push an HTTP or unencrypted HTTPS packet to GRS library for processing.
+ *
+ *	\param 	*packet		Pointer to a uint8_t array containing the packet (including the HTTP headers).
+ *						After SN_NSDL_SUCCESSful execution this array may contain the response packet.
+ *
+ *	\param 	*packet_len	Pointer to length of the packet. After successful execution this array may
+ *						contain the length of the response packet.
+ *
+ *	\param 	*src		Pointer to packet source address information. After SN_NSDL_SUCCESSful execution
+ *						this array may contain the destination address of the response packet.
+ *
+ *	\return				1 success, response packet to be sent.
+ *						0 success, no response to be sent
+ *						-1 failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_process_http(uint8_t *packet, uint16_t *packet_len, sn_nsdl_addr_s *src)
+{
+#if(SN_NSDL_HAVE_HTTP_CAPABILITY && SN_NSDL_HAVE_HTTPS_CAPABILITY)
+	/* Local variables */
+	sn_http_hdr_t 	*http_packet_ptr 	= NULL;
+	int8_t 			status 				= 0;
+
+	/******************************************/
+	/* Parse HTTP packet and check if succeed */
+	/******************************************/
+	http_packet_ptr = sn_http_parse(*packet_len, packet);
+	if(!http_packet_ptr)
+		return SN_NSDL_FAILURE;
+
+	if(http_packet_ptr->status != SN_HTTP_STATUS_OK)
+		return SN_NSDL_FAILURE;			// Todo: other SN_NSDL_FAILUREs from HTTP
+
+	switch (http_packet_ptr->method)
+	{
+	case (SN_GRS_POST):
+		return status;
+
+	case (SN_GRS_PUT):
+		return status;
+
+	case (SN_GRS_GET):
+		return status;
+
+	case (SN_GRS_DELETE):
+		return status;
+
+	default:
+		return SN_NSDL_FAILURE;
+	}
+#endif
+	return SN_NSDL_FAILURE;
+}
+
+
+
+/**
+ * \fn 	extern int8_t sn_grs_process_coap(uint8_t *packet, uint16_t *packet_len, sn_nsdl_addr_s *src)
+ *
+ * \brief To push CoAP packet to GRS library
+ *
+ *	Used to push an CoAP packet to GRS library for processing.
+ *
+ *	\param 	*packet		Pointer to a uint8_t array containing the packet (including the CoAP headers).
+ *						After successful execution this array may contain the response packet.
+ *
+ *	\param 	*packet_len	Pointer to length of the packet. After successful execution this array may contain the length
+ *						of the response packet.
+ *
+ *	\param 	*src		Pointer to packet source address information. After successful execution this array may contain
+ *						the destination address of the response packet.
+ *
+ *	\return				0 = success, -1 = failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int8_t sn_grs_process_coap(uint8_t *packet, uint16_t packet_len, sn_nsdl_addr_s *src_addr_ptr)
+{
+	sn_coap_hdr_s 			*coap_packet_ptr 	= NULL;
+	sn_nsdl_resource_info_s	*resource_temp_ptr	= NULL;
+	sn_coap_msg_code_e 		status 				= COAP_MSG_CODE_EMPTY;
+	sn_coap_hdr_s 			*response_message_hdr_ptr = NULL;
+
+
+	/* Parse CoAP packet */
+	coap_packet_ptr = sn_coap_protocol_parse(src_addr_ptr, packet_len, packet);
+
+	/* 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(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)
+		{
+			status = COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED;
+		}
+
+	}
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * */
+	/* If message is response message, call RX callback  */
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	if((coap_packet_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE && status == COAP_MSG_CODE_EMPTY) ||
+			(coap_packet_ptr->msg_type == COAP_MSG_TYPE_ACKNOWLEDGEMENT && status == COAP_MSG_CODE_EMPTY))
+	{
+		int8_t retval = sn_grs_rx_callback(coap_packet_ptr, src_addr_ptr);
+		if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+		{
+			sn_grs_free(coap_packet_ptr->payload_ptr);
+			coap_packet_ptr->payload_ptr = 0;
+		}
+		sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+		return retval;
+	}
+
+	/* * * * * * * * * * * * * * * */
+	/* Other messages are for GRS  */
+	/* * * * * * * * * * * * * * * */
+
+	else if(coap_packet_ptr->msg_code <= COAP_MSG_CODE_REQUEST_DELETE && status == COAP_MSG_CODE_EMPTY)
+	{
+		/* Check if .well-known/core */
+		if(coap_packet_ptr->uri_path_len == WELLKNOWN_PATH_LEN && sn_grs_compare_code(coap_packet_ptr->uri_path_ptr, (const uint8_t*)WELLKNOWN_PATH, WELLKNOWN_PATH_LEN) == 0)
+		{
+
+			sn_coap_content_format_e wellknown_content_format = COAP_CT_LINK_FORMAT;
+
+			/* Allocate resopnse message  */
+			response_message_hdr_ptr = sn_grs_alloc(sizeof(sn_coap_hdr_s));
+			if(!response_message_hdr_ptr)
+			{
+				if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+				{
+					sn_grs_free(coap_packet_ptr->payload_ptr);
+					coap_packet_ptr->payload_ptr = 0;
+				}
+				sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+				return SN_NSDL_FAILURE;
+			}
+			memset(response_message_hdr_ptr, 0, sizeof(sn_coap_hdr_s));
+
+			/* Build response */
+			response_message_hdr_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
+			response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT;
+			response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id;
+			response_message_hdr_ptr->content_type_len = 1;
+			response_message_hdr_ptr->content_type_ptr = malloc(1);
+			if(!response_message_hdr_ptr)
+			{
+				if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+				{
+					sn_grs_free(coap_packet_ptr->payload_ptr);
+					coap_packet_ptr->payload_ptr = 0;
+				}
+				sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+				sn_grs_free(response_message_hdr_ptr);
+				return SN_NSDL_FAILURE;
+			}
+
+			*response_message_hdr_ptr->content_type_ptr = wellknown_content_format;
+
+
+			sn_nsdl_build_registration_body(response_message_hdr_ptr, 0);
+
+			/* Send and free */
+			sn_grs_send_coap_message(src_addr_ptr, response_message_hdr_ptr);
+
+			if(response_message_hdr_ptr->payload_ptr)
+			{
+				sn_grs_free(response_message_hdr_ptr->payload_ptr);
+				response_message_hdr_ptr->payload_ptr = 0;
+			}
+			sn_coap_parser_release_allocated_coap_msg_mem(response_message_hdr_ptr);
+
+			/* Free parsed CoAP message */
+			if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+			{
+				sn_grs_free(coap_packet_ptr->payload_ptr);
+				coap_packet_ptr->payload_ptr = 0;
+			}
+			sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+
+			return SN_NSDL_SUCCESS;
+		}
+
+		/* Get resource */
+		resource_temp_ptr = sn_grs_get_resource(coap_packet_ptr->uri_path_len, coap_packet_ptr->uri_path_ptr);
+
+		/* * * * * * * * * * * */
+		/* If resource exists  */
+		/* * * * * * * * * * * */
+		if(resource_temp_ptr)
+		{
+			/* If dynamic resource, go to callback */
+			if(resource_temp_ptr->mode == SN_GRS_DYNAMIC)
+			{
+				/* Check accesses */
+				if(((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) && !(resource_temp_ptr->access & SN_GRS_GET_ALLOWED)) 			||
+						((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) && !(resource_temp_ptr->access & SN_GRS_POST_ALLOWED)) 	||
+						((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) && !(resource_temp_ptr->access & SN_GRS_PUT_ALLOWED))   	||
+						((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) && !(resource_temp_ptr->access & SN_GRS_DELETE_ALLOWED)))
+				{
+
+					status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
+				}
+				else
+				{
+					resource_temp_ptr->sn_grs_dyn_res_callback(coap_packet_ptr, src_addr_ptr,0);
+					if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+					{
+						sn_grs_free(coap_packet_ptr->payload_ptr);
+						coap_packet_ptr->payload_ptr = 0;
+					}
+					sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+					return SN_NSDL_SUCCESS;
+				}
+			}
+			else
+			{
+				/* Static resource handling */
+				switch (coap_packet_ptr->msg_code )
+				{
+				case (COAP_MSG_CODE_REQUEST_GET):
+					if(resource_temp_ptr->access & SN_GRS_GET_ALLOWED)
+					{
+						status = COAP_MSG_CODE_RESPONSE_CONTENT;
+					}
+					else
+						status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
+					break;
+				case (COAP_MSG_CODE_REQUEST_POST):
+					if(resource_temp_ptr->access & SN_GRS_POST_ALLOWED)
+					{
+						resource_temp_ptr->resourcelen = coap_packet_ptr->payload_len;
+						sn_grs_free(resource_temp_ptr->resource);
+						resource_temp_ptr->resource = 0;
+						if(resource_temp_ptr->resourcelen)
+						{
+							resource_temp_ptr->resource = sn_grs_alloc(resource_temp_ptr->resourcelen);
+							if(!resource_temp_ptr->resource)
+							{
+								status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+								break;
+							}
+							memcpy(resource_temp_ptr->resource, coap_packet_ptr->payload_ptr, resource_temp_ptr->resourcelen);
+						}
+						if(coap_packet_ptr->content_type_ptr)
+						{
+							if(resource_temp_ptr->resource_parameters_ptr)
+							{
+								resource_temp_ptr->resource_parameters_ptr->coap_content_type = *coap_packet_ptr->content_type_ptr;
+							}
+						}
+						status = COAP_MSG_CODE_RESPONSE_CHANGED;
+					}
+					else
+						status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
+					break;
+				case (COAP_MSG_CODE_REQUEST_PUT):
+					if(resource_temp_ptr->access & SN_GRS_PUT_ALLOWED)
+					{
+						resource_temp_ptr->resourcelen = coap_packet_ptr->payload_len;
+						sn_grs_free(resource_temp_ptr->resource);
+						resource_temp_ptr->resource = 0;
+						if(resource_temp_ptr->resourcelen)
+						{
+							resource_temp_ptr->resource = sn_grs_alloc(resource_temp_ptr->resourcelen);
+							if(!resource_temp_ptr->resource)
+							{
+								status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+								break;
+							}
+							memcpy(resource_temp_ptr->resource, coap_packet_ptr->payload_ptr, resource_temp_ptr->resourcelen);
+						}
+						if(coap_packet_ptr->content_type_ptr)
+						{
+							if(resource_temp_ptr->resource_parameters_ptr)
+							{
+								resource_temp_ptr->resource_parameters_ptr->coap_content_type = *coap_packet_ptr->content_type_ptr;
+							}
+						}
+						status = COAP_MSG_CODE_RESPONSE_CHANGED;
+					}
+					else
+						status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
+					break;
+
+				case (COAP_MSG_CODE_REQUEST_DELETE):
+					if(resource_temp_ptr->access & SN_GRS_DELETE_ALLOWED)
+					{
+						if(sn_grs_delete_resource(coap_packet_ptr->uri_path_len, coap_packet_ptr->uri_path_ptr) == SN_NSDL_SUCCESS)
+							status = COAP_MSG_CODE_RESPONSE_DELETED;
+						else
+							status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+					}
+					else
+						status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
+					break;
+
+				default:
+					status = COAP_MSG_CODE_RESPONSE_FORBIDDEN;
+					break;
+				}
+			}
+		}
+
+		/* * * * * * * * * * * * * * */
+		/* If resource was not found */
+		/* * * * * * * * * * * * * * */
+
+		else
+		{
+			if(coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST ||
+					coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT)
+			{
+				resource_temp_ptr = sn_grs_alloc(sizeof(sn_nsdl_resource_info_s));
+				if(!resource_temp_ptr)
+				{
+					status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+				}
+				else
+				{
+					memset(resource_temp_ptr, 0, sizeof(sn_nsdl_resource_info_s));
+
+					resource_temp_ptr->access = (sn_grs_resource_acl_e)SN_GRS_DEFAULT_ACCESS;
+					resource_temp_ptr->mode = SN_GRS_STATIC;
+
+					resource_temp_ptr->pathlen = coap_packet_ptr->uri_path_len;
+					resource_temp_ptr->path = sn_grs_alloc(resource_temp_ptr->pathlen);
+					if(!resource_temp_ptr->path)
+					{
+						sn_grs_free(resource_temp_ptr);
+						resource_temp_ptr =  0;
+						status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+					}
+					else
+					{
+						memcpy(resource_temp_ptr->path, coap_packet_ptr->uri_path_ptr, resource_temp_ptr->pathlen);
+
+						resource_temp_ptr->resourcelen = coap_packet_ptr->payload_len;
+						resource_temp_ptr->resource = sn_grs_alloc(resource_temp_ptr->resourcelen);
+						if(!resource_temp_ptr->resource)
+						{
+							sn_grs_free(resource_temp_ptr->path);
+							resource_temp_ptr->path = 0;
+							sn_grs_free(resource_temp_ptr);
+							resource_temp_ptr = 0;
+							status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+						}
+						else
+						{
+
+							memcpy(resource_temp_ptr->resource, coap_packet_ptr->payload_ptr, resource_temp_ptr->resourcelen);
+
+							if(sn_linked_list_add_node(resource_root_list, resource_temp_ptr) == SN_LINKED_LIST_ERROR_NO_ERROR)
+							{
+								if(coap_packet_ptr->content_type_ptr)
+								{
+									if(resource_temp_ptr->resource_parameters_ptr)
+									{
+										resource_temp_ptr->resource_parameters_ptr->coap_content_type = *coap_packet_ptr->content_type_ptr;
+									}
+								}
+								status = COAP_MSG_CODE_RESPONSE_CREATED;
+							}
+							else
+							{
+								sn_grs_free(resource_temp_ptr->path);
+								resource_temp_ptr->path = 0;
+
+								sn_grs_free(resource_temp_ptr->resource);
+								resource_temp_ptr->resource = 0;
+
+								sn_grs_free(resource_temp_ptr);
+								resource_temp_ptr = 0;
+
+								status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+			else
+				status = COAP_MSG_CODE_RESPONSE_NOT_FOUND;
+		}
+
+	}
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	/* If received packed was other than reset, create response  */
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	if(coap_packet_ptr->msg_type != COAP_MSG_TYPE_RESET && coap_packet_ptr->msg_type != COAP_MSG_TYPE_ACKNOWLEDGEMENT)
+	{
+
+		/* Allocate resopnse message  */
+		response_message_hdr_ptr = sn_grs_alloc(sizeof(sn_coap_hdr_s));
+		if(!response_message_hdr_ptr)
+		{
+			if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+			{
+				sn_grs_free(coap_packet_ptr->payload_ptr);
+				coap_packet_ptr->payload_ptr = 0;
+			}
+			sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+			return SN_NSDL_FAILURE;
+		}
+		memset(response_message_hdr_ptr, 0, sizeof(sn_coap_hdr_s));
+
+		/* If status has not been defined, response internal server error */
+		if(status == COAP_MSG_CODE_EMPTY)
+			status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
+
+		/* Fill header */
+		response_message_hdr_ptr->msg_code = status;
+
+		if(coap_packet_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE)
+			response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT;
+		else
+			response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE;
+
+		response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id;
+
+		if(coap_packet_ptr->token_ptr)
+		{
+			response_message_hdr_ptr->token_len = coap_packet_ptr->token_len;
+			response_message_hdr_ptr->token_ptr = sn_grs_alloc(response_message_hdr_ptr->token_len);
+			if(!response_message_hdr_ptr->token_ptr)
+			{
+				if(response_message_hdr_ptr->payload_ptr)
+				{
+					sn_grs_free(response_message_hdr_ptr->payload_ptr);
+					response_message_hdr_ptr->payload_ptr = 0;
+				}
+				sn_coap_parser_release_allocated_coap_msg_mem(response_message_hdr_ptr);
+
+				if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+				{
+					sn_grs_free(coap_packet_ptr->payload_ptr);
+					coap_packet_ptr->payload_ptr = 0;
+				}
+
+				sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+				return SN_NSDL_FAILURE;
+			}
+			memcpy(response_message_hdr_ptr->token_ptr, coap_packet_ptr->token_ptr, response_message_hdr_ptr->token_len);
+		}
+
+		if(status == COAP_MSG_CODE_RESPONSE_CONTENT)
+		{
+			/* Add content type if other than default */
+			if(resource_temp_ptr->resource_parameters_ptr)
+			{
+				if(resource_temp_ptr->resource_parameters_ptr->coap_content_type != 0)
+				{
+					response_message_hdr_ptr->content_type_len = 1;
+					response_message_hdr_ptr->content_type_ptr = sn_grs_alloc(response_message_hdr_ptr->content_type_len);
+					if(!response_message_hdr_ptr->content_type_ptr)
+					{
+						sn_coap_parser_release_allocated_coap_msg_mem(response_message_hdr_ptr);
+
+						if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+						{
+							sn_grs_free(coap_packet_ptr->payload_ptr);
+							coap_packet_ptr->payload_ptr = 0;
+						}
+
+						sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+						return SN_NSDL_FAILURE;
+					}
+					memcpy(response_message_hdr_ptr->content_type_ptr, &resource_temp_ptr->resource_parameters_ptr->coap_content_type, response_message_hdr_ptr->content_type_len);
+				}
+			}
+
+			/* Add payload */
+			response_message_hdr_ptr->payload_len = resource_temp_ptr->resourcelen;
+			response_message_hdr_ptr->payload_ptr = sn_grs_alloc(response_message_hdr_ptr->payload_len);
+
+			if(!response_message_hdr_ptr->payload_ptr)
+			{
+				sn_coap_parser_release_allocated_coap_msg_mem(response_message_hdr_ptr);
+
+				if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+				{
+					sn_grs_free(coap_packet_ptr->payload_ptr);
+					coap_packet_ptr->payload_ptr = 0;
+				}
+
+				sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+				return SN_NSDL_FAILURE;
+			}
+
+			memcpy(response_message_hdr_ptr->payload_ptr, resource_temp_ptr->resource, response_message_hdr_ptr->payload_len);
+		}
+
+		sn_grs_send_coap_message(src_addr_ptr, response_message_hdr_ptr);
+
+		if(response_message_hdr_ptr->payload_ptr)
+		{
+			sn_grs_free(response_message_hdr_ptr->payload_ptr);
+			response_message_hdr_ptr->payload_ptr = 0;
+		}
+		sn_coap_parser_release_allocated_coap_msg_mem(response_message_hdr_ptr);
+	}
+
+	/* Free parsed CoAP message */
+	if(coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr)
+	{
+		sn_grs_free(coap_packet_ptr->payload_ptr);
+		coap_packet_ptr->payload_ptr = 0;
+	}
+	sn_coap_parser_release_allocated_coap_msg_mem(coap_packet_ptr);
+
+
+	return SN_NSDL_SUCCESS;
+}
+
+
+
+
+/**
+ * \fn 	extern int16_t sn_grs_get_capability(void)
+ *
+ * \brief Capability query function.
+ *
+ *	Used to retrieve the list of supported protocols from the GRS module.
+ *
+ *	\return				>0 success, supported capabilities reported using bitmask with definitions from sn_grs_capab_t\n
+ *						0 success, no supported capabilities\n
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern int16_t sn_grs_get_capability(void)
+{
+	int16_t capabilities = 0;
+	if(SN_NSDL_HAVE_HTTP_CAPABILITY)
+		capabilities |= 0x01;
+
+	if(SN_NSDL_HAVE_HTTPS_CAPABILITY)
+		capabilities |= 0x02;
+
+	if(SN_NSDL_HAVE_COAP_CAPABILITY)
+		capabilities |= 0x04;
+
+	return capabilities;
+}
+
+
+/**
+ * \fn 	extern uint32_t sn_grs_get_version(void)
+ *
+ * \brief Version query function.
+ *
+ *	Used to retrieve the version information structure from the GRS library.
+ *
+ *	\return 		!0 MSB 2 bytes major version, LSB 2 bytes minor version.
+ *					0 failure
+*/
+SN_MEM_ATTR_GRS_FUNC
+extern uint32_t sn_grs_get_version(void)
+{
+	return SN_GRS_VERSION;
+}
+
+/**
+ * \fn 	extern int8_t sn_grs_send_coap_message(sn_nsdl_addr_s * address_ptr, sn_coap_hdr_s *coap_hdr_ptr)
+ *
+ * \brief Sends CoAP message
+ *
+ *	Sends CoAP message
+ *
+ *	\param  *coap_hdr_ptr	Pointer to CoAP message to be sent
+ *
+ *	\param 	*address_ptr	Pointer to source address struct
+ *
+ *	\return	0 = success, -1 = failed
+ *
+*/
+extern int8_t sn_grs_send_coap_message(sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr)
+{
+	uint8_t 	*message_ptr = NULL;
+	uint16_t 	message_len	= 0;
+	uint8_t		ret_val = 0;
+
+	/* Calculate message length */
+	message_len = sn_coap_builder_calc_needed_packet_data_size(coap_hdr_ptr);
+
+	/* Allocate memory for message and check was allocating successfully */
+	message_ptr = sn_grs_alloc(message_len);
+	if(message_ptr == NULL)
+		return SN_NSDL_FAILURE;
+
+	/* Build CoAP message */
+	if(sn_coap_protocol_build(address_ptr, message_ptr, coap_hdr_ptr) < 0)
+	{
+		sn_grs_free(message_ptr);
+		message_ptr = 0;
+		return SN_NSDL_FAILURE;
+	}
+
+	/* Call tx callback function to send message */
+	ret_val = sn_grs_tx_callback(SN_NSDL_PROTOCOL_COAP, message_ptr, message_len, address_ptr);
+
+	/* Free allocated memory */
+	sn_grs_free(message_ptr);
+	message_ptr = 0;
+
+	if(ret_val == 0)
+		return SN_NSDL_FAILURE;
+	else
+		return SN_NSDL_SUCCESS;
+}
+
+/**
+ * \fn 	static sn_grs_resource_info_s *sn_grs_search_resource(uint16_t pathlen, uint8_t *path, uint8_t search_method)
+ *
+ * \brief Searches given resource from linked list
+ *
+ *	Search either precise path, or subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc...
+ *
+ *	\param  pathlen			Length of the path to be search
+ *
+ *	\param 	*path			Pointer to the path string to be search
+ *
+ *	\param 	search_method	Search method, SEARCH or DELETE
+ *
+ *	\return					Pointer to the resource. If resource not found, return value is NULL
+ *
+*/
+SN_MEM_ATTR_GRS_FUNC
+static sn_nsdl_resource_info_s *sn_grs_search_resource(uint16_t pathlen, uint8_t *path, uint8_t search_method)
+{
+	/* Local variables */
+	sn_nsdl_resource_info_s 	*resource_search_temp 	= NULL;
+	uint8_t 					*path_temp_ptr 			= NULL;
+
+	/* Check parameters */
+	if(!pathlen || !path)
+	{
+		return (sn_nsdl_resource_info_s *)NULL;;
+	}
+
+	/* Remove '/' - marks from the end and beginning */
+	path_temp_ptr = sn_grs_convert_uri(&pathlen, path);
+
+	resource_search_temp = sn_linked_list_get_first_node(resource_root_list);
+
+	/* Searchs exact path */
+	if(search_method == SN_GRS_SEARCH_METHOD)
+	{
+		/* Scan all nodes on list */
+		while(resource_search_temp)
+		{
+			/* If length equals.. */
+			if(resource_search_temp->pathlen == pathlen)
+			{
+				/* Compare paths, If same return node pointer*/
+				if(0 == memcmp(resource_search_temp->path, path_temp_ptr, pathlen))
+					return resource_search_temp;
+			}
+			/* If that was not what we needed, get next node.. */
+			resource_search_temp = sn_linked_list_get_next_node(resource_root_list);
+		}
+	}
+
+	/* Search also subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc... */
+	else if(search_method == SN_GRS_DELETE_METHOD)
+	{
+		/* Scan all nodes on list */
+		while(resource_search_temp)
+		{
+			uint8_t *temp_ptr = resource_search_temp->path;
+
+			/* If found, return pointer */
+			if((*(temp_ptr+(uint8_t)pathlen) == '/')
+					&& !memcmp(resource_search_temp->path, path_temp_ptr, pathlen))
+				return resource_search_temp;
+
+			/* else get next node */
+			resource_search_temp = sn_linked_list_get_next_node(resource_root_list);
+		}
+	}
+
+	/* If there was not nodes we wanted, return NULL */
+	return (sn_nsdl_resource_info_s *)NULL;
+}
+
+
+/**
+ * \fn 	static int8_t sn_grs_add_resource_to_list(sn_linked_list_t *list_ptr, sn_grs_resource_info_s *resource_ptr)
+ *
+ * \brief Adds given resource to resource list
+ *
+ *	\param  *list_ptr			Length of the path to be search
+ *
+ *	\param 	*resource_ptr			Pointer to the path string to be search
+ *
+ *	\return	0 = SN_NSDL_SUCCESS, -1 = SN_NSDL_FAILURE
+ *
+*/
+SN_MEM_ATTR_GRS_FUNC
+static int8_t sn_grs_add_resource_to_list(sn_linked_list_t *list_ptr, sn_nsdl_resource_info_s *resource_ptr)
+{
+	/* Local variables */
+	int8_t status = 0;
+	uint8_t *path_start_ptr = NULL;
+	uint16_t path_len = 0;
+	sn_nsdl_resource_info_s *resource_copy_ptr = NULL;
+
+		/* Allocate memory for the resource info copy */
+	if(!resource_ptr->pathlen)
+	{
+		return SN_NSDL_FAILURE;
+	}
+	resource_copy_ptr = sn_grs_alloc(sizeof(sn_nsdl_resource_info_s));
+	if(resource_copy_ptr == (sn_nsdl_resource_info_s*)NULL)
+	{
+		return SN_NSDL_FAILURE;
+	}
+
+	/* Set everything to zero  */
+	memset(resource_copy_ptr, 0, sizeof(sn_nsdl_resource_info_s));
+
+	resource_copy_ptr->mode = resource_ptr->mode;
+	resource_copy_ptr->resourcelen = resource_ptr->resourcelen;
+	resource_copy_ptr->sn_grs_dyn_res_callback = resource_ptr->sn_grs_dyn_res_callback;
+	resource_copy_ptr->access = resource_ptr->access;
+
+	/* Remove '/' - chars from the beginning and from the end */
+
+	path_len = resource_ptr->pathlen;
+	path_start_ptr = sn_grs_convert_uri(&path_len, resource_ptr->path);
+
+	/* Allocate memory for the path */
+	resource_copy_ptr->path = sn_grs_alloc(path_len);
+	if(!resource_copy_ptr->path)
+	{
+		sn_grs_resource_info_free(resource_copy_ptr);
+		return SN_NSDL_FAILURE;
+	}
+
+	/* Update pathlen */
+	resource_copy_ptr->pathlen = path_len;
+
+	/* Copy path string to the copy */
+#ifdef CC8051_PLAT
+        copy_code_nsdl(resource_copy_ptr->path, (prog_uint8_t*)path_start_ptr, resource_copy_ptr->pathlen);
+#else
+	memcpy(resource_copy_ptr->path, path_start_ptr, resource_copy_ptr->pathlen);
+#endif
+	/* Allocate memory for the resource, and copy it to copy */
+	if(resource_ptr->resource)
+	{
+		resource_copy_ptr->resource = sn_grs_alloc(resource_ptr->resourcelen);
+		if(!resource_copy_ptr->resource)
+		{
+			sn_grs_resource_info_free(resource_copy_ptr);
+			return SN_NSDL_FAILURE;
+		}
+		memcpy(resource_copy_ptr->resource, resource_ptr->resource, resource_ptr->resourcelen);
+	}
+
+
+
+	/* If resource parameters exists, copy them */
+	if(resource_ptr->resource_parameters_ptr)
+	{
+		resource_copy_ptr->resource_parameters_ptr = sn_grs_alloc(sizeof(sn_nsdl_resource_parameters_s));
+		if(!resource_copy_ptr->resource_parameters_ptr)
+		{
+			sn_grs_resource_info_free(resource_copy_ptr);
+			return SN_NSDL_FAILURE;
+		}
+
+		memset(resource_copy_ptr->resource_parameters_ptr, 0, sizeof(sn_nsdl_resource_parameters_s));
+
+
+		resource_copy_ptr->resource_parameters_ptr->resource_type_len = resource_ptr->resource_parameters_ptr->resource_type_len;
+
+		resource_copy_ptr->resource_parameters_ptr->interface_description_len = resource_ptr->resource_parameters_ptr->interface_description_len;
+
+		resource_copy_ptr->resource_parameters_ptr->mime_content_type = resource_ptr->resource_parameters_ptr->mime_content_type;
+
+		resource_copy_ptr->resource_parameters_ptr->observable = resource_ptr->resource_parameters_ptr->observable;
+
+		if(resource_ptr->resource_parameters_ptr->resource_type_ptr)
+		{
+			resource_copy_ptr->resource_parameters_ptr->resource_type_ptr = sn_grs_alloc(resource_ptr->resource_parameters_ptr->resource_type_len);
+			if(!resource_copy_ptr->resource_parameters_ptr->resource_type_ptr)
+			{
+				sn_grs_resource_info_free(resource_copy_ptr);
+				return SN_NSDL_FAILURE;
+			}
+#ifdef CC8051_PLAT
+                        copy_code_nsdl(resource_copy_ptr->resource_parameters_ptr->resource_type_ptr,(prog_uint8_t*) resource_ptr->resource_parameters_ptr->resource_type_ptr, resource_ptr->resource_parameters_ptr->resource_type_len);
+#else
+			memcpy(resource_copy_ptr->resource_parameters_ptr->resource_type_ptr, resource_ptr->resource_parameters_ptr->resource_type_ptr, resource_ptr->resource_parameters_ptr->resource_type_len);
+#endif
+                }
+
+		if(resource_ptr->resource_parameters_ptr->interface_description_ptr)
+		{
+			resource_copy_ptr->resource_parameters_ptr->interface_description_ptr = sn_grs_alloc(resource_ptr->resource_parameters_ptr->interface_description_len);
+			if(!resource_copy_ptr->resource_parameters_ptr->interface_description_ptr)
+			{
+				sn_grs_resource_info_free(resource_copy_ptr);
+				return SN_NSDL_FAILURE;
+			}
+			memcpy(resource_copy_ptr->resource_parameters_ptr->interface_description_ptr, resource_ptr->resource_parameters_ptr->interface_description_ptr, resource_ptr->resource_parameters_ptr->interface_description_len);
+		}
+
+		/* Copy auto observation parameter */
+		/* todo: aobs not supported ATM - needs fixing */
+/*		if(resource_ptr->resource_parameters_ptr->auto_obs_ptr && resource_ptr->resource_parameters_ptr->auto_obs_len)
+		{
+			resource_copy_ptr->resource_parameters_ptr->auto_obs_ptr = sn_grs_alloc(resource_ptr->resource_parameters_ptr->auto_obs_len);
+			if(!resource_copy_ptr->resource_parameters_ptr->auto_obs_ptr)
+			{
+				sn_grs_resource_info_free(resource_copy_ptr);
+				return SN_NSDL_FAILURE;
+			}
+			memcpy(resource_copy_ptr->resource_parameters_ptr->auto_obs_ptr, resource_ptr->resource_parameters_ptr->auto_obs_ptr, resource_ptr->resource_parameters_ptr->auto_obs_len);
+			resource_copy_ptr->resource_parameters_ptr->auto_obs_len = resource_ptr->resource_parameters_ptr->auto_obs_len;
+		}
+
+		resource_copy_ptr->resource_parameters_ptr->coap_content_type = resource_ptr->resource_parameters_ptr->coap_content_type;
+		*/
+	}
+
+	/* Add copied resource to the linked list */
+	status = sn_linked_list_add_node(list_ptr, resource_copy_ptr);
+
+	/* Was adding ok? */
+	if(status == SN_LINKED_LIST_ERROR_NO_ERROR)
+	{
+		return SN_NSDL_SUCCESS;
+	}
+	else
+	{
+		sn_grs_resource_info_free(resource_copy_ptr);
+		return SN_NSDL_FAILURE;//DONE?: Free memory
+	}
+}
+
+
+/**
+ * \fn 	static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr)
+ *
+ * \brief Removes '/' from the beginning and from the end of uri string
+ *
+ *	\param  *uri_len			Pointer to the length of the path string
+ *
+ *	\param 	*uri_ptr			Pointer to the path string
+ *
+ *	\return	start pointer of the uri
+ *
+*/
+
+static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr)
+{
+	/* Local variables */
+	uint8_t *uri_start_ptr = uri_ptr;
+
+	/* If '/' in the beginning, update uri start pointer and uri len */
+	if(*uri_ptr == '/')
+	{
+		uri_start_ptr = uri_ptr+1;
+		*uri_len = *uri_len-1;
+	}
+
+	/* If '/' at the end, update uri len */
+	if(*(uri_start_ptr+*uri_len-1) == '/')
+	{
+		*uri_len = *uri_len-1;
+	}
+
+	/* Return start pointer */
+	return uri_start_ptr;
+}
+
+/**
+ * \fn 	static int8_t sn_grs_resource_info_free(sn_grs_resource_info_s *resource_ptr)
+ *
+ * \brief Frees resource info structure
+ *
+ *	\param *resource_ptr	Pointer to the resource
+ *
+ *	\return	0 if success, -1 if failed
+ *
+*/
+SN_MEM_ATTR_GRS_FUNC
+static int8_t sn_grs_resource_info_free(sn_nsdl_resource_info_s *resource_ptr)
+{
+	if(resource_ptr)
+	{
+		if(resource_ptr->resource_parameters_ptr)
+		{
+			if(resource_ptr->resource_parameters_ptr->interface_description_ptr)
+			{
+				sn_grs_free(resource_ptr->resource_parameters_ptr->interface_description_ptr);
+				resource_ptr->resource_parameters_ptr->interface_description_ptr = 0;
+			}
+
+			if(resource_ptr->resource_parameters_ptr->resource_type_ptr)
+			{
+				sn_grs_free(resource_ptr->resource_parameters_ptr->resource_type_ptr);
+				resource_ptr->resource_parameters_ptr->resource_type_ptr = 0;
+			}
+
+			/* Todo: aobs not supported ATM - needs fixing */
+			/*
+			if(resource_ptr->resource_parameters_ptr->auto_obs_ptr)
+			{
+				sn_grs_free(resource_ptr->resource_parameters_ptr->auto_obs_ptr);
+				resource_ptr->resource_parameters_ptr->auto_obs_ptr = 0;
+			}
+			*/
+
+			sn_grs_free(resource_ptr->resource_parameters_ptr);
+			resource_ptr->resource_parameters_ptr = 0;
+		}
+
+		if(resource_ptr->path)
+		{
+			sn_grs_free(resource_ptr->path);
+			resource_ptr->path = 0;
+		}
+		if(resource_ptr->resource)
+		{
+			sn_grs_free(resource_ptr->resource);
+			resource_ptr->resource = 0;
+		}
+		sn_grs_free(resource_ptr);
+		resource_ptr = 0;
+		return SN_NSDL_SUCCESS;
+	}
+	return SN_NSDL_FAILURE;
+}
+
+#ifdef CC8051_PLAT
+void copy_code_nsdl(uint8_t * ptr, prog_uint8_t * code_ptr, uint16_t len)
+{
+	uint16_t i;
+	for(i=0; i<len; i++)
+	{
+		ptr[i] = code_ptr[i];
+	}
+}
+#endif
+
+static uint8_t sn_grs_compare_code(uint8_t * ptr, prog_uint8_t * code_ptr, uint8_t len)
+{
+	uint8_t i=0;
+	while(len)
+	{
+		if(ptr[i] != code_ptr[i])
+		{
+			break;
+		}
+		len--;
+		i++;
+	}
+	return len;
+}
+