libcoap  4.2.0rc1
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 "debug.h"
24 #include "mem.h"
25 #include "utlist.h"
26 
27 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
28  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  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  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  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  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  warn("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  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  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  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  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  debug("insufficient space to encode option delta %d\n", delta);
343  return 0;
344  }
345 
346  opt[0] = 0xd0;
347  opt[++skip] = (coap_opt_t)(delta - 13);
348  } else {
349  if (maxlen < 3) {
350  debug("insufficient space to encode option delta %d\n", delta);
351  return 0;
352  }
353 
354  opt[0] = 0xe0;
355  opt[++skip] = ((delta - 269) >> 8) & 0xff;
356  opt[++skip] = (delta - 269) & 0xff;
357  }
358 
359  if (length < 13) {
360  opt[0] |= length & 0x0f;
361  } else if (length < 269) {
362  if (maxlen < skip + 2) {
363  debug("insufficient space to encode option length %zu\n", length);
364  return 0;
365  }
366 
367  opt[0] |= 0x0d;
368  opt[++skip] = (coap_opt_t)(length - 13);
369  } else {
370  if (maxlen < skip + 3) {
371  debug("insufficient space to encode option delta %d\n", delta);
372  return 0;
373  }
374 
375  opt[0] |= 0x0e;
376  opt[++skip] = ((length - 269) >> 8) & 0xff;
377  opt[++skip] = (length - 269) & 0xff;
378  }
379 
380  return skip + 1;
381 }
382 
383 size_t
384 coap_opt_encode_size(uint16_t delta, size_t length) {
385  size_t n = 1;
386 
387  if (delta >= 13) {
388  if (delta < 269)
389  n += 1;
390  else
391  n += 2;
392  }
393 
394  if (length >= 13) {
395  if (length < 269)
396  n += 1;
397  else
398  n += 2;
399  }
400 
401  return n + length;
402 }
403 
404 size_t
405 coap_opt_encode(coap_opt_t *opt, size_t maxlen, uint16_t delta,
406  const uint8_t *val, size_t length) {
407  size_t l = 1;
408 
409  l = coap_opt_setheader(opt, maxlen, delta, length);
410  assert(l <= maxlen);
411 
412  if (!l) {
413  debug("coap_opt_encode: cannot set option header\n");
414  return 0;
415  }
416 
417  maxlen -= l;
418  opt += l;
419 
420  if (maxlen < length) {
421  debug("coap_opt_encode: option too large for buffer\n");
422  return 0;
423  }
424 
425  if (val) /* better be safe here */
426  memcpy(opt, val, length);
427 
428  return l + length;
429 }
430 
431 /* coap_opt_filter_t has the following internal structure: */
432 typedef struct {
433  uint16_t mask;
434 
435 #define LONG_MASK ((1 << COAP_OPT_FILTER_LONG) - 1)
436 #define SHORT_MASK \
437  (~LONG_MASK & ((1 << (COAP_OPT_FILTER_LONG + COAP_OPT_FILTER_SHORT)) - 1))
438 
439  uint16_t long_opts[COAP_OPT_FILTER_LONG];
441 } opt_filter;
442 
445 is_long_option(uint16_t type) { return type > 255; }
446 
449 
469 static int
471  uint16_t type,
472  enum filter_op_t op) {
473  size_t lindex = 0;
474  opt_filter *of = (opt_filter *)filter;
475  uint16_t nr, mask = 0;
476 
477  if (is_long_option(type)) {
478  mask = LONG_MASK;
479 
480  for (nr = 1; lindex < COAP_OPT_FILTER_LONG; nr <<= 1, lindex++) {
481 
482  if (((of->mask & nr) > 0) && (of->long_opts[lindex] == type)) {
483  if (op == FILTER_CLEAR) {
484  of->mask &= ~nr;
485  }
486 
487  return 1;
488  }
489  }
490  } else {
491  mask = SHORT_MASK;
492 
493  for (nr = 1 << COAP_OPT_FILTER_LONG; lindex < COAP_OPT_FILTER_SHORT;
494  nr <<= 1, lindex++) {
495 
496  if (((of->mask & nr) > 0) && (of->short_opts[lindex] == (type & 0xff))) {
497  if (op == FILTER_CLEAR) {
498  of->mask &= ~nr;
499  }
500 
501  return 1;
502  }
503  }
504  }
505 
506  /* type was not found, so there is nothing to do if op is CLEAR or GET */
507  if ((op == FILTER_CLEAR) || (op == FILTER_GET)) {
508  return 0;
509  }
510 
511  /* handle FILTER_SET: */
512 
513  lindex = coap_fls(~of->mask & mask);
514  if (!lindex) {
515  return 0;
516  }
517 
518  if (is_long_option(type)) {
519  of->long_opts[lindex - 1] = type;
520  } else {
521  of->short_opts[lindex - COAP_OPT_FILTER_LONG - 1] = (uint8_t)type;
522  }
523 
524  of->mask |= 1 << (lindex - 1);
525 
526  return 1;
527 }
528 
529 int
531  return coap_option_filter_op(filter, type, FILTER_SET);
532 }
533 
534 int
536  return coap_option_filter_op(filter, type, FILTER_CLEAR);
537 }
538 
539 int
541  /* Ugly cast to make the const go away (FILTER_GET wont change filter
542  * but as _set and _unset do, the function does not take a const). */
543  return coap_option_filter_op((uint16_t *)filter, type, FILTER_GET);
544 }
545 
547 coap_new_optlist(uint16_t number,
548  size_t length,
549  const uint8_t *data
550 ) {
551  coap_optlist_t *node;
552 
553  node = coap_malloc_type(COAP_OPTLIST, sizeof(coap_optlist_t) + length);
554 
555  if (node) {
556  node->number = number;
557  node->length = length;
558  node->data = (uint8_t *)&node[1];
559  memcpy(node->data, data, length);
560  } else {
561  coap_log(LOG_WARNING, "coap_new_optlist: malloc failure\n");
562  }
563 
564  return node;
565 }
566 
567 static int
568 order_opts(void *a, void *b) {
569  coap_optlist_t *o1 = (coap_optlist_t *)a;
570  coap_optlist_t *o2 = (coap_optlist_t *)b;
571 
572  if (!a || !b)
573  return a < b ? -1 : 1;
574 
575  return (int)(o1->number - o2->number);
576 }
577 
578 int
580  coap_optlist_t *opt;
581 
582  if (options && *options) {
583  /* sort options for delta encoding */
584  LL_SORT((*options), order_opts);
585 
586  LL_FOREACH((*options), opt) {
587  coap_add_option(pdu, opt->number, opt->length, opt->data);
588  }
589  return 1;
590  }
591  return 0;
592 }
593 
594 int
596  if (!node) {
597  coap_log(LOG_DEBUG, "optlist not provided\n");
598  } else {
599  /* must append at the list end to avoid re-ordering of
600  * options during sort */
601  LL_APPEND((*head), node);
602  }
603 
604  return node != NULL;
605 }
606 
607 static int
609  if (node) {
611  }
612  return 1;
613 }
614 
615 void
617  coap_optlist_t *elt, *tmp;
618 
619  if (!queue)
620  return;
621 
622  LL_FOREACH_SAFE(queue, elt, tmp) {
624  }
625 }
626 
#define LONG_MASK
Definition: option.c:435
#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:433
#define SHORT_MASK
Definition: option.c:436
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:595
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:608
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:530
filter_op_t
Operation specifiers for coap_filter_op().
Definition: option.c:448
Debug.
Definition: 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:616
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:384
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:540
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: 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:535
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:470
size_t coap_add_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
de-duplicate code with coap_add_option_later
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
#define warn(...)
Obsoleted.
Definition: debug.h:138
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:445
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:405
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
#define debug(...)
Obsoleted.
Definition: debug.h:143
uint16_t long_opts[COAP_OPT_FILTER_LONG]
Definition: option.c:439
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:579
uint8_t short_opts[COAP_OPT_FILTER_SHORT]
Definition: option.c:440
static int order_opts(void *a, void *b)
Definition: option.c:568
#define coap_log(level,...)
Logging function.
Definition: 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:547
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