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)
23 options_start(coap_pdu_t *pdu)
27 && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *) pdu->hdr + pdu->length))
30 coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
31 return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
38 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
41 const coap_opt_t *opt_start = opt; /* store where parsing starts */
45 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
46 debug("cannot advance opt past end\n"); \
50 (o) = ((unsigned char *)(o)) + step; \
56 result->delta = (*opt & 0xf0) >> 4;
57 result->length = *opt & 0x0f;
59 switch (result->delta)
62 if (*opt != COAP_PAYLOAD_START)
63 debug("ignored reserved option delta 15\n");
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)
73 debug("delta too large\n");
78 ADVANCE_OPT(opt, length, 1);
79 result->delta += *opt & 0xff;
86 switch (result->length)
89 debug("found reserved option length 15\n");
92 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
93 * After that, the option pointer is advanced to the LSB which is handled
94 * just like case delta == 13. */
95 ADVANCE_OPT(opt, length, 1);
96 result->length = ((*opt & 0xff) << 8) + 269;
99 ADVANCE_OPT(opt, length, 1);
100 result->length += *opt & 0xff;
107 ADVANCE_OPT(opt, length, 1);
108 /* opt now points to value, if present */
110 result->value = (unsigned char *) opt;
111 if (length < result->length)
113 debug("invalid option length\n");
116 //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
120 return (opt + result->length) - opt_start;
123 coap_opt_iterator_t *
124 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
130 memset(oi, 0, sizeof(coap_opt_iterator_t));
132 oi->next_option = (unsigned char *) pdu->hdr + sizeof(coap_hdr_t) + pdu->hdr->token_length;
133 if ((unsigned char *) pdu->hdr + pdu->length <= oi->next_option)
139 assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
141 oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
145 memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
151 static inline int opt_finished(coap_opt_iterator_t *oi)
155 if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
164 coap_option_next(coap_opt_iterator_t *oi)
166 coap_option_t option;
167 coap_opt_t *current_opt = NULL;
169 int b; /* to store result of coap_option_getb() */
173 if (opt_finished(oi))
178 /* oi->option always points to the next option to deliver; as
179 * opt_finished() filters out any bad conditions, we can assume that
180 * oi->option is valid. */
181 current_opt = oi->next_option;
183 /* Advance internal pointer to next option, skipping any option that
184 * is not included in oi->filter. */
185 optsize = coap_opt_parse(oi->next_option, oi->length, &option);
188 assert(optsize <= oi->length);
190 oi->next_option += optsize;
191 oi->length -= optsize;
193 oi->type += option.delta;
196 { /* current option is malformed */
201 /* Exit the while loop when:
202 * - no filtering is done at all
203 * - the filter matches for the current option
204 * - the filter is too small for the current option number
206 if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
209 { /* filter too small, cannot proceed */
219 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
223 coap_option_filter_clear(f);
224 coap_option_setb(f, type);
226 coap_option_iterator_init(pdu, oi, f);
228 return coap_option_next(oi);
231 unsigned short coap_opt_delta(const coap_opt_t *opt)
235 n = (*opt++ & 0xf0) >> 4;
240 warn("coap_opt_delta: illegal option delta\n");
242 /* This case usually should not happen, hence we do not have a
243 * proper way to indicate an error. */
246 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
247 * After that, the option pointer is advanced to the LSB which is handled
248 * just like case delta == 13. */
249 n = ((*opt++ & 0xff) << 8) + 269;
254 default: /* n already contains the actual delta value */
261 unsigned short coap_opt_length(const coap_opt_t *opt)
263 unsigned short length;
265 length = *opt & 0x0f;
269 debug("illegal option delta\n");
273 /* fall through to skip another byte */
276 /* fall through to skip another byte */
284 debug("illegal option length\n");
287 length = (*opt++ << 8) + 269;
299 coap_opt_value(coap_opt_t *opt)
306 debug("illegal option delta\n");
321 debug("illegal option length\n");
333 return (unsigned char *) opt + ofs;
336 size_t coap_opt_size(const coap_opt_t *opt)
338 coap_option_t option;
340 /* we must assume that opt is encoded correctly */
341 return coap_opt_parse(opt, (size_t) - 1, &option);
344 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
350 if (maxlen == 0) /* need at least one byte */
357 else if (delta < 270)
361 debug("insufficient space to encode option delta %d", delta);
366 opt[++skip] = delta - 13;
372 debug("insufficient space to encode option delta %d", delta);
377 opt[++skip] = ((delta - 269) >> 8) & 0xff;
378 opt[++skip] = (delta - 269) & 0xff;
383 opt[0] |= length & 0x0f;
385 else if (length < 270)
387 if (maxlen < skip + 1)
389 debug("insufficient space to encode option length %d", length);
394 opt[++skip] = length - 13;
398 if (maxlen < skip + 2)
400 debug("insufficient space to encode option delta %d", delta);
405 opt[++skip] = ((length - 269) >> 8) & 0xff;
406 opt[++skip] = (length - 269) & 0xff;
412 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
413 const unsigned char *val, size_t length)
417 l = coap_opt_setheader(opt, maxlen, delta, length);
422 debug("coap_opt_encode: cannot set option header\n");
431 debug("coap_opt_encode: option too large for buffer\n");
435 if (val) /* better be safe here */
436 memcpy(opt, val, length);