2 * option.c -- helpers for handling options in CoAP PDUs
4 * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
6 * This file is part of the CoAP library libcoap. Please see
7 * README for terms of use.
12 #if defined(HAVE_ASSERT_H) && !defined(assert)
24 options_start(coap_pdu_t *pdu)
28 && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *) pdu->hdr + pdu->length))
31 coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
32 return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
39 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
42 const coap_opt_t *opt_start = opt; /* store where parsing starts */
46 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
47 debug("cannot advance opt past end\n"); \
51 (o) = ((unsigned char *)(o)) + step; \
57 result->delta = (*opt & 0xf0) >> 4;
58 result->length = *opt & 0x0f;
60 switch (result->delta)
63 if (*opt != COAP_PAYLOAD_START)
64 debug("ignored reserved option delta 15\n");
67 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
68 * After that, the option pointer is advanced to the LSB which is handled
69 * just like case delta == 13. */
70 ADVANCE_OPT(opt, length, 1);
71 result->delta = ((*opt & 0xff) << 8) + 269;
72 if (result->delta < 269)
74 debug("delta too large\n");
79 ADVANCE_OPT(opt, length, 1);
80 result->delta += *opt & 0xff;
87 switch (result->length)
90 debug("found reserved option length 15\n");
93 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
94 * After that, the option pointer is advanced to the LSB which is handled
95 * just like case delta == 13. */
96 ADVANCE_OPT(opt, length, 1);
97 result->length = ((*opt & 0xff) << 8) + 269;
100 ADVANCE_OPT(opt, length, 1);
101 result->length += *opt & 0xff;
108 ADVANCE_OPT(opt, length, 1);
109 /* opt now points to value, if present */
111 result->value = (unsigned char *) opt;
112 if (length < result->length)
114 debug("invalid option length\n");
117 //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
121 return (opt + result->length) - opt_start;
124 coap_opt_iterator_t *
125 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
131 memset(oi, 0, sizeof(coap_opt_iterator_t));
133 oi->next_option = (unsigned char *) pdu->hdr + sizeof(coap_hdr_t) + pdu->hdr->token_length;
134 if ((unsigned char *) pdu->hdr + pdu->length <= oi->next_option)
140 assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
142 oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
146 memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
152 static inline int opt_finished(coap_opt_iterator_t *oi)
156 if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
165 coap_option_next(coap_opt_iterator_t *oi)
167 coap_option_t option;
168 coap_opt_t *current_opt = NULL;
170 int b; /* to store result of coap_option_getb() */
174 if (opt_finished(oi))
179 /* oi->option always points to the next option to deliver; as
180 * opt_finished() filters out any bad conditions, we can assume that
181 * oi->option is valid. */
182 current_opt = oi->next_option;
184 /* Advance internal pointer to next option, skipping any option that
185 * is not included in oi->filter. */
186 optsize = coap_opt_parse(oi->next_option, oi->length, &option);
189 assert(optsize <= oi->length);
191 oi->next_option += optsize;
192 oi->length -= optsize;
194 oi->type += option.delta;
197 { /* current option is malformed */
202 /* Exit the while loop when:
203 * - no filtering is done at all
204 * - the filter matches for the current option
205 * - the filter is too small for the current option number
207 if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
210 { /* filter too small, cannot proceed */
220 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
224 coap_option_filter_clear(f);
225 coap_option_setb(f, type);
227 coap_option_iterator_init(pdu, oi, f);
229 return coap_option_next(oi);
232 unsigned short coap_opt_delta(const coap_opt_t *opt)
236 n = (*opt++ & 0xf0) >> 4;
241 warn("coap_opt_delta: illegal option delta\n");
243 /* This case usually should not happen, hence we do not have a
244 * proper way to indicate an error. */
247 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
248 * After that, the option pointer is advanced to the LSB which is handled
249 * just like case delta == 13. */
250 n = ((*opt++ & 0xff) << 8) + 269;
255 default: /* n already contains the actual delta value */
262 unsigned short coap_opt_length(const coap_opt_t *opt)
264 unsigned short length;
266 length = *opt & 0x0f;
270 debug("illegal option delta\n");
274 /* fall through to skip another byte */
277 /* fall through to skip another byte */
285 debug("illegal option length\n");
288 length = (*opt++ << 8) + 269;
300 coap_opt_value(coap_opt_t *opt)
307 debug("illegal option delta\n");
322 debug("illegal option length\n");
334 return (unsigned char *) opt + ofs;
337 size_t coap_opt_size(const coap_opt_t *opt)
339 coap_option_t option;
341 /* we must assume that opt is encoded correctly */
342 return coap_opt_parse(opt, (size_t) - 1, &option);
345 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
351 if (maxlen == 0) /* need at least one byte */
358 else if (delta < 270)
362 debug("insufficient space to encode option delta %d", delta);
367 opt[++skip] = delta - 13;
373 debug("insufficient space to encode option delta %d", delta);
378 opt[++skip] = ((delta - 269) >> 8) & 0xff;
379 opt[++skip] = (delta - 269) & 0xff;
384 opt[0] |= length & 0x0f;
386 else if (length < 270)
388 if (maxlen < skip + 1)
390 debug("insufficient space to encode option length %d", length);
395 opt[++skip] = length - 13;
399 if (maxlen < skip + 2)
401 debug("insufficient space to encode option delta %d", delta);
406 opt[++skip] = ((length - 269) >> 8) & 0xff;
407 opt[++skip] = (length - 269) & 0xff;
413 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
414 const unsigned char *val, size_t length)
418 l = coap_opt_setheader(opt, maxlen, delta, length);
423 debug("coap_opt_encode: cannot set option header\n");
432 debug("coap_opt_encode: option too large for buffer\n");
436 if (val) /* better be safe here */
437 memcpy(opt, val, length);
442 static coap_option_def_t coap_option_def[] = {
443 { COAP_OPTION_IF_MATCH, 'o', 0, 8 },
444 { COAP_OPTION_URI_HOST, 's', 1, 255 },
445 { COAP_OPTION_ETAG, 'o', 1, 8 },
446 { COAP_OPTION_IF_NONE_MATCH, 'e', 0, 0 },
447 { COAP_OPTION_URI_PORT, 'u', 0, 2 },
448 { COAP_OPTION_LOCATION_PATH, 's', 0, 255 },
449 { COAP_OPTION_URI_PATH, 's', 0, 255 },
450 { COAP_OPTION_CONTENT_TYPE, 'u', 0, 2 },
451 { COAP_OPTION_MAXAGE, 'u', 0, 4 },
452 { COAP_OPTION_URI_QUERY, 's', 1, 255 },
453 { COAP_OPTION_ACCEPT, 'u', 0, 2 },
454 { COAP_OPTION_LOCATION_QUERY, 's', 0, 255 },
455 { COAP_OPTION_PROXY_URI, 's', 1,1034 },
456 { COAP_OPTION_PROXY_SCHEME, 's', 1, 255 },
457 { COAP_OPTION_SIZE1, 'u', 0, 4 },
458 { COAP_OPTION_SIZE2, 'u', 0, 4 },
459 { COAP_OPTION_OBSERVE, 'u', 0, 3 },
460 { COAP_OPTION_BLOCK2, 'u', 0, 3 },
461 { COAP_OPTION_BLOCK1, 'u', 0, 3 },
465 coap_option_def_t* coap_opt_def(unsigned short key)
469 if (COAP_MAX_OPT < key)
473 for (i = 0; i < (int)(sizeof(coap_option_def)/sizeof(coap_option_def_t)); i++)
475 if (key == coap_option_def[i].key)
476 return &(coap_option_def[i]);
478 debug("coap_opt_def: add key:[%d] to coap_is_var_bytes", key);