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