libcoap  4.3.0
option.c
Go to the documentation of this file.
1 /*
2  * option.c -- helpers for handling options in CoAP PDUs
3  *
4  * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * SPDX-License-Identifier: BSD-2-Clause
7  *
8  * This file is part of the CoAP library libcoap. Please see
9  * README for terms of use.
10  */
11 
12 
13 #include "coap3/coap_internal.h"
14 
15 #include <stdio.h>
16 #include <string.h>
17 
18 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
19  coap_log(LOG_DEBUG, "cannot advance opt past end\n"); \
20  return 0; \
21  } else { \
22  (e) -= step; \
23  (o) = ((o)) + step; \
24  }
25 
26 /*
27  * Used to prevent access to *opt when pointing to after end of buffer
28  * after doing a ADVANCE_OPT()
29  */
30 #define ADVANCE_OPT_CHECK(o,e,step) do { \
31  ADVANCE_OPT(o,e,step); \
32  if ((e) < 1) \
33  return 0; \
34  } while (0)
35 
36 size_t
37 coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
38 
39  const coap_opt_t *opt_start = opt; /* store where parsing starts */
40 
41  assert(opt); assert(result);
42 
43  if (length < 1)
44  return 0;
45 
46  result->delta = (*opt & 0xf0) >> 4;
47  result->length = *opt & 0x0f;
48 
49  switch(result->delta) {
50  case 15:
51  if (*opt != COAP_PAYLOAD_START) {
52  coap_log(LOG_DEBUG, "ignored reserved option delta 15\n");
53  }
54  return 0;
55  case 14:
56  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
57  * After that, the option pointer is advanced to the LSB which is handled
58  * just like case delta == 13. */
59  ADVANCE_OPT_CHECK(opt,length,1);
60  result->delta = ((*opt & 0xff) << 8) + 269;
61  if (result->delta < 269) {
62  coap_log(LOG_DEBUG, "delta too large\n");
63  return 0;
64  }
65  /* fall through */
66  case 13:
67  ADVANCE_OPT_CHECK(opt,length,1);
68  result->delta += *opt & 0xff;
69  break;
70 
71  default:
72  ;
73  }
74 
75  switch(result->length) {
76  case 15:
77  coap_log(LOG_DEBUG, "found reserved option length 15\n");
78  return 0;
79  case 14:
80  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
81  * After that, the option pointer is advanced to the LSB which is handled
82  * just like case delta == 13. */
83  ADVANCE_OPT_CHECK(opt,length,1);
84  result->length = ((*opt & 0xff) << 8) + 269;
85  /* fall through */
86  case 13:
87  ADVANCE_OPT_CHECK(opt,length,1);
88  result->length += *opt & 0xff;
89  break;
90 
91  default:
92  ;
93  }
94 
95  /* ADVANCE_OPT() is correct here */
96  ADVANCE_OPT(opt,length,1);
97  /* opt now points to value, if present */
98 
99  result->value = opt;
100  if (length < result->length) {
101  coap_log(LOG_DEBUG, "invalid option length\n");
102  return 0;
103  }
104 
105 #undef ADVANCE_OPT
106 #undef ADVANCE_OPT_CHECK
107 
108  return (opt + result->length) - opt_start;
109 }
110 
113  const coap_opt_filter_t *filter) {
114  assert(pdu);
115  assert(pdu->token);
116  assert(oi);
117 
118  memset(oi, 0, sizeof(coap_opt_iterator_t));
119 
120  oi->next_option = pdu->token + pdu->token_length;
121  if (pdu->token + pdu->used_size <= oi->next_option) {
122  oi->bad = 1;
123  return NULL;
124  }
125 
126  oi->length = pdu->used_size - pdu->token_length;
127 
128  if (filter) {
129  memcpy(&oi->filter, filter, sizeof(coap_opt_filter_t));
130  oi->filtered = 1;
131  }
132  return oi;
133 }
134 
137  assert(oi);
138 
139  if (oi->bad || oi->length == 0 ||
140  !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
141  oi->bad = 1;
142  }
143 
144  return oi->bad;
145 }
146 
147 coap_opt_t *
149  coap_option_t option;
150  coap_opt_t *current_opt = NULL;
151  size_t optsize;
152  int b; /* to store result of coap_option_getb() */
153 
154  assert(oi);
155 
156  if (opt_finished(oi))
157  return NULL;
158 
159  while (1) {
160  /* oi->option always points to the next option to deliver; as
161  * opt_finished() filters out any bad conditions, we can assume that
162  * oi->option is valid. */
163  current_opt = oi->next_option;
164 
165  /* Advance internal pointer to next option, skipping any option that
166  * is not included in oi->filter. */
167  optsize = coap_opt_parse(oi->next_option, oi->length, &option);
168  if (optsize) {
169  assert(optsize <= oi->length);
170 
171  oi->next_option += optsize;
172  oi->length -= optsize;
173 
174  oi->number += option.delta;
175  } else { /* current option is malformed */
176  oi->bad = 1;
177  return NULL;
178  }
179 
180  /* Exit the while loop when:
181  * - no filtering is done at all
182  * - the filter matches for the current option
183  * - the filter is too small for the current option number
184  */
185  if (!oi->filtered ||
186  (b = coap_option_filter_get(&oi->filter, oi->number)) > 0)
187  break;
188  else if (b < 0) { /* filter too small, cannot proceed */
189  oi->bad = 1;
190  return NULL;
191  }
192  }
193 
194  return current_opt;
195 }
196 
197 coap_opt_t *
199  coap_opt_iterator_t *oi) {
201 
203  coap_option_filter_set(&f, number);
204 
205  coap_option_iterator_init(pdu, oi, &f);
206 
207  return coap_option_next(oi);
208 }
209 
210 uint32_t
212  uint32_t length;
213 
214  length = *opt & 0x0f;
215  switch (*opt & 0xf0) {
216  case 0xf0:
217  coap_log(LOG_DEBUG, "illegal option delta\n");
218  return 0;
219  case 0xe0:
220  ++opt;
221  /* fall through */
222  /* to skip another byte */
223  case 0xd0:
224  ++opt;
225  /* fall through */
226  /* to skip another byte */
227  default:
228  ++opt;
229  }
230 
231  switch (length) {
232  case 0x0f:
233  coap_log(LOG_DEBUG, "illegal option length\n");
234  return 0;
235  case 0x0e:
236  length = (*opt++ << 8) + 269;
237  /* fall through */
238  case 0x0d:
239  length += *opt++;
240  break;
241  default:
242  ;
243  }
244  return length;
245 }
246 
247 const uint8_t *
249  size_t ofs = 1;
250 
251  switch (*opt & 0xf0) {
252  case 0xf0:
253  coap_log(LOG_DEBUG, "illegal option delta\n");
254  return 0;
255  case 0xe0:
256  ++ofs;
257  /* fall through */
258  case 0xd0:
259  ++ofs;
260  break;
261  default:
262  ;
263  }
264 
265  switch (*opt & 0x0f) {
266  case 0x0f:
267  coap_log(LOG_DEBUG, "illegal option length\n");
268  return 0;
269  case 0x0e:
270  ++ofs;
271  /* fall through */
272  case 0x0d:
273  ++ofs;
274  break;
275  default:
276  ;
277  }
278 
279  return (const uint8_t *)opt + ofs;
280 }
281 
282 size_t
284  coap_option_t option;
285 
286  /* we must assume that opt is encoded correctly */
287  return coap_opt_parse(opt, (size_t)-1, &option);
288 }
289 
290 size_t
291 coap_opt_setheader(coap_opt_t *opt, size_t maxlen,
292  uint16_t delta, size_t length) {
293  size_t skip = 0;
294 
295  assert(opt);
296 
297  if (maxlen == 0) /* need at least one byte */
298  return 0;
299 
300  if (delta < 13) {
301  opt[0] = (coap_opt_t)(delta << 4);
302  } else if (delta < 269) {
303  if (maxlen < 2) {
304  coap_log(LOG_DEBUG, "insufficient space to encode option delta %d\n",
305  delta);
306  return 0;
307  }
308 
309  opt[0] = 0xd0;
310  opt[++skip] = (coap_opt_t)(delta - 13);
311  } else {
312  if (maxlen < 3) {
313  coap_log(LOG_DEBUG, "insufficient space to encode option delta %d\n",
314  delta);
315  return 0;
316  }
317 
318  opt[0] = 0xe0;
319  opt[++skip] = ((delta - 269) >> 8) & 0xff;
320  opt[++skip] = (delta - 269) & 0xff;
321  }
322 
323  if (length < 13) {
324  opt[0] |= length & 0x0f;
325  } else if (length < 269) {
326  if (maxlen < skip + 2) {
327  coap_log(LOG_DEBUG, "insufficient space to encode option length %zu\n",
328  length);
329  return 0;
330  }
331 
332  opt[0] |= 0x0d;
333  opt[++skip] = (coap_opt_t)(length - 13);
334  } else {
335  if (maxlen < skip + 3) {
336  coap_log(LOG_DEBUG, "insufficient space to encode option delta %d\n",
337  delta);
338  return 0;
339  }
340 
341  opt[0] |= 0x0e;
342  opt[++skip] = ((length - 269) >> 8) & 0xff;
343  opt[++skip] = (length - 269) & 0xff;
344  }
345 
346  return skip + 1;
347 }
348 
349 size_t
350 coap_opt_encode_size(uint16_t delta, size_t length) {
351  size_t n = 1;
352 
353  if (delta >= 13) {
354  if (delta < 269)
355  n += 1;
356  else
357  n += 2;
358  }
359 
360  if (length >= 13) {
361  if (length < 269)
362  n += 1;
363  else
364  n += 2;
365  }
366 
367  return n + length;
368 }
369 
370 size_t
371 coap_opt_encode(coap_opt_t *opt, size_t maxlen, uint16_t delta,
372  const uint8_t *val, size_t length) {
373  size_t l = 1;
374 
375  l = coap_opt_setheader(opt, maxlen, delta, length);
376  assert(l <= maxlen);
377 
378  if (!l) {
379  coap_log(LOG_DEBUG, "coap_opt_encode: cannot set option header\n");
380  return 0;
381  }
382 
383  maxlen -= l;
384  opt += l;
385 
386  if (maxlen < length) {
387  coap_log(LOG_DEBUG, "coap_opt_encode: option too large for buffer\n");
388  return 0;
389  }
390 
391  if (val) /* better be safe here */
392  memcpy(opt, val, length);
393 
394  return l + length;
395 }
396 
397 #define LONG_MASK ((1 << COAP_OPT_FILTER_LONG) - 1)
398 #define SHORT_MASK \
399  (~LONG_MASK & ((1 << (COAP_OPT_FILTER_LONG + COAP_OPT_FILTER_SHORT)) - 1))
400 
403 is_long_option(coap_option_num_t number) { return number > 255; }
404 
407 
427 static int
429  coap_option_num_t number,
430  enum filter_op_t op) {
431  size_t lindex = 0;
432  coap_opt_filter_t *of = filter;
433  uint16_t nr, mask = 0;
434 
435  if (is_long_option(number)) {
436  mask = LONG_MASK;
437 
438  for (nr = 1; lindex < COAP_OPT_FILTER_LONG; nr <<= 1, lindex++) {
439 
440  if (((of->mask & nr) > 0) && (of->long_opts[lindex] == number)) {
441  if (op == FILTER_CLEAR) {
442  of->mask &= ~nr;
443  }
444 
445  return 1;
446  }
447  }
448  } else {
449  mask = SHORT_MASK;
450 
451  for (nr = 1 << COAP_OPT_FILTER_LONG; lindex < COAP_OPT_FILTER_SHORT;
452  nr <<= 1, lindex++) {
453 
454  if (((of->mask & nr) > 0) && (of->short_opts[lindex] == (number & 0xff))) {
455  if (op == FILTER_CLEAR) {
456  of->mask &= ~nr;
457  }
458 
459  return 1;
460  }
461  }
462  }
463 
464  /* number was not found, so there is nothing to do if op is CLEAR or GET */
465  if ((op == FILTER_CLEAR) || (op == FILTER_GET)) {
466  return 0;
467  }
468 
469  /* handle FILTER_SET: */
470 
471  lindex = coap_fls(~of->mask & mask);
472  if (!lindex) {
473  return 0;
474  }
475 
476  if (is_long_option(number)) {
477  of->long_opts[lindex - 1] = number;
478  } else {
479  of->short_opts[lindex - COAP_OPT_FILTER_LONG - 1] = (uint8_t)number;
480  }
481 
482  of->mask |= 1 << (lindex - 1);
483 
484  return 1;
485 }
486 
487 void
489  memset(filter, 0, sizeof(coap_opt_filter_t));
490 }
491 
492 int
494  return coap_option_filter_op(filter, option, FILTER_SET);
495 }
496 
497 int
499  return coap_option_filter_op(filter, option, FILTER_CLEAR);
500 }
501 
502 int
504  return coap_option_filter_op(filter, option, FILTER_GET);
505 }
506 
508 coap_new_optlist(uint16_t number,
509  size_t length,
510  const uint8_t *data
511 ) {
512  coap_optlist_t *node;
513 
514 #ifdef WITH_LWIP
515  if (length > MEMP_LEN_COAPOPTLIST) {
517  "coap_new_optlist: size too large (%zu > MEMP_LEN_COAPOPTLIST)\n",
518  length);
519  return NULL;
520  }
521 #endif /* WITH_LWIP */
522  node = coap_malloc_type(COAP_OPTLIST, sizeof(coap_optlist_t) + length);
523 
524  if (node) {
525  memset(node, 0, (sizeof(coap_optlist_t) + length));
526  node->number = number;
527  node->length = length;
528  node->data = (uint8_t *)&node[1];
529  memcpy(node->data, data, length);
530  } else {
531  coap_log(LOG_WARNING, "coap_new_optlist: malloc failure\n");
532  }
533 
534  return node;
535 }
536 
537 static int
538 order_opts(void *a, void *b) {
539  coap_optlist_t *o1 = (coap_optlist_t *)a;
540  coap_optlist_t *o2 = (coap_optlist_t *)b;
541 
542  if (!a || !b)
543  return a < b ? -1 : 1;
544 
545  return (int)(o1->number - o2->number);
546 }
547 
548 int
550  coap_optlist_t *opt;
551 
552  if (options && *options) {
553  /* sort options for delta encoding */
554  LL_SORT((*options), order_opts);
555 
556  LL_FOREACH((*options), opt) {
557  coap_add_option(pdu, opt->number, opt->length, opt->data);
558  }
559  return 1;
560  }
561  return 0;
562 }
563 
564 int
566  if (!node) {
567  coap_log(LOG_DEBUG, "optlist not provided\n");
568  } else {
569  /* must append at the list end to avoid re-ordering of
570  * options during sort */
571  LL_APPEND((*head), node);
572  }
573 
574  return node != NULL;
575 }
576 
577 static int
579  if (node) {
581  }
582  return 1;
583 }
584 
585 void
587  coap_optlist_t *elt, *tmp;
588 
589  if (!queue)
590  return;
591 
592  LL_FOREACH_SAFE(queue, elt, tmp) {
594  }
595 }
596 
Pulls together all the internal only header files.
int coap_fls(unsigned int i)
Definition: encode.c:15
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:152
@ LOG_CRIT
Critical.
Definition: coap_debug.h:54
@ LOG_WARNING
Warning.
Definition: coap_debug.h:56
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:59
coap_optlist_t * coap_new_optlist(uint16_t number, size_t length, const uint8_t *data)
Create a new optlist entry.
Definition: option.c:508
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:148
size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, uint16_t delta, const uint8_t *val, size_t length)
Encodes option with given delta into opt.
Definition: option.c:371
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:211
void coap_delete_optlist(coap_optlist_t *queue)
Removes all entries from the optlist_chain, freeing off their memory usage.
Definition: option.c:586
size_t coap_opt_encode_size(uint16_t delta, size_t length)
Compute storage bytes needed for an option with given delta and length.
Definition: option.c:350
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition: option.c:198
#define COAP_OPT_FILTER_SHORT
The number of option types below 256 that can be stored in an option filter.
Definition: option.h:77
int coap_option_filter_unset(coap_opt_filter_t *filter, coap_option_num_t option)
Clears the corresponding entry for number in filter.
Definition: option.c:498
int coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t **options)
The current optlist of optlist_chain is first sorted (as per RFC7272 ordering requirements) and then ...
Definition: option.c:549
#define COAP_OPT_FILTER_LONG
The number of option types above 255 that can be stored in an option filter.
Definition: option.h:85
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
Definition: option.c:488
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:248
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
Definition: option.c:112
int coap_insert_optlist(coap_optlist_t **head, coap_optlist_t *node)
Adds optlist to the given optlist_chain.
Definition: option.c:565
int coap_option_filter_get(coap_opt_filter_t *filter, coap_option_num_t option)
Checks if number is contained in filter.
Definition: option.c:503
int coap_option_filter_set(coap_opt_filter_t *filter, coap_option_num_t option)
Sets the corresponding entry for number in filter.
Definition: option.c:493
size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, uint16_t delta, size_t length)
Encodes the given delta and length values into opt.
Definition: option.c:291
#define COAP_PAYLOAD_START
size_t coap_add_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition: pdu.c:543
#define COAP_STATIC_INLINE
Definition: libcoap.h:40
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
@ COAP_OPTLIST
Definition: mem.h:47
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
const uint32_t n
Definition: murmur3.c:56
size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
Parses the option pointed to by opt into result.
Definition: option.c:37
filter_op_t
Operation specifiers for coap_filter_op().
Definition: option.c:406
@ FILTER_CLEAR
Definition: option.c:406
@ FILTER_GET
Definition: option.c:406
@ FILTER_SET
Definition: option.c:406
#define ADVANCE_OPT_CHECK(o, e, step)
Definition: option.c:30
#define SHORT_MASK
Definition: option.c:398
size_t coap_opt_size(const coap_opt_t *opt)
Returns the size of the given option, taking into account a possible option jump.
Definition: option.c:283
COAP_STATIC_INLINE int opt_finished(coap_opt_iterator_t *oi)
Definition: option.c:136
static int coap_internal_delete(coap_optlist_t *node)
Definition: option.c:578
#define ADVANCE_OPT(o, e, step)
Definition: option.c:18
static int coap_option_filter_op(coap_opt_filter_t *filter, coap_option_num_t number, enum filter_op_t op)
Applies op on filter with respect to number.
Definition: option.c:428
COAP_STATIC_INLINE int is_long_option(coap_option_num_t number)
Returns true iff number denotes an option number larger than 255.
Definition: option.c:403
static int order_opts(void *a, void *b)
Definition: option.c:538
#define LONG_MASK
Definition: option.c:397
uint16_t coap_option_num_t
Definition: option.h:20
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:26
uint16_t mask
Definition: option.h:101
uint8_t short_opts[COAP_OPT_FILTER_SHORT]
Definition: option.h:103
uint16_t long_opts[COAP_OPT_FILTER_LONG]
Definition: option.h:102
Iterator to run through PDU options.
Definition: option.h:170
coap_opt_t * next_option
pointer to the unparsed next option
Definition: option.h:175
coap_opt_filter_t filter
option filter
Definition: option.h:176
unsigned int bad
iterator object is ok if not set
Definition: option.h:173
size_t length
remaining length of PDU
Definition: option.h:171
unsigned int filtered
denotes whether or not filter is used
Definition: option.h:174
coap_option_num_t number
decoded option number
Definition: option.h:172
Representation of CoAP options.
Definition: option.h:32
const uint8_t * value
Definition: option.h:35
uint16_t delta
Definition: option.h:33
size_t length
Definition: option.h:34
Representation of chained list of CoAP options to install.
Definition: option.h:327
uint16_t number
the option number (no delta coding)
Definition: option.h:329
size_t length
the option value length
Definition: option.h:330
uint8_t * data
the option data
Definition: option.h:331
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
uint8_t * token
first byte of token, if any, or options
uint8_t token_length
length of Token
size_t used_size
used bytes of storage for token, options and payload