Contiki-NG
coap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * An implementation of the Constrained Application Protocol (RFC).
35  * \author
36  * Matthias Kovatsch <kovatsch@inf.ethz.ch>
37  *
38  * Joakim Eriksson, joakim.eriksson@ri.se
39  * Niclas Finne, niclas.finne@ri.se
40  */
41 
42 /**
43  * \addtogroup coap
44  * @{
45  */
46 
47 
48 #include <string.h>
49 #include <stdlib.h>
50 #include <inttypes.h>
51 #include "sys/cc.h"
52 #include "lib/random.h"
53 
54 #include "coap.h"
55 #include "coap-transactions.h"
56 
57 /* Log configuration */
58 #include "coap-log.h"
59 #define LOG_MODULE "coap"
60 #define LOG_LEVEL LOG_LEVEL_COAP
61 
62 /*---------------------------------------------------------------------------*/
63 /*- Variables ---------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------*/
65 static uint16_t current_mid = 0;
66 
67 coap_status_t coap_status_code = NO_ERROR;
68 const char *coap_error_message = "";
69 /*---------------------------------------------------------------------------*/
70 /*- Local helper functions --------------------------------------------------*/
71 /*---------------------------------------------------------------------------*/
72 static uint16_t
73 coap_log_2(uint16_t value)
74 {
75  uint16_t result = 0;
76 
77  do {
78  value = value >> 1;
79  result++;
80  } while(value);
81 
82  return result ? result - 1 : result;
83 }
84 /*---------------------------------------------------------------------------*/
85 static uint32_t
86 coap_parse_int_option(uint8_t *bytes, size_t length)
87 {
88  uint32_t var = 0;
89  int i = 0;
90 
91  while(i < length) {
92  var <<= 8;
93  var |= bytes[i++];
94  }
95  return var;
96 }
97 /*---------------------------------------------------------------------------*/
98 static uint8_t
99 coap_option_nibble(unsigned int value)
100 {
101  if(value < 13) {
102  return value;
103  } else if(value <= 0xFF + 13) {
104  return 13;
105  } else {
106  return 14;
107  }
108 }
109 /*---------------------------------------------------------------------------*/
110 static size_t
111 coap_set_option_header(unsigned int delta, size_t length, uint8_t *buffer)
112 {
113  size_t written = 0;
114 
115  buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length);
116 
117  if(delta > 268) {
118  buffer[++written] = ((delta - 269) >> 8) & 0xff;
119  buffer[++written] = (delta - 269) & 0xff;
120  } else if(delta > 12) {
121  buffer[++written] = (delta - 13);
122  }
123 
124  if(length > 268) {
125  buffer[++written] = ((length - 269) >> 8) & 0xff;
126  buffer[++written] = (length - 269) & 0xff;
127  } else if(length > 12) {
128  buffer[++written] = (length - 13);
129  }
130 
131  LOG_DBG("WRITTEN %zu B opt header\n", 1 + written);
132 
133  return ++written;
134 }
135 /*---------------------------------------------------------------------------*/
136 static size_t
137 coap_serialize_int_option(unsigned int number, unsigned int current_number,
138  uint8_t *buffer, uint32_t value)
139 {
140  size_t i = 0;
141 
142  if(0xFF000000 & value) {
143  ++i;
144  }
145  if(0xFFFF0000 & value) {
146  ++i;
147  }
148  if(0xFFFFFF00 & value) {
149  ++i;
150  }
151  if(0xFFFFFFFF & value) {
152  ++i;
153  }
154  LOG_DBG("OPTION %u (delta %u, len %zu)\n", number, number - current_number,
155  i);
156 
157  i = coap_set_option_header(number - current_number, i, buffer);
158 
159  if(0xFF000000 & value) {
160  buffer[i++] = (uint8_t)(value >> 24);
161  }
162  if(0xFFFF0000 & value) {
163  buffer[i++] = (uint8_t)(value >> 16);
164  }
165  if(0xFFFFFF00 & value) {
166  buffer[i++] = (uint8_t)(value >> 8);
167  }
168  if(0xFFFFFFFF & value) {
169  buffer[i++] = (uint8_t)(value);
170  }
171  return i;
172 }
173 /*---------------------------------------------------------------------------*/
174 static size_t
175 coap_serialize_array_option(unsigned int number, unsigned int current_number,
176  uint8_t *buffer, uint8_t *array, size_t length,
177  char split_char)
178 {
179  size_t i = 0;
180 
181  LOG_DBG("ARRAY type %u, len %zu, full [", number, length);
182  LOG_DBG_COAP_STRING((const char *)array, length);
183  LOG_DBG_("]\n");
184 
185  if(split_char != '\0') {
186  int j;
187  uint8_t *part_start = array;
188  uint8_t *part_end = NULL;
189  size_t temp_length;
190 
191  for(j = 0; j <= length + 1; ++j) {
192  LOG_DBG("STEP %u/%zu (%c)\n", j, length, array[j]);
193  if(array[j] == split_char || j == length) {
194  part_end = array + j;
195  temp_length = part_end - part_start;
196 
197  i += coap_set_option_header(number - current_number, temp_length,
198  &buffer[i]);
199  memcpy(&buffer[i], part_start, temp_length);
200  i += temp_length;
201 
202  LOG_DBG("OPTION type %u, delta %u, len %zu, part [", number,
203  number - current_number, i);
204  LOG_DBG_COAP_STRING((const char *)part_start, temp_length);
205  LOG_DBG_("]\n");
206  ++j; /* skip the splitter */
207  current_number = number;
208  part_start = array + j;
209  }
210  } /* for */
211  } else {
212  i += coap_set_option_header(number - current_number, length, &buffer[i]);
213  memcpy(&buffer[i], array, length);
214  i += length;
215 
216  LOG_DBG("OPTION type %u, delta %u, len %zu\n", number,
217  number - current_number, length);
218  }
219 
220  return i;
221 }
222 /*---------------------------------------------------------------------------*/
223 static void
224 coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option,
225  size_t option_len, char separator)
226 {
227  /* merge multiple options */
228  if(*dst_len > 0) {
229  /* dst already contains an option: concatenate */
230  (*dst)[*dst_len] = separator;
231  *dst_len += 1;
232 
233  /* memmove handles 2-byte option headers */
234  memmove((*dst) + (*dst_len), option, option_len);
235 
236  *dst_len += option_len;
237  } else {
238  /* dst is empty: set to option */
239  *dst = (char *)option;
240  *dst_len = option_len;
241  }
242 }
243 /*---------------------------------------------------------------------------*/
244 static int
245 coap_get_variable(const char *buffer, size_t length, const char *name,
246  const char **output)
247 {
248  const char *start = NULL;
249  const char *end = NULL;
250  const char *value_end = NULL;
251  size_t name_len = 0;
252 
253  /*initialize the output buffer first */
254  *output = 0;
255 
256  name_len = strlen(name);
257  end = buffer + length;
258 
259  for(start = buffer; start + name_len < end; ++start) {
260  if((start == buffer || start[-1] == '&') && start[name_len] == '='
261  && strncmp(name, start, name_len) == 0) {
262 
263  /* Point start to variable value */
264  start += name_len + 1;
265 
266  /* Point end to the end of the value */
267  value_end = (const char *)memchr(start, '&', end - start);
268  if(value_end == NULL) {
269  value_end = end;
270  }
271  *output = start;
272 
273  return value_end - start;
274  }
275  }
276  return 0;
277 }
278 /*---------------------------------------------------------------------------*/
279 /*- Internal API ------------------------------------------------------------*/
280 /*---------------------------------------------------------------------------*/
281 void
282 coap_init_connection(void)
283 {
284  /* initialize transaction ID */
285  current_mid = random_rand();
286 }
287 /*---------------------------------------------------------------------------*/
288 uint16_t
289 coap_get_mid()
290 {
291  return ++current_mid;
292 }
293 /*---------------------------------------------------------------------------*/
294 void
295 coap_init_message(coap_message_t *coap_pkt, coap_message_type_t type,
296  uint8_t code, uint16_t mid)
297 {
298  /* Important thing */
299  memset(coap_pkt, 0, sizeof(coap_message_t));
300 
301  coap_pkt->type = type;
302  coap_pkt->code = code;
303  coap_pkt->mid = mid;
304 }
305 /*---------------------------------------------------------------------------*/
306 size_t
307 coap_serialize_message(coap_message_t *coap_pkt, uint8_t *buffer)
308 {
309  uint8_t *option;
310  unsigned int current_number = 0;
311 
312  /* Initialize */
313  coap_pkt->buffer = buffer;
314  coap_pkt->version = 1;
315 
316  LOG_DBG("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer);
317 
318  /* set header fields */
319  coap_pkt->buffer[0] = 0x00;
320  coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK
321  & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION;
322  coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK
323  & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION;
324  coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK
325  & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION;
326  coap_pkt->buffer[1] = coap_pkt->code;
327  coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8);
328  coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid);
329 
330  /* empty message, dont need to do more stuff */
331  if(!coap_pkt->code) {
332  LOG_DBG_("-Done serializing empty message at %p-\n", coap_pkt->buffer);
333  return 4;
334  }
335 
336  /* set Token */
337  LOG_DBG_("Token (len %u)", coap_pkt->token_len);
338  option = coap_pkt->buffer + COAP_HEADER_LEN;
339  for(current_number = 0; current_number < coap_pkt->token_len;
340  ++current_number) {
341  LOG_DBG_(" %02X", coap_pkt->token[current_number]);
342  *option = coap_pkt->token[current_number];
343  ++option;
344  }
345  LOG_DBG_("-\n");
346 
347  /* Serialize options */
348  current_number = 0;
349 
350  LOG_DBG("-Serializing options at %p-\n", option);
351 
352  /* The options must be serialized in the order of their number */
353  COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match");
354  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0',
355  "Uri-Host");
356  COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag");
357  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH,
358  content_format -
359  coap_pkt->
360  content_format /* hack to get a zero field */,
361  "If-None-Match");
362  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe");
363  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port");
364  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/',
365  "Location-Path");
366  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/',
367  "Uri-Path");
368  LOG_DBG("Serialize content format: %d\n", coap_pkt->content_format);
369  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format,
370  "Content-Format");
371  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age");
372  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&',
373  "Uri-Query");
374  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept");
375  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query,
376  '&', "Location-Query");
377  COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2");
378  COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1");
379  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2");
380  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0',
381  "Proxy-Uri");
382  COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0',
383  "Proxy-Scheme");
384  COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1");
385 
386  LOG_DBG("-Done serializing at %p----\n", option);
387 
388  /* Pack payload */
389  if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) {
390  /* Payload marker */
391  if(coap_pkt->payload_len) {
392  *option = 0xFF;
393  ++option;
394  }
395  memmove(option, coap_pkt->payload, coap_pkt->payload_len);
396  } else {
397  /* an error occurred: caller must check for !=0 */
398  coap_pkt->buffer = NULL;
399  coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE";
400  return 0;
401  }
402 
403  LOG_DBG("-Done %u B (header len %u, payload len %u)-\n",
404  (unsigned int)(coap_pkt->payload_len + option - buffer),
405  (unsigned int)(option - buffer),
406  (unsigned int)coap_pkt->payload_len);
407 
408  LOG_DBG("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n",
409  coap_pkt->buffer[0], coap_pkt->buffer[1], coap_pkt->buffer[2],
410  coap_pkt->buffer[3], coap_pkt->buffer[4], coap_pkt->buffer[5],
411  coap_pkt->buffer[6], coap_pkt->buffer[7]);
412 
413  return (option - buffer) + coap_pkt->payload_len; /* message length */
414 }
415 /*---------------------------------------------------------------------------*/
416 coap_status_t
417 coap_parse_message(coap_message_t *coap_pkt, uint8_t *data, uint16_t data_len)
418 {
419  if(data_len < COAP_HEADER_LEN) {
420  /* Too short - malformed CoAP message */
421  LOG_WARN("BAD REQUEST: message too short\n");
422  return BAD_REQUEST_4_00;
423  }
424 
425  /* initialize message */
426  memset(coap_pkt, 0, sizeof(coap_message_t));
427 
428  /* pointer to message bytes */
429  coap_pkt->buffer = data;
430 
431  /* parse header fields */
432  coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])
433  >> COAP_HEADER_VERSION_POSITION;
434  coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])
435  >> COAP_HEADER_TYPE_POSITION;
436  coap_pkt->token_len = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])
437  >> COAP_HEADER_TOKEN_LEN_POSITION;
438  coap_pkt->code = coap_pkt->buffer[1];
439  coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3];
440 
441  if(coap_pkt->version != 1) {
442  coap_error_message = "CoAP version must be 1";
443  return BAD_REQUEST_4_00;
444  }
445 
446  if(coap_pkt->token_len > COAP_TOKEN_LEN) {
447  coap_error_message = "Token Length must not be more than 8";
448  return BAD_REQUEST_4_00;
449  }
450 
451  uint8_t *current_option = data + COAP_HEADER_LEN;
452  if(current_option + coap_pkt->token_len > data + data_len) {
453  /* Malformed CoAP message - token length out od message bounds */
454  LOG_WARN("BAD REQUEST: token outside message buffer");
455  return BAD_REQUEST_4_00;
456  }
457 
458  memcpy(coap_pkt->token, current_option, coap_pkt->token_len);
459  LOG_DBG("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
460  coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1],
461  coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4],
462  coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7]
463  ); /* FIXME always prints 8 bytes */
464 
465  /* parse options */
466  memset(coap_pkt->options, 0, sizeof(coap_pkt->options));
467  current_option += coap_pkt->token_len;
468 
469  unsigned int option_number = 0;
470  unsigned int option_delta = 0;
471  size_t option_length = 0;
472 
473  while(current_option < data + data_len) {
474  /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */
475  if((current_option[0] & 0xF0) == 0xF0) {
476  coap_pkt->payload = ++current_option;
477  coap_pkt->payload_len = data_len - (coap_pkt->payload - data);
478 
479  /* also for receiving, the Erbium upper bound is COAP_MAX_CHUNK_SIZE */
480  if(coap_pkt->payload_len > COAP_MAX_CHUNK_SIZE) {
481  coap_pkt->payload_len = COAP_MAX_CHUNK_SIZE;
482  /* null-terminate payload */
483  }
484  coap_pkt->payload[coap_pkt->payload_len] = '\0';
485 
486  break;
487  }
488 
489  option_delta = current_option[0] >> 4;
490  option_length = current_option[0] & 0x0F;
491  ++current_option;
492  if(current_option >= data + data_len) {
493  /* Malformed CoAP - out of bounds */
494  LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
495  return BAD_REQUEST_4_00;
496  }
497 
498  if(option_delta == 13) {
499  option_delta += current_option[0];
500  ++current_option;
501  } else if(option_delta == 14) {
502  option_delta += 255;
503  option_delta += current_option[0] << 8;
504  ++current_option;
505  if(current_option >= data + data_len) {
506  /* Malformed CoAP - out of bounds */
507  LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
508  return BAD_REQUEST_4_00;
509  }
510  option_delta += current_option[0];
511  ++current_option;
512  }
513 
514  if(current_option >= data + data_len) {
515  /* Malformed CoAP - out of bounds */
516  LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
517  return BAD_REQUEST_4_00;
518  }
519 
520  if(option_length == 13) {
521  option_length += current_option[0];
522  ++current_option;
523  } else if(option_length == 14) {
524  option_length += 255;
525  option_length += current_option[0] << 8;
526  ++current_option;
527  if(current_option >= data + data_len) {
528  /* Malformed CoAP - out of bounds */
529  LOG_WARN("BAD REQUEST: option length outside message buffer\n");
530  return BAD_REQUEST_4_00;
531  }
532  option_length += current_option[0];
533  ++current_option;
534  }
535 
536  if(current_option + option_length > data + data_len) {
537  /* Malformed CoAP - out of bounds */
538  LOG_WARN("BAD REQUEST: options outside data message: %u > %u\n",
539  (unsigned)(current_option + option_length - data), data_len);
540  return BAD_REQUEST_4_00;
541  }
542 
543  option_number += option_delta;
544 
545  if(option_number > COAP_OPTION_SIZE1) {
546  /* Malformed CoAP - out of bounds */
547  LOG_WARN("BAD REQUEST: option number too large: %u\n", option_number);
548  return BAD_REQUEST_4_00;
549  }
550 
551  LOG_DBG("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
552  option_length);
553 
554  coap_set_option(coap_pkt, option_number);
555 
556  switch(option_number) {
557  case COAP_OPTION_CONTENT_FORMAT:
558  coap_pkt->content_format = coap_parse_int_option(current_option,
559  option_length);
560  LOG_DBG_("Content-Format [%u]\n", coap_pkt->content_format);
561  break;
562  case COAP_OPTION_MAX_AGE:
563  coap_pkt->max_age = coap_parse_int_option(current_option,
564  option_length);
565  LOG_DBG_("Max-Age [%"PRIu32"]\n", coap_pkt->max_age);
566  break;
567  case COAP_OPTION_ETAG:
568  coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length);
569  memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len);
570  LOG_DBG_("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
571  coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1],
572  coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4],
573  coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7]
574  ); /*FIXME always prints 8 bytes */
575  break;
576  case COAP_OPTION_ACCEPT:
577  coap_pkt->accept = coap_parse_int_option(current_option, option_length);
578  LOG_DBG_("Accept [%u]\n", coap_pkt->accept);
579  break;
580  case COAP_OPTION_IF_MATCH:
581  /* TODO support multiple ETags */
582  coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length);
583  memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len);
584  LOG_DBG_("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
585  coap_pkt->if_match_len, coap_pkt->if_match[0],
586  coap_pkt->if_match[1], coap_pkt->if_match[2],
587  coap_pkt->if_match[3], coap_pkt->if_match[4],
588  coap_pkt->if_match[5], coap_pkt->if_match[6],
589  coap_pkt->if_match[7]
590  ); /* FIXME always prints 8 bytes */
591  break;
592  case COAP_OPTION_IF_NONE_MATCH:
593  coap_pkt->if_none_match = 1;
594  LOG_DBG_("If-None-Match\n");
595  break;
596 
597  case COAP_OPTION_PROXY_URI:
598 #if COAP_PROXY_OPTION_PROCESSING
599  coap_pkt->proxy_uri = (char *)current_option;
600  coap_pkt->proxy_uri_len = option_length;
601 #endif /* COAP_PROXY_OPTION_PROCESSING */
602  LOG_DBG_("Proxy-Uri NOT IMPLEMENTED [");
603  LOG_DBG_COAP_STRING(coap_pkt->proxy_uri, coap_pkt->proxy_uri_len);
604  LOG_DBG_("]\n");
605 
606  coap_error_message = "This is a constrained server (Contiki)";
607  return PROXYING_NOT_SUPPORTED_5_05;
608  break;
609  case COAP_OPTION_PROXY_SCHEME:
610 #if COAP_PROXY_OPTION_PROCESSING
611  coap_pkt->proxy_scheme = (char *)current_option;
612  coap_pkt->proxy_scheme_len = option_length;
613 #endif
614  LOG_DBG_("Proxy-Scheme NOT IMPLEMENTED [");
615  LOG_DBG_COAP_STRING(coap_pkt->proxy_scheme, coap_pkt->proxy_scheme_len);
616  LOG_DBG_("]\n");
617  coap_error_message = "This is a constrained server (Contiki)";
618  return PROXYING_NOT_SUPPORTED_5_05;
619  break;
620 
621  case COAP_OPTION_URI_HOST:
622  coap_pkt->uri_host = (char *)current_option;
623  coap_pkt->uri_host_len = option_length;
624  LOG_DBG_("Uri-Host [");
625  LOG_DBG_COAP_STRING(coap_pkt->uri_host, coap_pkt->uri_host_len);
626  LOG_DBG_("]\n");
627  break;
628  case COAP_OPTION_URI_PORT:
629  coap_pkt->uri_port = coap_parse_int_option(current_option,
630  option_length);
631  LOG_DBG_("Uri-Port [%u]\n", coap_pkt->uri_port);
632  break;
633  case COAP_OPTION_URI_PATH:
634  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
635  coap_merge_multi_option((char **)&(coap_pkt->uri_path),
636  &(coap_pkt->uri_path_len), current_option,
637  option_length, '/');
638  LOG_DBG_("Uri-Path [");
639  LOG_DBG_COAP_STRING(coap_pkt->uri_path, coap_pkt->uri_path_len);
640  LOG_DBG_("]\n");
641  break;
642  case COAP_OPTION_URI_QUERY:
643  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
644  coap_merge_multi_option((char **)&(coap_pkt->uri_query),
645  &(coap_pkt->uri_query_len), current_option,
646  option_length, '&');
647  LOG_DBG_("Uri-Query[");
648  LOG_DBG_COAP_STRING(coap_pkt->uri_query, coap_pkt->uri_query_len);
649  LOG_DBG_("]\n");
650  break;
651 
652  case COAP_OPTION_LOCATION_PATH:
653  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
654  coap_merge_multi_option((char **)&(coap_pkt->location_path),
655  &(coap_pkt->location_path_len), current_option,
656  option_length, '/');
657 
658  LOG_DBG_("Location-Path [");
659  LOG_DBG_COAP_STRING(coap_pkt->location_path, coap_pkt->location_path_len);
660  LOG_DBG_("]\n");
661  break;
662  case COAP_OPTION_LOCATION_QUERY:
663  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
664  coap_merge_multi_option((char **)&(coap_pkt->location_query),
665  &(coap_pkt->location_query_len), current_option,
666  option_length, '&');
667  LOG_DBG_("Location-Query [");
668  LOG_DBG_COAP_STRING(coap_pkt->location_query, coap_pkt->location_query_len);
669  LOG_DBG_("]\n");
670  break;
671 
672  case COAP_OPTION_OBSERVE:
673  coap_pkt->observe = coap_parse_int_option(current_option,
674  option_length);
675  LOG_DBG_("Observe [%"PRId32"]\n", coap_pkt->observe);
676  break;
677  case COAP_OPTION_BLOCK2:
678  coap_pkt->block2_num = coap_parse_int_option(current_option,
679  option_length);
680  coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3;
681  coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07);
682  coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)
683  << (coap_pkt->block2_num & 0x07);
684  coap_pkt->block2_num >>= 4;
685  LOG_DBG_("Block2 [%lu%s (%u B/blk)]\n",
686  (unsigned long)coap_pkt->block2_num,
687  coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size);
688  break;
689  case COAP_OPTION_BLOCK1:
690  coap_pkt->block1_num = coap_parse_int_option(current_option,
691  option_length);
692  coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3;
693  coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07);
694  coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F)
695  << (coap_pkt->block1_num & 0x07);
696  coap_pkt->block1_num >>= 4;
697  LOG_DBG_("Block1 [%lu%s (%u B/blk)]\n",
698  (unsigned long)coap_pkt->block1_num,
699  coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size);
700  break;
701  case COAP_OPTION_SIZE2:
702  coap_pkt->size2 = coap_parse_int_option(current_option, option_length);
703  LOG_DBG_("Size2 [%"PRIu32"]\n", coap_pkt->size2);
704  break;
705  case COAP_OPTION_SIZE1:
706  coap_pkt->size1 = coap_parse_int_option(current_option, option_length);
707  LOG_DBG_("Size1 [%"PRIu32"]\n", coap_pkt->size1);
708  break;
709  default:
710  LOG_DBG_("unknown (%u)\n", option_number);
711  /* check if critical (odd) */
712  if(option_number & 1) {
713  coap_error_message = "Unsupported critical option";
714  return BAD_OPTION_4_02;
715  }
716  }
717 
718  current_option += option_length;
719  } /* for */
720  LOG_DBG("-Done parsing-------\n");
721 
722  return NO_ERROR;
723 }
724 /*---------------------------------------------------------------------------*/
725 /*- CoAP Engine API ---------------------------------------------------------*/
726 /*---------------------------------------------------------------------------*/
727 int
728 coap_get_query_variable(coap_message_t *coap_pkt,
729  const char *name, const char **output)
730 {
731  if(coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
732  return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len,
733  name, output);
734  }
735  return 0;
736 }
737 int
738 coap_get_post_variable(coap_message_t *coap_pkt,
739  const char *name, const char **output)
740 {
741  if(coap_pkt->payload_len) {
742  return coap_get_variable((const char *)coap_pkt->payload,
743  coap_pkt->payload_len, name, output);
744  }
745  return 0;
746 }
747 /*---------------------------------------------------------------------------*/
748 int
749 coap_set_status_code(coap_message_t *message, unsigned int code)
750 {
751  if(code <= 0xFF) {
752  message->code = (uint8_t)code;
753  return 1;
754  } else {
755  return 0;
756  }
757 }
758 /*---------------------------------------------------------------------------*/
759 int
760 coap_set_token(coap_message_t *coap_pkt, const uint8_t *token, size_t token_len)
761 {
762  coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len);
763  memcpy(coap_pkt->token, token, coap_pkt->token_len);
764 
765  return coap_pkt->token_len;
766 }
767 /*---------------------------------------------------------------------------*/
768 /*- CoAP Implementation API -------------------------------------------------*/
769 /*---------------------------------------------------------------------------*/
770 int
771 coap_get_header_content_format(coap_message_t *coap_pkt, unsigned int *format)
772 {
773  if(!coap_is_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) {
774  return 0;
775  }
776  *format = coap_pkt->content_format;
777  return 1;
778 }
779 int
780 coap_set_header_content_format(coap_message_t *coap_pkt, unsigned int format)
781 {
782  coap_pkt->content_format = format;
783  coap_set_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT);
784  return 1;
785 }
786 /*---------------------------------------------------------------------------*/
787 int
788 coap_get_header_accept(coap_message_t *coap_pkt, unsigned int *accept)
789 {
790  if(!coap_is_option(coap_pkt, COAP_OPTION_ACCEPT)) {
791  return 0;
792  }
793  *accept = coap_pkt->accept;
794  return 1;
795 }
796 int
797 coap_set_header_accept(coap_message_t *coap_pkt, unsigned int accept)
798 {
799  coap_pkt->accept = accept;
800  coap_set_option(coap_pkt, COAP_OPTION_ACCEPT);
801  return 1;
802 }
803 /*---------------------------------------------------------------------------*/
804 int
805 coap_get_header_max_age(coap_message_t *coap_pkt, uint32_t *age)
806 {
807  if(!coap_is_option(coap_pkt, COAP_OPTION_MAX_AGE)) {
808  *age = COAP_DEFAULT_MAX_AGE;
809  } else {
810  *age = coap_pkt->max_age;
811  } return 1;
812 }
813 int
814 coap_set_header_max_age(coap_message_t *coap_pkt, uint32_t age)
815 {
816  coap_pkt->max_age = age;
817  coap_set_option(coap_pkt, COAP_OPTION_MAX_AGE);
818  return 1;
819 }
820 /*---------------------------------------------------------------------------*/
821 int
822 coap_get_header_etag(coap_message_t *coap_pkt, const uint8_t **etag)
823 {
824  if(!coap_is_option(coap_pkt, COAP_OPTION_ETAG)) {
825  return 0;
826  }
827  *etag = coap_pkt->etag;
828  return coap_pkt->etag_len;
829 }
830 int
831 coap_set_header_etag(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
832 {
833  coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len);
834  memcpy(coap_pkt->etag, etag, coap_pkt->etag_len);
835 
836  coap_set_option(coap_pkt, COAP_OPTION_ETAG);
837  return coap_pkt->etag_len;
838 }
839 /*---------------------------------------------------------------------------*/
840 /*FIXME support multiple ETags */
841 int
842 coap_get_header_if_match(coap_message_t *coap_pkt, const uint8_t **etag)
843 {
844  if(!coap_is_option(coap_pkt, COAP_OPTION_IF_MATCH)) {
845  return 0;
846  }
847  *etag = coap_pkt->if_match;
848  return coap_pkt->if_match_len;
849 }
850 int
851 coap_set_header_if_match(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
852 {
853  coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len);
854  memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len);
855 
856  coap_set_option(coap_pkt, COAP_OPTION_IF_MATCH);
857  return coap_pkt->if_match_len;
858 }
859 /*---------------------------------------------------------------------------*/
860 int
861 coap_get_header_if_none_match(coap_message_t *message)
862 {
863  return coap_is_option(message, COAP_OPTION_IF_NONE_MATCH) ? 1 : 0;
864 }
865 int
866 coap_set_header_if_none_match(coap_message_t *message)
867 {
868  coap_set_option(message, COAP_OPTION_IF_NONE_MATCH);
869  return 1;
870 }
871 /*---------------------------------------------------------------------------*/
872 int
873 coap_get_header_proxy_uri(coap_message_t *coap_pkt, const char **uri)
874 {
875  if(!coap_is_option(coap_pkt, COAP_OPTION_PROXY_URI)) {
876  return 0;
877  }
878  *uri = coap_pkt->proxy_uri;
879  return coap_pkt->proxy_uri_len;
880 }
881 int
882 coap_set_header_proxy_uri(coap_message_t *coap_pkt, const char *uri)
883 {
884  /* TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide coap-conf define */
885 
886  coap_pkt->proxy_uri = uri;
887  coap_pkt->proxy_uri_len = strlen(uri);
888 
889  coap_set_option(coap_pkt, COAP_OPTION_PROXY_URI);
890  return coap_pkt->proxy_uri_len;
891 }
892 /*---------------------------------------------------------------------------*/
893 int
894 coap_get_header_uri_host(coap_message_t *coap_pkt, const char **host)
895 {
896  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_HOST)) {
897  return 0;
898  }
899  *host = coap_pkt->uri_host;
900  return coap_pkt->uri_host_len;
901 }
902 int
903 coap_set_header_uri_host(coap_message_t *coap_pkt, const char *host)
904 {
905  coap_pkt->uri_host = host;
906  coap_pkt->uri_host_len = strlen(host);
907 
908  coap_set_option(coap_pkt, COAP_OPTION_URI_HOST);
909  return coap_pkt->uri_host_len;
910 }
911 /*---------------------------------------------------------------------------*/
912 int
913 coap_get_header_uri_path(coap_message_t *coap_pkt, const char **path)
914 {
915  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_PATH)) {
916  return 0;
917  }
918  *path = coap_pkt->uri_path;
919  return coap_pkt->uri_path_len;
920 }
921 int
922 coap_set_header_uri_path(coap_message_t *coap_pkt, const char *path)
923 {
924  while(path[0] == '/') {
925  ++path;
926  }
927 
928  coap_pkt->uri_path = path;
929  coap_pkt->uri_path_len = strlen(path);
930 
931  coap_set_option(coap_pkt, COAP_OPTION_URI_PATH);
932  return coap_pkt->uri_path_len;
933 }
934 /*---------------------------------------------------------------------------*/
935 int
936 coap_get_header_uri_query(coap_message_t *coap_pkt, const char **query)
937 {
938  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
939  return 0;
940  }
941  *query = coap_pkt->uri_query;
942  return coap_pkt->uri_query_len;
943 }
944 int
945 coap_set_header_uri_query(coap_message_t *coap_pkt, const char *query)
946 {
947  while(query[0] == '?') {
948  ++query;
949  }
950 
951  coap_pkt->uri_query = query;
952  coap_pkt->uri_query_len = strlen(query);
953 
954  coap_set_option(coap_pkt, COAP_OPTION_URI_QUERY);
955  return coap_pkt->uri_query_len;
956 }
957 /*---------------------------------------------------------------------------*/
958 int
959 coap_get_header_location_path(coap_message_t *coap_pkt, const char **path)
960 {
961  if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_PATH)) {
962  return 0;
963  }
964  *path = coap_pkt->location_path;
965  return coap_pkt->location_path_len;
966 }
967 int
968 coap_set_header_location_path(coap_message_t *coap_pkt, const char *path)
969 {
970  char *query;
971 
972  while(path[0] == '/') {
973  ++path;
974  }
975 
976  if((query = strchr(path, '?'))) {
977  coap_set_header_location_query(coap_pkt, query + 1);
978  coap_pkt->location_path_len = query - path;
979  } else {
980  coap_pkt->location_path_len = strlen(path);
981  } coap_pkt->location_path = path;
982 
983  if(coap_pkt->location_path_len > 0) {
984  coap_set_option(coap_pkt, COAP_OPTION_LOCATION_PATH);
985  }
986  return coap_pkt->location_path_len;
987 }
988 /*---------------------------------------------------------------------------*/
989 int
990 coap_get_header_location_query(coap_message_t *coap_pkt, const char **query)
991 {
992  if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_QUERY)) {
993  return 0;
994  }
995  *query = coap_pkt->location_query;
996  return coap_pkt->location_query_len;
997 }
998 int
999 coap_set_header_location_query(coap_message_t *coap_pkt, const char *query)
1000 {
1001  while(query[0] == '?') {
1002  ++query;
1003  }
1004 
1005  coap_pkt->location_query = query;
1006  coap_pkt->location_query_len = strlen(query);
1007 
1008  coap_set_option(coap_pkt, COAP_OPTION_LOCATION_QUERY);
1009  return coap_pkt->location_query_len;
1010 }
1011 /*---------------------------------------------------------------------------*/
1012 int
1013 coap_get_header_observe(coap_message_t *coap_pkt, uint32_t *observe)
1014 {
1015  if(!coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) {
1016  return 0;
1017  }
1018  *observe = coap_pkt->observe;
1019  return 1;
1020 }
1021 int
1022 coap_set_header_observe(coap_message_t *coap_pkt, uint32_t observe)
1023 {
1024  coap_pkt->observe = observe;
1025  coap_set_option(coap_pkt, COAP_OPTION_OBSERVE);
1026  return 1;
1027 }
1028 /*---------------------------------------------------------------------------*/
1029 int
1030 coap_get_header_block2(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
1031  uint16_t *size, uint32_t *offset)
1032 {
1033  if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK2)) {
1034  return 0;
1035  }
1036  /* pointers may be NULL to get only specific block parameters */
1037  if(num != NULL) {
1038  *num = coap_pkt->block2_num;
1039  }
1040  if(more != NULL) {
1041  *more = coap_pkt->block2_more;
1042  }
1043  if(size != NULL) {
1044  *size = coap_pkt->block2_size;
1045  }
1046  if(offset != NULL) {
1047  *offset = coap_pkt->block2_offset;
1048  }
1049  return 1;
1050 }
1051 int
1052 coap_set_header_block2(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1053  uint16_t size)
1054 {
1055  if(size < 16) {
1056  return 0;
1057  }
1058  if(size > 2048) {
1059  return 0;
1060  }
1061  if(num > 0x0FFFFF) {
1062  return 0;
1063  }
1064  coap_pkt->block2_num = num;
1065  coap_pkt->block2_more = more ? 1 : 0;
1066  coap_pkt->block2_size = size;
1067 
1068  coap_set_option(coap_pkt, COAP_OPTION_BLOCK2);
1069  return 1;
1070 }
1071 /*---------------------------------------------------------------------------*/
1072 int
1073 coap_get_header_block1(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
1074  uint16_t *size, uint32_t *offset)
1075 {
1076  if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK1)) {
1077  return 0;
1078  }
1079  /* pointers may be NULL to get only specific block parameters */
1080  if(num != NULL) {
1081  *num = coap_pkt->block1_num;
1082  }
1083  if(more != NULL) {
1084  *more = coap_pkt->block1_more;
1085  }
1086  if(size != NULL) {
1087  *size = coap_pkt->block1_size;
1088  }
1089  if(offset != NULL) {
1090  *offset = coap_pkt->block1_offset;
1091  }
1092  return 1;
1093 }
1094 int
1095 coap_set_header_block1(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1096  uint16_t size)
1097 {
1098  if(size < 16) {
1099  return 0;
1100  }
1101  if(size > 2048) {
1102  return 0;
1103  }
1104  if(num > 0x0FFFFF) {
1105  return 0;
1106  }
1107  coap_pkt->block1_num = num;
1108  coap_pkt->block1_more = more;
1109  coap_pkt->block1_size = size;
1110 
1111  coap_set_option(coap_pkt, COAP_OPTION_BLOCK1);
1112  return 1;
1113 }
1114 /*---------------------------------------------------------------------------*/
1115 int
1116 coap_get_header_size2(coap_message_t *coap_pkt, uint32_t *size)
1117 {
1118  if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE2)) {
1119  return 0;
1120  }
1121  *size = coap_pkt->size2;
1122  return 1;
1123 }
1124 int
1125 coap_set_header_size2(coap_message_t *coap_pkt, uint32_t size)
1126 {
1127  coap_pkt->size2 = size;
1128  coap_set_option(coap_pkt, COAP_OPTION_SIZE2);
1129  return 1;
1130 }
1131 /*---------------------------------------------------------------------------*/
1132 int
1133 coap_get_header_size1(coap_message_t *coap_pkt, uint32_t *size)
1134 {
1135  if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE1)) {
1136  return 0;
1137  }
1138  *size = coap_pkt->size1;
1139  return 1;
1140 }
1141 int
1142 coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size)
1143 {
1144  coap_pkt->size1 = size;
1145  coap_set_option(coap_pkt, COAP_OPTION_SIZE1);
1146  return 1;
1147 }
1148 /*---------------------------------------------------------------------------*/
1149 int
1150 coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload)
1151 {
1152  if(payload != NULL) {
1153  *payload = coap_pkt->payload;
1154  }
1155  return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0;
1156 }
1157 int
1158 coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length)
1159 {
1160  coap_pkt->payload = (uint8_t *)payload;
1161  coap_pkt->payload_len = MIN(COAP_MAX_CHUNK_SIZE, length);
1162 
1163  return coap_pkt->payload_len;
1164 }
1165 /*---------------------------------------------------------------------------*/
1166 /** @} */
Log support for CoAP
static uint8_t accept(uint8_t in)
Definition: mpl.c:1391
static uint8_t output(const linkaddr_t *localdest)
Take an IP packet and format it to be sent on an 802.15.4 network using 6lowpan.
Definition: sicslowpan.c:1576
static void start(void)
Start measurement.
CoAP module for reliable transport
An implementation of the Constrained Application Protocol (RFC 7252).
Default definitions of C compiler quirk work-arounds.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58