Austin Blackstone / Mbed 2 deprecated mbed-client-classic-example-lwip

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Fork of mbed-client-classic-example-lwip by sandbox

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