libcoap  4.1.2
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 "option.h"
21 #include "encode.h" /* for coap_fls() */
22 #include "debug.h"
23 
24 coap_opt_t *
26 
27  if (pdu && pdu->hdr &&
28  (pdu->hdr->token + pdu->hdr->token_length
29  < (unsigned char *)pdu->hdr + pdu->length)) {
30 
31  coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
32  return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
33 
34  } else
35  return NULL;
36 }
37 
38 size_t
39 coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
40 
41  const coap_opt_t *opt_start = opt; /* store where parsing starts */
42 
43  assert(opt); assert(result);
44 
45 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
46  debug("cannot advance opt past end\n"); \
47  return 0; \
48  } else { \
49  (e) -= step; \
50  (o) = ((unsigned char *)(o)) + step; \
51  }
52 
53  if (length < 1)
54  return 0;
55 
56  result->delta = (*opt & 0xf0) >> 4;
57  result->length = *opt & 0x0f;
58 
59  switch(result->delta) {
60  case 15:
61  if (*opt != COAP_PAYLOAD_START) {
62  debug("ignored reserved option delta 15\n");
63  }
64  return 0;
65  case 14:
66  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
67  * After that, the option pointer is advanced to the LSB which is handled
68  * just like case delta == 13. */
69  ADVANCE_OPT(opt,length,1);
70  result->delta = ((*opt & 0xff) << 8) + 269;
71  if (result->delta < 269) {
72  debug("delta too large\n");
73  return 0;
74  }
75  /* fall through */
76  case 13:
77  ADVANCE_OPT(opt,length,1);
78  result->delta += *opt & 0xff;
79  break;
80 
81  default:
82  ;
83  }
84 
85  switch(result->length) {
86  case 15:
87  debug("found reserved option length 15\n");
88  return 0;
89  case 14:
90  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
91  * After that, the option pointer is advanced to the LSB which is handled
92  * just like case delta == 13. */
93  ADVANCE_OPT(opt,length,1);
94  result->length = ((*opt & 0xff) << 8) + 269;
95  /* fall through */
96  case 13:
97  ADVANCE_OPT(opt,length,1);
98  result->length += *opt & 0xff;
99  break;
100 
101  default:
102  ;
103  }
104 
105  ADVANCE_OPT(opt,length,1);
106  /* opt now points to value, if present */
107 
108  result->value = (unsigned char *)opt;
109  if (length < result->length) {
110  debug("invalid option length\n");
111  return 0;
112  }
113 
114 #undef ADVANCE_OPT
115 
116  return (opt + result->length) - opt_start;
117 }
118 
121  const coap_opt_filter_t filter) {
122  assert(pdu);
123  assert(pdu->hdr);
124  assert(oi);
125 
126  memset(oi, 0, sizeof(coap_opt_iterator_t));
127 
128  oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
129  + pdu->hdr->token_length;
130  if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
131  oi->bad = 1;
132  return NULL;
133  }
134 
135  assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
136 
137  oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
138 
139  if (filter) {
140  memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
141  oi->filtered = 1;
142  }
143  return oi;
144 }
145 
146 static inline int
148  assert(oi);
149 
150  if (oi->bad || oi->length == 0 ||
151  !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
152  oi->bad = 1;
153  }
154 
155  return oi->bad;
156 }
157 
158 coap_opt_t *
160  coap_option_t option;
161  coap_opt_t *current_opt = NULL;
162  size_t optsize;
163  int b; /* to store result of coap_option_getb() */
164 
165  assert(oi);
166 
167  if (opt_finished(oi))
168  return NULL;
169 
170  while (1) {
171  /* oi->option always points to the next option to deliver; as
172  * opt_finished() filters out any bad conditions, we can assume that
173  * oi->option is valid. */
174  current_opt = oi->next_option;
175 
176  /* Advance internal pointer to next option, skipping any option that
177  * is not included in oi->filter. */
178  optsize = coap_opt_parse(oi->next_option, oi->length, &option);
179  if (optsize) {
180  assert(optsize <= oi->length);
181 
182  oi->next_option += optsize;
183  oi->length -= optsize;
184 
185  oi->type += option.delta;
186  } else { /* current option is malformed */
187  oi->bad = 1;
188  return NULL;
189  }
190 
191  /* Exit the while loop when:
192  * - no filtering is done at all
193  * - the filter matches for the current option
194  * - the filter is too small for the current option number
195  */
196  if (!oi->filtered ||
197  (b = coap_option_getb(oi->filter, oi->type)) > 0)
198  break;
199  else if (b < 0) { /* filter too small, cannot proceed */
200  oi->bad = 1;
201  return NULL;
202  }
203  }
204 
205  return current_opt;
206 }
207 
208 coap_opt_t *
209 coap_check_option(coap_pdu_t *pdu, unsigned short type,
210  coap_opt_iterator_t *oi) {
212 
214  coap_option_setb(f, type);
215 
216  coap_option_iterator_init(pdu, oi, f);
217 
218  return coap_option_next(oi);
219 }
220 
221 unsigned short
223  unsigned short n;
224 
225  n = (*opt++ & 0xf0) >> 4;
226 
227  switch (n) {
228  case 15: /* error */
229  warn("coap_opt_delta: illegal option delta\n");
230 
231  /* This case usually should not happen, hence we do not have a
232  * proper way to indicate an error. */
233  return 0;
234  case 14:
235  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
236  * After that, the option pointer is advanced to the LSB which is handled
237  * just like case delta == 13. */
238  n = ((*opt++ & 0xff) << 8) + 269;
239  /* fall through */
240  case 13:
241  n += *opt & 0xff;
242  break;
243  default: /* n already contains the actual delta value */
244  ;
245  }
246 
247  return n;
248 }
249 
250 unsigned short
252  unsigned short length;
253 
254  length = *opt & 0x0f;
255  switch (*opt & 0xf0) {
256  case 0xf0:
257  debug("illegal option delta\n");
258  return 0;
259  case 0xe0:
260  ++opt;
261  /* fall through to skip another byte */
262  case 0xd0:
263  ++opt;
264  /* fall through 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 unsigned char *
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 (unsigned char *)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  unsigned short 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] = delta << 4;
340  } else if (delta < 270) {
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] = 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 < 270) {
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] = 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(coap_opt_t *opt, size_t maxlen, unsigned short delta,
385  const unsigned char *val, size_t length) {
386  size_t l = 1;
387 
388  l = coap_opt_setheader(opt, maxlen, delta, length);
389  assert(l <= maxlen);
390 
391  if (!l) {
392  debug("coap_opt_encode: cannot set option header\n");
393  return 0;
394  }
395 
396  maxlen -= l;
397  opt += l;
398 
399  if (maxlen < length) {
400  debug("coap_opt_encode: option too large for buffer\n");
401  return 0;
402  }
403 
404  if (val) /* better be safe here */
405  memcpy(opt, val, length);
406 
407  return l + length;
408 }
409 
410 /* coap_opt_filter_t has the following internal structure: */
411 typedef struct {
412  uint16_t mask;
413 
414 #define LONG_MASK ((1 << COAP_OPT_FILTER_LONG) - 1)
415 #define SHORT_MASK \
416  (~LONG_MASK & ((1 << (COAP_OPT_FILTER_LONG + COAP_OPT_FILTER_SHORT)) - 1))
417 
418  uint16_t long_opts[COAP_OPT_FILTER_LONG];
419  uint8_t short_opts[COAP_OPT_FILTER_SHORT];
420 } opt_filter;
421 
423 static inline int
424 is_long_option(unsigned short type) { return type > 255; }
425 
428 
448 static int
450  unsigned short type,
451  enum filter_op_t op) {
452  size_t index = 0;
453  opt_filter *of = (opt_filter *)filter;
454  uint16_t nr, mask = 0;
455 
456  if (is_long_option(type)) {
457  mask = LONG_MASK;
458 
459  for (nr = 1; index < COAP_OPT_FILTER_LONG; nr <<= 1, index++) {
460 
461  if (((of->mask & nr) > 0) && (of->long_opts[index] == type)) {
462  if (op == FILTER_CLEAR) {
463  of->mask &= ~nr;
464  }
465 
466  return 1;
467  }
468  }
469  } else {
470  mask = SHORT_MASK;
471 
472  for (nr = 1 << COAP_OPT_FILTER_LONG; index < COAP_OPT_FILTER_SHORT;
473  nr <<= 1, index++) {
474 
475  if (((of->mask & nr) > 0) && (of->short_opts[index] == (type & 0xff))) {
476  if (op == FILTER_CLEAR) {
477  of->mask &= ~nr;
478  }
479 
480  return 1;
481  }
482  }
483  }
484 
485  /* type was not found, so there is nothing to do if op is CLEAR or GET */
486  if ((op == FILTER_CLEAR) || (op == FILTER_GET)) {
487  return 0;
488  }
489 
490  /* handle FILTER_SET: */
491 
492  index = coap_fls(~of->mask & mask);
493  if (!index) {
494  return 0;
495  }
496 
497  if (is_long_option(type)) {
498  of->long_opts[index - 1] = type;
499  } else {
500  of->short_opts[index - COAP_OPT_FILTER_LONG - 1] = type;
501  }
502 
503  of->mask |= 1 << (index - 1);
504 
505  return 1;
506 }
507 
508 int
509 coap_option_filter_set(coap_opt_filter_t filter, unsigned short type) {
510  return coap_option_filter_op(filter, type, FILTER_SET);
511 }
512 
513 int
514 coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type) {
515  return coap_option_filter_op(filter, type, FILTER_CLEAR);
516 }
517 
518 int
519 coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type) {
520  /* Ugly cast to make the const go away (FILTER_GET wont change filter
521  * but as _set and _unset do, the function does not take a const). */
522  return coap_option_filter_op((uint16_t *)filter, type, FILTER_GET);
523 }
#define LONG_MASK
Definition: option.c:414
uint16_t mask
Definition: option.c:412
#define SHORT_MASK
Definition: option.c:415
unsigned char token[]
Definition: pdu.h:192
int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type)
Sets the corresponding entry for type in filter.
Definition: option.c:509
#define warn(...)
Definition: debug.h:65
unsigned short delta
Definition: option.h:30
#define COAP_OPT_FILTER_LONG
The number of option types above 255 that can be stored in an option filter.
Definition: option.h:100
unsigned char * coap_opt_value(coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:286
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:234
size_t length
remaining length of PDU
Definition: option.h:254
filter_op_t
Operation specifiers for coap_filter_op().
Definition: option.c:427
static int coap_option_getb(const coap_opt_filter_t filter, unsigned short type)
Gets the corresponding bit for type in filter.
Definition: option.h:233
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:159
static int coap_option_filter_op(coap_opt_filter_t filter, unsigned short type, enum filter_op_t op)
Applies op on filter with respect to type.
Definition: option.c:449
coap_opt_filter_t filter
option filter
Definition: option.h:259
int coap_fls(unsigned int i)
Definition: encode.c:17
Helpers for handling options in CoAP PDUs.
static int coap_option_setb(coap_opt_filter_t filter, unsigned short type)
Sets the corresponding bit for type in filter.
Definition: option.h:199
coap_hdr_t * hdr
Address of the first byte of the CoAP message.
Definition: pdu.h:229
static int opt_finished(coap_opt_iterator_t *oi)
Definition: option.c:147
#define COAP_OPT_FILTER_SHORT
The number of option types below 256 that can be stored in an option filter.
Definition: option.h:92
#define debug(...)
Definition: debug.h:66
Header structure for CoAP PDUs.
Definition: pdu.h:227
coap_opt_iterator_t * coap_option_iterator_init(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:120
size_t length
Definition: option.h:31
Representation of CoAP options.
Definition: option.h:29
#define assert(...)
Definition: mem.c:17
coap_opt_t * next_option
pointer to the unparsed next option
Definition: option.h:258
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:39
unsigned short coap_opt_delta(const coap_opt_t *opt)
Decodes the delta value of the next option.
Definition: option.c:222
Iterator to run through PDU options.
Definition: option.h:253
unsigned int bad
iterator object is ok if not set
Definition: option.h:256
unsigned int filtered
denotes whether or not filter is used
Definition: option.h:257
unsigned short type
decoded option type
Definition: option.h:255
uint16_t coap_opt_filter_t[COAP_OPT_FILTER_SIZE]
Fixed-size vector we use for option filtering.
Definition: option.h:135
static void coap_option_filter_clear(coap_opt_filter_t f)
Clears filter f.
Definition: option.h:146
#define COAP_PAYLOAD_START
Definition: pdu.h:207
#define ADVANCE_OPT(o, e, step)
unsigned int token_length
Definition: pdu.h:186
uint16_t long_opts[COAP_OPT_FILTER_LONG]
Definition: option.c:418
size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
Encodes the given delta and length values into opt.
Definition: option.c:329
uint8_t short_opts[COAP_OPT_FILTER_SHORT]
Definition: option.c:419
int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type)
Checks if type is contained in filter.
Definition: option.c:519
coap_opt_t * options_start(coap_pdu_t *pdu)
Calculates the beginning of the PDU&#39;s option section.
Definition: option.c:25
unsigned char 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_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned short type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
Definition: option.c:209
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
static int is_long_option(unsigned short type)
Returns true iff type denotes an option type larger than 255.
Definition: option.c:424
unsigned char * value
Definition: option.h:32
unsigned short coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:251
size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, const unsigned char *val, size_t length)
Encodes option with given delta into opt.
Definition: option.c:384
int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type)
Clears the corresponding entry for type in filter.
Definition: option.c:514