Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sn_coap_parser.c Source File

sn_coap_parser.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011-2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /**
00018  *\file sn_coap_parser.c
00019  *
00020  * \brief CoAP Header parser
00021  *
00022  * Functionality: Parses CoAP Header
00023  *
00024  */
00025 
00026 /* * * * * * * * * * * * * * */
00027 /* * * * INCLUDE FILES * * * */
00028 /* * * * * * * * * * * * * * */
00029 
00030 #include <stdio.h>
00031 #include <string.h> /* For memset() and memcpy() */
00032 
00033 #include "ns_types.h"
00034 #include "mbed-coap/sn_coap_header.h"
00035 #include "mbed-coap/sn_coap_protocol.h"
00036 #include "sn_coap_header_internal.h"
00037 #include "sn_coap_protocol_internal.h"
00038 #include "mbed-trace/mbed_trace.h"
00039 
00040 #define TRACE_GROUP "coap"
00041 /* * * * * * * * * * * * * * * * * * * * */
00042 /* * * * LOCAL FUNCTION PROTOTYPES * * * */
00043 /* * * * * * * * * * * * * * * * * * * * */
00044 
00045 static void     sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr);
00046 static int8_t   sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len);
00047 static int8_t   sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len,  uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len);
00048 static int16_t  sn_coap_parser_options_count_needed_memory_multiple_option(const uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len);
00049 static int8_t   sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr);
00050 
00051 sn_coap_hdr_s *sn_coap_parser_init_message(sn_coap_hdr_s *coap_msg_ptr)
00052 {
00053     /* * * * Check given pointer * * * */
00054     if (coap_msg_ptr == NULL) {
00055         tr_error("sn_coap_parser_init_message - message null!");
00056         return NULL;
00057     }
00058 
00059     /* XXX not technically legal to memset pointers to 0 */
00060     memset(coap_msg_ptr, 0x00, sizeof(sn_coap_hdr_s));
00061 
00062     coap_msg_ptr->content_format = COAP_CT_NONE;
00063 
00064     return coap_msg_ptr;
00065 }
00066 
00067 sn_coap_hdr_s *sn_coap_parser_alloc_message_with_options(struct coap_s *handle)
00068 {
00069     // check the handle just as in any other place
00070     if (handle == NULL) {
00071         return NULL;
00072     }
00073 
00074     sn_coap_hdr_s *coap_msg_ptr = sn_coap_parser_alloc_message(handle);
00075 
00076     sn_coap_options_list_s *options_list_ptr = sn_coap_parser_alloc_options(handle, coap_msg_ptr);
00077 
00078     if ((coap_msg_ptr == NULL) || (options_list_ptr == NULL)) {
00079 
00080         // oops, out of memory free if got already any
00081         handle->sn_coap_protocol_free(coap_msg_ptr);
00082         handle->sn_coap_protocol_free(options_list_ptr);
00083 
00084         coap_msg_ptr = NULL;
00085     }
00086 
00087     return coap_msg_ptr;
00088 }
00089 
00090 sn_coap_hdr_s *sn_coap_parser_alloc_message(struct coap_s *handle)
00091 {
00092     sn_coap_hdr_s *returned_coap_msg_ptr;
00093 
00094     /* * * * Check given pointer * * * */
00095     if (handle == NULL) {
00096         return NULL;
00097     }
00098 
00099     /* * * * Allocate memory for returned CoAP message and initialize allocated memory with with default values  * * * */
00100     returned_coap_msg_ptr = handle->sn_coap_protocol_malloc(sizeof(sn_coap_hdr_s));
00101 
00102     return sn_coap_parser_init_message(returned_coap_msg_ptr);
00103 }
00104 
00105 sn_coap_options_list_s *sn_coap_parser_alloc_options(struct coap_s *handle, sn_coap_hdr_s *coap_msg_ptr)
00106 {
00107     sn_coap_options_list_s *options_list_ptr;
00108 
00109     /* * * * Check given pointers * * * */
00110     if (handle == NULL || coap_msg_ptr == NULL) {
00111         return NULL;
00112     }
00113 
00114     /* * * * If the message already has options, return them * * * */
00115     if (coap_msg_ptr->options_list_ptr) {
00116         return coap_msg_ptr->options_list_ptr;
00117     }
00118 
00119     /* * * * Allocate memory for options and initialize allocated memory with with default values  * * * */
00120     /* XXX not technically legal to memset pointers to 0 */
00121     options_list_ptr = sn_coap_protocol_calloc(handle, sizeof(sn_coap_options_list_s));
00122 
00123     if (options_list_ptr == NULL) {
00124         tr_error("sn_coap_parser_alloc_options - failed to allocate options list!");
00125         return NULL;
00126     }
00127 
00128     coap_msg_ptr->options_list_ptr = options_list_ptr;
00129 
00130     options_list_ptr->uri_port = COAP_OPTION_URI_PORT_NONE;
00131     options_list_ptr->observe = COAP_OBSERVE_NONE;
00132     options_list_ptr->accept = COAP_CT_NONE;
00133     options_list_ptr->block2 = COAP_OPTION_BLOCK_NONE;
00134     options_list_ptr->block1 = COAP_OPTION_BLOCK_NONE;
00135 
00136     return options_list_ptr;
00137 }
00138 
00139 sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr)
00140 {
00141     uint8_t       *data_temp_ptr                    = packet_data_ptr;
00142     sn_coap_hdr_s *parsed_and_returned_coap_msg_ptr = NULL;
00143 
00144     /* * * * Check given pointer * * * */
00145     if (packet_data_ptr == NULL || packet_data_len < 4 || handle == NULL) {
00146         return NULL;
00147     }
00148 
00149     /* * * * Allocate and initialize CoAP message  * * * */
00150     parsed_and_returned_coap_msg_ptr = sn_coap_parser_alloc_message(handle);
00151 
00152     if (parsed_and_returned_coap_msg_ptr == NULL) {
00153         tr_error("sn_coap_parser - failed to allocate message!");
00154         return NULL;
00155     }
00156 
00157     /* * * * Header parsing, move pointer over the header...  * * * */
00158     sn_coap_parser_header_parse(&data_temp_ptr, parsed_and_returned_coap_msg_ptr, coap_version_ptr);
00159 
00160     /* * * * Options parsing, move pointer over the options... * * * */
00161     if (sn_coap_parser_options_parse(handle, &data_temp_ptr, parsed_and_returned_coap_msg_ptr, packet_data_ptr, packet_data_len) != 0) {
00162         parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER;
00163         return parsed_and_returned_coap_msg_ptr;
00164     }
00165 
00166     /* * * * Payload parsing * * * */
00167     if (sn_coap_parser_payload_parse(packet_data_len, packet_data_ptr, &data_temp_ptr, parsed_and_returned_coap_msg_ptr) == -1) {
00168         parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER;
00169         return parsed_and_returned_coap_msg_ptr;
00170     }
00171 
00172     /* * * * Return parsed CoAP message  * * * * */
00173     return parsed_and_returned_coap_msg_ptr;
00174 }
00175 
00176 void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr)
00177 {
00178     if (handle == NULL) {
00179         return;
00180     }
00181 
00182     if (freed_coap_msg_ptr != NULL) {
00183 
00184         // As there are multiple sequential calls to the protocol_free, caching pointer to it
00185         // saves one instruction per call.
00186         void (*local_free)(void *) = handle->sn_coap_protocol_free;
00187 
00188         local_free(freed_coap_msg_ptr->uri_path_ptr);
00189         local_free(freed_coap_msg_ptr->token_ptr);
00190 
00191         // same here, caching the struct start saves a bit.
00192         sn_coap_options_list_s *options_list_ptr = freed_coap_msg_ptr->options_list_ptr;
00193 
00194         if (options_list_ptr != NULL) {
00195 
00196             local_free(options_list_ptr->proxy_uri_ptr);
00197 
00198             local_free(options_list_ptr->etag_ptr);
00199 
00200             local_free(options_list_ptr->uri_host_ptr);
00201 
00202             local_free(options_list_ptr->location_path_ptr);
00203 
00204             local_free(options_list_ptr->location_query_ptr);
00205 
00206             local_free(options_list_ptr->uri_query_ptr);
00207 
00208             local_free(options_list_ptr);
00209         }
00210 
00211         local_free(freed_coap_msg_ptr);
00212     }
00213 }
00214 
00215 /**
00216  * \fn static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr)
00217  *
00218  * \brief Parses CoAP message's Header part from given Packet data
00219  *
00220  * \param **packet_data_ptr is source for Packet data to be parsed to CoAP message
00221  *
00222  * \param *dst_coap_msg_ptr is destination for parsed CoAP message
00223  *
00224  * \param *coap_version_ptr is destination for parsed CoAP specification version
00225  */
00226 static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr)
00227 {
00228     /* Parse CoAP Version and message type*/
00229     *coap_version_ptr = (coap_version_e)(**packet_data_pptr & COAP_HEADER_VERSION_MASK);
00230     dst_coap_msg_ptr->msg_type = (sn_coap_msg_type_e)(**packet_data_pptr & COAP_HEADER_MSG_TYPE_MASK);
00231     (*packet_data_pptr) += 1;
00232 
00233     /* Parse Message code */
00234     dst_coap_msg_ptr->msg_code = (sn_coap_msg_code_e) **packet_data_pptr;
00235     (*packet_data_pptr) += 1;
00236 
00237     /* Parse Message ID */
00238     dst_coap_msg_ptr->msg_id = *(*packet_data_pptr + 1);
00239     dst_coap_msg_ptr->msg_id += **packet_data_pptr << COAP_HEADER_MSG_ID_MSB_SHIFT;
00240     (*packet_data_pptr) += 2;
00241 
00242 }
00243 
00244 /**
00245  * \brief Parses a variable-length uint value from an option
00246  *
00247  * \param **packet_data_pptr is source of option data to be parsed
00248  * \param option_len is length of option data (will be 0-4)
00249  *
00250  * \return Return value is value of uint
00251  */
00252 static uint32_t sn_coap_parser_options_parse_uint(uint8_t **packet_data_pptr, uint8_t option_len)
00253 {
00254     uint32_t value = 0;
00255     while (option_len--) {
00256         value <<= 8;
00257         value |= *(*packet_data_pptr)++;
00258     }
00259     return value;
00260 }
00261 
00262 /**
00263  * \fn static uint8_t sn_coap_parser_options_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr)
00264  *
00265  * \brief Parses CoAP message's Options part from given Packet data
00266  *
00267  * \param **packet_data_pptr is source of Packet data to be parsed to CoAP message
00268  * \param *dst_coap_msg_ptr is destination for parsed CoAP message
00269  *
00270  * \return Return value is 0 in ok case and -1 in failure case
00271  */
00272 static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len)
00273 {
00274     uint8_t previous_option_number = 0;
00275     uint8_t i                      = 0;
00276     int8_t  ret_status             = 0;
00277     uint16_t message_left          = 0;
00278 
00279     /*  Parse token, if exists  */
00280     dst_coap_msg_ptr->token_len = *packet_data_start_ptr & COAP_HEADER_TOKEN_LENGTH_MASK;
00281 
00282     if (dst_coap_msg_ptr->token_len) {
00283         if ((dst_coap_msg_ptr->token_len > 8) || dst_coap_msg_ptr->token_ptr) {
00284             tr_error("sn_coap_parser_options_parse - token not valid!");
00285             return -1;
00286         }
00287 
00288         dst_coap_msg_ptr->token_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, dst_coap_msg_ptr->token_len);
00289 
00290         if (dst_coap_msg_ptr->token_ptr == NULL) {
00291             tr_error("sn_coap_parser_options_parse - failed to allocate token!");
00292             return -1;
00293         }
00294 
00295         (*packet_data_pptr) += dst_coap_msg_ptr->token_len;
00296     }
00297 
00298     message_left = packet_len - ((*packet_data_pptr) - packet_data_start_ptr);
00299 
00300     /* Loop all Options */
00301     while (message_left && (**packet_data_pptr != 0xff)) {
00302 
00303         /* Get option length WITHOUT extensions */
00304         uint16_t option_len = (**packet_data_pptr & 0x0F);
00305 
00306         /* Resolve option delta */
00307         uint16_t  option_number = (**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT);
00308 
00309         if (option_number == 13) {
00310             option_number = *(*packet_data_pptr + 1) + 13;
00311             (*packet_data_pptr)++;
00312         } else if (option_number == 14) {
00313             option_number = *(*packet_data_pptr + 2);
00314             option_number += (*(*packet_data_pptr + 1) << 8) + 269;
00315             (*packet_data_pptr) += 2;
00316         }
00317         /* Option number 15 reserved for payload marker. This is handled as a error! */
00318         else if (option_number == 15) {
00319             tr_error("sn_coap_parser_options_parse - invalid option number(15)!");
00320             return -1;
00321         }
00322 
00323         /* Add previous option to option delta and get option number */
00324         option_number += previous_option_number;
00325 
00326         /* Add possible option length extension to resolve full length of the option */
00327         if (option_len == 13) {
00328             option_len = *(*packet_data_pptr + 1) + 13;
00329             (*packet_data_pptr)++;
00330         } else if (option_len == 14) {
00331             option_len = *(*packet_data_pptr + 2);
00332             option_len += (*(*packet_data_pptr + 1) << 8) + 269;
00333             (*packet_data_pptr) += 2;
00334         }
00335         /* Option number length 15 is reserved for the future use - ERROR */
00336         else if (option_len == 15) {
00337             tr_error("sn_coap_parser_options_parse - invalid option len(15)!");
00338             return -1;
00339         }
00340 
00341         message_left = packet_len - (*packet_data_pptr - packet_data_start_ptr);
00342 
00343         /* * * Parse option itself * * */
00344         /* Some options are handled independently in own functions */
00345         previous_option_number = option_number;
00346         /* Allocate options_list_ptr if needed */
00347         switch (option_number) {
00348             case COAP_OPTION_MAX_AGE:
00349             case COAP_OPTION_PROXY_URI:
00350             case COAP_OPTION_ETAG:
00351             case COAP_OPTION_URI_HOST:
00352             case COAP_OPTION_LOCATION_PATH:
00353             case COAP_OPTION_URI_PORT:
00354             case COAP_OPTION_LOCATION_QUERY:
00355             case COAP_OPTION_OBSERVE:
00356             case COAP_OPTION_URI_QUERY:
00357             case COAP_OPTION_BLOCK2:
00358             case COAP_OPTION_BLOCK1:
00359             case COAP_OPTION_ACCEPT:
00360             case COAP_OPTION_SIZE1:
00361             case COAP_OPTION_SIZE2:
00362                 if (sn_coap_parser_alloc_options(handle, dst_coap_msg_ptr) == NULL) {
00363                     tr_error("sn_coap_parser_options_parse - failed to allocate options!");
00364                     return -1;
00365                 }
00366                 break;
00367         }
00368 
00369         /* Parse option */
00370         switch (option_number) {
00371             case COAP_OPTION_CONTENT_FORMAT:
00372                 if ((option_len > 2) || (dst_coap_msg_ptr->content_format != COAP_CT_NONE)) {
00373                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_CONTENT_FORMAT not valid!");
00374                     return -1;
00375                 }
00376                 (*packet_data_pptr)++;
00377                 dst_coap_msg_ptr->content_format = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00378                 break;
00379 
00380             case COAP_OPTION_MAX_AGE:
00381                 if (option_len > 4) {
00382                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_MAX_AGE not valid!");
00383                     return -1;
00384                 }
00385                 (*packet_data_pptr)++;
00386                 dst_coap_msg_ptr->options_list_ptr->max_age = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00387                 break;
00388 
00389             case COAP_OPTION_PROXY_URI:
00390                 if ((option_len > 1034) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr) {
00391                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI not valid!");
00392                     return -1;
00393                 }
00394                 dst_coap_msg_ptr->options_list_ptr->proxy_uri_len = option_len;
00395                 (*packet_data_pptr)++;
00396 
00397                 dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, option_len);
00398 
00399                 if (dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr == NULL) {
00400                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI allocation failed!");
00401                     return -1;
00402                 }
00403 
00404                 (*packet_data_pptr) += option_len;
00405 
00406                 break;
00407 
00408             case COAP_OPTION_ETAG:
00409                 /* This is managed independently because User gives this option in one character table */
00410 
00411                 ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr,
00412                              message_left,
00413                              &dst_coap_msg_ptr->options_list_ptr->etag_ptr,
00414                              (uint16_t *)&dst_coap_msg_ptr->options_list_ptr->etag_len,
00415                              COAP_OPTION_ETAG, option_len);
00416                 if (ret_status >= 0) {
00417                     i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */
00418                 } else {
00419                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_ETAG not valid!");
00420                     return -1;
00421                 }
00422                 break;
00423 
00424             case COAP_OPTION_URI_HOST:
00425                 if ((option_len > 255) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->uri_host_ptr) {
00426                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST not valid!");
00427                     return -1;
00428                 }
00429                 dst_coap_msg_ptr->options_list_ptr->uri_host_len = option_len;
00430                 (*packet_data_pptr)++;
00431 
00432                 dst_coap_msg_ptr->options_list_ptr->uri_host_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, option_len);
00433 
00434                 if (dst_coap_msg_ptr->options_list_ptr->uri_host_ptr == NULL) {
00435                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST allocation failed!");
00436                     return -1;
00437                 }
00438                 (*packet_data_pptr) += option_len;
00439 
00440                 break;
00441 
00442             case COAP_OPTION_LOCATION_PATH:
00443                 if (dst_coap_msg_ptr->options_list_ptr->location_path_ptr) {
00444                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH exists!");
00445                     return -1;
00446                 }
00447                 /* This is managed independently because User gives this option in one character table */
00448                 ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left,
00449                              &dst_coap_msg_ptr->options_list_ptr->location_path_ptr, &dst_coap_msg_ptr->options_list_ptr->location_path_len,
00450                              COAP_OPTION_LOCATION_PATH, option_len);
00451                 if (ret_status >= 0) {
00452                     i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */
00453                 } else {
00454                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH not valid!");
00455                     return -1;
00456                 }
00457 
00458                 break;
00459 
00460 
00461             case COAP_OPTION_URI_PORT:
00462                 if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) {
00463                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PORT not valid!");
00464                     return -1;
00465                 }
00466                 (*packet_data_pptr)++;
00467 
00468                 dst_coap_msg_ptr->options_list_ptr->uri_port = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00469                 break;
00470 
00471             case COAP_OPTION_LOCATION_QUERY:
00472                 ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left,
00473                              &dst_coap_msg_ptr->options_list_ptr->location_query_ptr, &dst_coap_msg_ptr->options_list_ptr->location_query_len,
00474                              COAP_OPTION_LOCATION_QUERY, option_len);
00475                 if (ret_status >= 0) {
00476                     i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */
00477                 } else {
00478                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_QUERY not valid!");
00479                     return -1;
00480                 }
00481 
00482                 break;
00483 
00484             case COAP_OPTION_URI_PATH:
00485                 ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left,
00486                              &dst_coap_msg_ptr->uri_path_ptr, &dst_coap_msg_ptr->uri_path_len,
00487                              COAP_OPTION_URI_PATH, option_len);
00488                 if (ret_status >= 0) {
00489                     i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */
00490                 } else {
00491                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PATH not valid!");
00492                     return -1;
00493                 }
00494 
00495                 break;
00496 
00497             case COAP_OPTION_OBSERVE:
00498                 if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) {
00499                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_OBSERVE not valid!");
00500                     return -1;
00501                 }
00502 
00503                 (*packet_data_pptr)++;
00504 
00505                 dst_coap_msg_ptr->options_list_ptr->observe = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00506 
00507                 break;
00508 
00509             case COAP_OPTION_URI_QUERY:
00510                 ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left,
00511                              &dst_coap_msg_ptr->options_list_ptr->uri_query_ptr, &dst_coap_msg_ptr->options_list_ptr->uri_query_len,
00512                              COAP_OPTION_URI_QUERY, option_len);
00513                 if (ret_status >= 0) {
00514                     i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */
00515                 } else {
00516                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_QUERY not valid!");
00517                     return -1;
00518                 }
00519 
00520                 break;
00521 
00522             case COAP_OPTION_BLOCK2:
00523                 if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) {
00524                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK2 not valid!");
00525                     return -1;
00526                 }
00527                 (*packet_data_pptr)++;
00528 
00529                 dst_coap_msg_ptr->options_list_ptr->block2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00530 
00531                 break;
00532 
00533             case COAP_OPTION_BLOCK1:
00534                 if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) {
00535                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK1 not valid!");
00536                     return -1;
00537                 }
00538                 (*packet_data_pptr)++;
00539 
00540                 dst_coap_msg_ptr->options_list_ptr->block1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00541 
00542                 break;
00543 
00544             case COAP_OPTION_ACCEPT:
00545                 if ((option_len > 2) || (dst_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE)) {
00546                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_ACCEPT not valid!");
00547                     return -1;
00548                 }
00549 
00550                 (*packet_data_pptr)++;
00551 
00552                 dst_coap_msg_ptr->options_list_ptr->accept = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00553                 break;
00554 
00555             case COAP_OPTION_SIZE1:
00556                 if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size1) {
00557                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE1 not valid!");
00558                     return -1;
00559                 }
00560                 dst_coap_msg_ptr->options_list_ptr->use_size1 = true;
00561                 (*packet_data_pptr)++;
00562                 dst_coap_msg_ptr->options_list_ptr->size1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00563                 break;
00564 
00565             case COAP_OPTION_SIZE2:
00566                 if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size2) {
00567                     tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE2 not valid!");
00568                     return -1;
00569                 }
00570                 dst_coap_msg_ptr->options_list_ptr->use_size2 = true;
00571                 (*packet_data_pptr)++;
00572                 dst_coap_msg_ptr->options_list_ptr->size2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len);
00573                 break;
00574 
00575             default:
00576                 tr_error("sn_coap_parser_options_parse - unknown option!");
00577                 return -1;
00578         }
00579 
00580         /* Check for overflow */
00581         if ((*packet_data_pptr - packet_data_start_ptr) > packet_len) {
00582             return -1;
00583         }
00584 
00585         message_left = packet_len - (*packet_data_pptr - packet_data_start_ptr);
00586 
00587     }
00588 
00589     return 0;
00590 }
00591 
00592 
00593 /**
00594  * \fn static int8_t sn_coap_parser_options_parse_multiple_options(uint8_t **packet_data_pptr, uint8_t options_count_left, uint8_t *previous_option_number_ptr, uint8_t **dst_pptr,
00595  *                                                                  uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len)
00596  *
00597  * \brief Parses CoAP message's Uri-query options
00598  *
00599  * \param **packet_data_pptr is source for Packet data to be parsed to CoAP message
00600  *
00601  * \param *dst_coap_msg_ptr is destination for parsed CoAP message
00602  *
00603  * \param options_count_left tells how many options are unhandled in Packet data
00604  *
00605  * \param *previous_option_number_ptr is pointer to used and returned previous Option number
00606  *
00607  * \return Return value is count of Uri-query optios parsed. In failure case -1 is returned.
00608 */
00609 static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len,  uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len)
00610 {
00611     int16_t     uri_query_needed_heap       = sn_coap_parser_options_count_needed_memory_multiple_option(*packet_data_pptr, packet_left_len, option, option_number_len);
00612     uint8_t    *temp_parsed_uri_query_ptr   = NULL;
00613     uint8_t     returned_option_counter     = 0;
00614 
00615     if (uri_query_needed_heap == -1) {
00616         return -1;
00617     }
00618 
00619     if (uri_query_needed_heap) {
00620         *dst_pptr = (uint8_t *) handle->sn_coap_protocol_malloc(uri_query_needed_heap);
00621 
00622         if (*dst_pptr == NULL) {
00623             tr_error("sn_coap_parser_options_parse_multiple_options - failed to allocate options!");
00624             return -1;
00625         }
00626     }
00627 
00628     *dst_len_ptr = uri_query_needed_heap;
00629 
00630     temp_parsed_uri_query_ptr = *dst_pptr;
00631 
00632     /* Loop all Uri-Query options */
00633     while ((temp_parsed_uri_query_ptr - *dst_pptr) < uri_query_needed_heap) {
00634         /* Check if this is first Uri-Query option */
00635         if (returned_option_counter > 0) {
00636             /* Uri-Query is modified to following format: temp1'\0'temp2'\0'temp3 i.e.  */
00637             /* Uri-Path is modified to following format: temp1\temp2\temp3 i.e.  */
00638             if (option == COAP_OPTION_URI_QUERY || option == COAP_OPTION_LOCATION_QUERY || option == COAP_OPTION_ETAG || option == COAP_OPTION_ACCEPT) {
00639                 *temp_parsed_uri_query_ptr = '&';
00640             } else if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) {
00641                 *temp_parsed_uri_query_ptr = '/';
00642             }
00643 
00644             temp_parsed_uri_query_ptr++;
00645         }
00646 
00647         returned_option_counter++;
00648 
00649         (*packet_data_pptr)++;
00650 
00651         if (((temp_parsed_uri_query_ptr - *dst_pptr) + option_number_len) > uri_query_needed_heap) {
00652             return -1;
00653         }
00654 
00655         memcpy(temp_parsed_uri_query_ptr, *packet_data_pptr, option_number_len);
00656 
00657         (*packet_data_pptr) += option_number_len;
00658         temp_parsed_uri_query_ptr += option_number_len;
00659 
00660         if ((temp_parsed_uri_query_ptr - *dst_pptr) >= uri_query_needed_heap || ((**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0)) {
00661             return returned_option_counter;
00662         }
00663 
00664         option_number_len = (**packet_data_pptr & 0x0F);
00665         if (option_number_len == 13) {
00666             option_number_len = *(*packet_data_pptr + 1) + 13;
00667             (*packet_data_pptr)++;
00668         } else if (option_number_len == 14) {
00669             option_number_len = *(*packet_data_pptr + 2);
00670             option_number_len += (*(*packet_data_pptr + 1) << 8) + 269;
00671             (*packet_data_pptr) += 2;
00672         }
00673     }
00674 
00675     return returned_option_counter;
00676 }
00677 
00678 
00679 
00680 
00681 /**
00682  * \fn static uint16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint8_t options_count_left, uint8_t previous_option_number, sn_coap_option_numbers_e option, uint16_t option_number_len)
00683  *
00684  * \brief Counts needed memory for uri query option
00685  *
00686  * \param *packet_data_ptr is start of source for Packet data to be parsed to CoAP message
00687  *
00688  * \param options_count_left tells how many options are unhandled in Packet data
00689  *
00690  * \param previous_option_number is previous Option number
00691  *
00692  * \param sn_coap_option_numbers_e option option number to be calculated
00693  *
00694  * \param uint16_t option_number_len length of the first option part
00695  */
00696 static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(const uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len)
00697 {
00698     uint16_t ret_value              = 0;
00699     uint16_t i                      = 1;
00700 
00701     /* Loop all Uri-Query options */
00702     while (i <= packet_left_len) {
00703         if (option == COAP_OPTION_LOCATION_PATH && option_number_len > 255) {
00704             return -1;
00705         }
00706         if (option == COAP_OPTION_URI_PATH && option_number_len > 255) {
00707             return -1;
00708         }
00709         if (option == COAP_OPTION_URI_QUERY && option_number_len > 255) {
00710             return -1;
00711         }
00712         if (option == COAP_OPTION_LOCATION_QUERY && option_number_len > 255) {
00713             return -1;
00714         }
00715         if (option == COAP_OPTION_ACCEPT && option_number_len > 2) {
00716             return -1;
00717         }
00718         if (option == COAP_OPTION_ETAG && option_number_len > 8) {
00719             return -1;
00720         }
00721 
00722         i += option_number_len;
00723         ret_value += option_number_len + 1; /* + 1 is for separator */
00724 
00725         if( i == packet_left_len ) {
00726             break;
00727         }
00728         else if( i > packet_left_len ) {
00729             return -1;
00730         }
00731 
00732         if ((*(packet_data_ptr + i) >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0) {
00733             return (ret_value - 1);    /* -1 because last Part path does not include separator */
00734         }
00735 
00736         option_number_len = (*(packet_data_ptr + i) & 0x0F);
00737 
00738         if (option_number_len == 13) {
00739 
00740             if(i + 1 >= packet_left_len) {
00741                 return -1;
00742             }
00743 
00744             i++;
00745             option_number_len = *(packet_data_ptr + i) + 13;
00746         } else if (option_number_len == 14) {
00747 
00748             if(i + 2 >= packet_left_len) {
00749                 return -1;
00750             }
00751 
00752             option_number_len = *(packet_data_ptr + i + 2);
00753             option_number_len += (*(packet_data_ptr + i + 1) << 8) + 269;
00754             i += 2;
00755         } else if (option_number_len == 15) {
00756             return -1;
00757         }
00758         i++;
00759 
00760     }
00761 
00762     if (ret_value != 0) {
00763         return (ret_value - 1);    /* -1 because last Part path does not include separator */
00764     } else {
00765         return 0;
00766     }
00767 }
00768 
00769 /**
00770  * \fn static void sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr)
00771  *
00772  * \brief Parses CoAP message's Payload part from given Packet data
00773  *
00774  * \param packet_data_len is length of given Packet data to be parsed to CoAP message
00775  *
00776  * \param *packet_data_ptr is start of source for Packet data to be parsed to CoAP message
00777  *
00778  * \param **packet_data_pptr is source for Packet data to be parsed to CoAP message
00779  *
00780  * \param *dst_coap_msg_ptr is destination for parsed CoAP message
00781  *****************************************************************************/
00782 static int8_t sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr)
00783 {
00784     /* If there is payload */
00785     if ((*packet_data_pptr - packet_data_start_ptr) < packet_data_len) {
00786         if (**packet_data_pptr == 0xff) {
00787             (*packet_data_pptr)++;
00788             /* Parse Payload length */
00789             dst_coap_msg_ptr->payload_len = packet_data_len - (*packet_data_pptr - packet_data_start_ptr);
00790 
00791             /* The presence of a marker followed by a zero-length payload MUST be processed as a message format error */
00792             if (dst_coap_msg_ptr->payload_len == 0) {
00793                 return -1;
00794             }
00795 
00796             /* Parse Payload by setting CoAP message's payload_ptr to point Payload in Packet data */
00797             dst_coap_msg_ptr->payload_ptr = *packet_data_pptr;
00798         }
00799         /* No payload marker.. */
00800         else {
00801             tr_error("sn_coap_parser_payload_parse - payload marker not found!");
00802             return -1;
00803         }
00804     }
00805     return 0;
00806 }
00807