sandbox / mbed-client-c

Fork of mbed-client-c by Christopher Haster

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