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