libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
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 "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 "debug.h"
22 
23 coap_opt_t *
25 
26  if (pdu && pdu->hdr &&
27  (pdu->hdr->token + pdu->hdr->token_length
28  < (unsigned char *)pdu->hdr + pdu->length)) {
29 
30  coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
31  return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
32 
33  } else
34  return NULL;
35 }
36 
37 size_t
38 coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
39 
40  const coap_opt_t *opt_start = opt; /* store where parsing starts */
41 
42  assert(opt); assert(result);
43 
44 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
45  debug("cannot advance opt past end\n"); \
46  return 0; \
47  } else { \
48  (e) -= step; \
49  (o) = ((unsigned char *)(o)) + step; \
50  }
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  return 0;
63  case 14:
64  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
65  * After that, the option pointer is advanced to the LSB which is handled
66  * just like case delta == 13. */
67  ADVANCE_OPT(opt,length,1);
68  result->delta = ((*opt & 0xff) << 8) + 269;
69  if (result->delta < 269) {
70  debug("delta too large\n");
71  return 0;
72  }
73  /* fall through */
74  case 13:
75  ADVANCE_OPT(opt,length,1);
76  result->delta += *opt & 0xff;
77  break;
78 
79  default:
80  ;
81  }
82 
83  switch(result->length) {
84  case 15:
85  debug("found reserved option length 15\n");
86  return 0;
87  case 14:
88  /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
89  * After that, the option pointer is advanced to the LSB which is handled
90  * just like case delta == 13. */
91  ADVANCE_OPT(opt,length,1);
92  result->length = ((*opt & 0xff) << 8) + 269;
93  /* fall through */
94  case 13:
95  ADVANCE_OPT(opt,length,1);
96  result->length += *opt & 0xff;
97  break;
98 
99  default:
100  ;
101  }
102 
103  ADVANCE_OPT(opt,length,1);
104  /* opt now points to value, if present */
105 
106  result->value = (unsigned char *)opt;
107  if (length < result->length) {
108  debug("invalid option length\n");
109  return 0;
110  }
111 
112 #undef ADVANCE_OPT
113 
114  return (opt + result->length) - opt_start;
115 }
116 
119  const coap_opt_filter_t filter) {
120  assert(pdu);
121  assert(pdu->hdr);
122  assert(oi);
123 
124  memset(oi, 0, sizeof(coap_opt_iterator_t));
125 
126  oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
127  + pdu->hdr->token_length;
128  if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
129  oi->bad = 1;
130  return NULL;
131  }
132 
133  assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
134 
135  oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->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 
144 static inline int
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, unsigned char 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 unsigned short
221  unsigned short 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 unsigned short
250  unsigned short 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 to skip another byte */
260  case 0xd0:
261  ++opt;
262  /* fall through to skip another byte */
263  default:
264  ++opt;
265  }
266 
267  switch (length) {
268  case 0x0f:
269  debug("illegal option length\n");
270  return 0;
271  case 0x0e:
272  length = (*opt++ << 8) + 269;
273  /* fall through */
274  case 0x0d:
275  length += *opt++;
276  break;
277  default:
278  ;
279  }
280  return length;
281 }
282 
283 unsigned char *
285  size_t ofs = 1;
286 
287  switch (*opt & 0xf0) {
288  case 0xf0:
289  debug("illegal option delta\n");
290  return 0;
291  case 0xe0:
292  ++ofs;
293  /* fall through */
294  case 0xd0:
295  ++ofs;
296  break;
297  default:
298  ;
299  }
300 
301  switch (*opt & 0x0f) {
302  case 0x0f:
303  debug("illegal option length\n");
304  return 0;
305  case 0x0e:
306  ++ofs;
307  /* fall through */
308  case 0x0d:
309  ++ofs;
310  break;
311  default:
312  ;
313  }
314 
315  return (unsigned char *)opt + ofs;
316 }
317 
318 size_t
320  coap_option_t option;
321 
322  /* we must assume that opt is encoded correctly */
323  return coap_opt_parse(opt, (size_t)-1, &option);
324 }
325 
326 size_t
327 coap_opt_setheader(coap_opt_t *opt, size_t maxlen,
328  unsigned short delta, size_t length) {
329  size_t skip = 0;
330 
331  assert(opt);
332 
333  if (maxlen == 0) /* need at least one byte */
334  return 0;
335 
336  if (delta < 13) {
337  opt[0] = delta << 4;
338  } else if (delta < 270) {
339  if (maxlen < 2) {
340  debug("insufficient space to encode option delta %d", delta);
341  return 0;
342  }
343 
344  opt[0] = 0xd0;
345  opt[++skip] = delta - 13;
346  } else {
347  if (maxlen < 3) {
348  debug("insufficient space to encode option delta %d", delta);
349  return 0;
350  }
351 
352  opt[0] = 0xe0;
353  opt[++skip] = ((delta - 269) >> 8) & 0xff;
354  opt[++skip] = (delta - 269) & 0xff;
355  }
356 
357  if (length < 13) {
358  opt[0] |= length & 0x0f;
359  } else if (length < 270) {
360  if (maxlen < skip + 1) {
361  debug("insufficient space to encode option length %d", length);
362  return 0;
363  }
364 
365  opt[0] |= 0x0d;
366  opt[++skip] = length - 13;
367  } else {
368  if (maxlen < skip + 2) {
369  debug("insufficient space to encode option delta %d", delta);
370  return 0;
371  }
372 
373  opt[0] |= 0x0e;
374  opt[++skip] = ((length - 269) >> 8) & 0xff;
375  opt[++skip] = (length - 269) & 0xff;
376  }
377 
378  return skip + 1;
379 }
380 
381 size_t
382 coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
383  const unsigned char *val, size_t length) {
384  size_t l = 1;
385 
386  l = coap_opt_setheader(opt, maxlen, delta, length);
387  assert(l <= maxlen);
388 
389  if (!l) {
390  debug("coap_opt_encode: cannot set option header\n");
391  return 0;
392  }
393 
394  maxlen -= l;
395  opt += l;
396 
397  if (maxlen < length) {
398  debug("coap_opt_encode: option too large for buffer\n");
399  return 0;
400  }
401 
402  if (val) /* better be safe here */
403  memcpy(opt, val, length);
404 
405  return l + length;
406 }
407 
unsigned char token[]
Definition: pdu.h:174
#define warn(...)
Definition: debug.h:54
unsigned short delta
Definition: option.h:31
unsigned char * coap_opt_value(coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:284
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:211
coap_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
Definition: option.c:207
size_t length
remaining length of PDU
Definition: option.h:170
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:149
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:175
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:119
coap_hdr_t * hdr
Definition: pdu.h:209
static int opt_finished(coap_opt_iterator_t *oi)
Definition: option.c:145
#define debug(...)
Definition: debug.h:55
Header structure for CoAP PDUs.
Definition: pdu.h:206
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's option list...
Definition: option.c:118
size_t length
Definition: option.h:32
Representation of CoAP options.
Definition: option.h:30
coap_opt_t * next_option
pointer to the unparsed next option
Definition: option.h:174
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:38
unsigned short coap_opt_delta(const coap_opt_t *opt)
Decodes the delta value of the next option.
Definition: option.c:220
Iterator to run through PDU options.
Definition: option.h:169
unsigned int bad
iterator object is ok if not set
Definition: option.h:172
unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3)+1]
Fixed-size bit-vector we use for option filtering.
Definition: option.h:93
unsigned int filtered
denotes whether or not filter is used
Definition: option.h:173
unsigned short type
decoded option type
Definition: option.h:171
static void coap_option_filter_clear(coap_opt_filter_t f)
Clears filter f.
Definition: option.h:104
#define COAP_PAYLOAD_START
Definition: pdu.h:188
#define ADVANCE_OPT(o, e, step)
unsigned int token_length
Definition: pdu.h:169
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:327
coap_opt_t * options_start(coap_pdu_t *pdu)
Calculates the beginning of the PDU's option section.
Definition: option.c:24
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:26
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:319
unsigned char * value
Definition: option.h:33
unsigned short coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:249
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:382