Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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