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, coap_transport_type transport)
28 if (coap_udp == transport && (pdu->hdr->coap_hdr_udp_t.token +
29 pdu->hdr->coap_hdr_udp_t.token_length
30 < (unsigned char *) pdu->hdr + pdu->length))
32 coap_opt_t *opt = pdu->hdr->coap_hdr_udp_t.token +
33 pdu->hdr->coap_hdr_udp_t.token_length;
34 return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
37 else if(coap_tcp == transport && (pdu->hdr->coap_hdr_tcp_t.token +
38 ((pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f)
39 < (unsigned char *) pdu->hdr + pdu->length))
41 coap_opt_t *opt = pdu->hdr->coap_hdr_tcp_t.token +
42 ((pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f);
43 return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
52 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
55 const coap_opt_t *opt_start = opt; /* store where parsing starts */
59 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
60 debug("cannot advance opt past end\n"); \
64 (o) = ((unsigned char *)(o)) + step; \
70 result->delta = (*opt & 0xf0) >> 4;
71 result->length = *opt & 0x0f;
73 switch (result->delta)
76 if (*opt != COAP_PAYLOAD_START)
77 debug("ignored reserved option delta 15\n");
80 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
81 * After that, the option pointer is advanced to the LSB which is handled
82 * just like case delta == 13. */
83 ADVANCE_OPT(opt, length, 1);
84 result->delta = ((*opt & 0xff) << 8) + 269;
85 if (result->delta < 269)
87 debug("delta too large\n");
92 ADVANCE_OPT(opt, length, 1);
93 result->delta += *opt & 0xff;
100 switch (result->length)
103 debug("found reserved option length 15\n");
106 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
107 * After that, the option pointer is advanced to the LSB which is handled
108 * just like case delta == 13. */
109 ADVANCE_OPT(opt, length, 1);
110 result->length = ((*opt & 0xff) << 8) + 269;
113 ADVANCE_OPT(opt, length, 1);
114 result->length += *opt & 0xff;
121 ADVANCE_OPT(opt, length, 1);
122 /* opt now points to value, if present */
124 result->value = (unsigned char *) opt;
125 if (length < result->length)
127 debug("invalid option length\n");
130 //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
134 return (opt + result->length) - opt_start;
137 coap_opt_iterator_t *
138 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
139 const coap_opt_filter_t filter, coap_transport_type transport)
145 memset(oi, 0, sizeof(coap_opt_iterator_t));
147 unsigned int token_length;
148 unsigned int headerSize;
154 token_length = (pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f;
155 headerSize = COAP_TCP_HEADER_NO_FIELD;
158 token_length = (pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0]) & 0x0f;
159 headerSize = COAP_TCP_HEADER_8_BIT;
162 token_length = (pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
163 headerSize = COAP_TCP_HEADER_16_BIT;
166 token_length = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] & 0x0f;
167 headerSize = COAP_TCP_HEADER_32_BIT;
171 token_length = pdu->hdr->coap_hdr_udp_t.token_length;
172 headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
176 oi->next_option = (unsigned char *) pdu->hdr + headerSize + token_length;
178 if (coap_udp == transport)
180 if ((unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length <= oi->next_option)
189 if ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length <= oi->next_option)
197 assert((headerSize + token_length) <= pdu->length);
199 oi->length = pdu->length - (headerSize + token_length);
203 memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
209 static inline int opt_finished(coap_opt_iterator_t *oi)
213 if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
222 coap_option_next(coap_opt_iterator_t *oi)
224 coap_option_t option;
225 coap_opt_t *current_opt = NULL;
227 int b; /* to store result of coap_option_getb() */
231 if (opt_finished(oi))
236 /* oi->option always points to the next option to deliver; as
237 * opt_finished() filters out any bad conditions, we can assume that
238 * oi->option is valid. */
239 current_opt = oi->next_option;
241 /* Advance internal pointer to next option, skipping any option that
242 * is not included in oi->filter. */
243 optsize = coap_opt_parse(oi->next_option, oi->length, &option);
246 assert(optsize <= oi->length);
248 oi->next_option += optsize;
249 oi->length -= optsize;
251 oi->type += option.delta;
254 { /* current option is malformed */
259 /* Exit the while loop when:
260 * - no filtering is done at all
261 * - the filter matches for the current option
262 * - the filter is too small for the current option number
264 if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
267 { /* filter too small, cannot proceed */
277 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
281 coap_option_filter_clear(f);
282 coap_option_setb(f, type);
284 coap_option_iterator_init(pdu, oi, f, coap_udp);
286 return coap_option_next(oi);
289 unsigned short coap_opt_delta(const coap_opt_t *opt)
293 n = (*opt++ & 0xf0) >> 4;
298 warn("coap_opt_delta: illegal option delta\n");
300 /* This case usually should not happen, hence we do not have a
301 * proper way to indicate an error. */
304 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
305 * After that, the option pointer is advanced to the LSB which is handled
306 * just like case delta == 13. */
307 n = ((*opt++ & 0xff) << 8) + 269;
312 default: /* n already contains the actual delta value */
319 unsigned short coap_opt_length(const coap_opt_t *opt)
321 unsigned short length;
323 length = *opt & 0x0f;
327 debug("illegal option delta\n");
331 /* fall through to skip another byte */
334 /* fall through to skip another byte */
342 debug("illegal option length\n");
345 length = (*opt++ << 8) + 269;
357 coap_opt_value(coap_opt_t *opt)
364 debug("illegal option delta\n");
379 debug("illegal option length\n");
391 return (unsigned char *) opt + ofs;
394 size_t coap_opt_size(const coap_opt_t *opt)
396 coap_option_t option;
398 /* we must assume that opt is encoded correctly */
399 return coap_opt_parse(opt, (size_t) - 1, &option);
402 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
408 if (maxlen == 0) /* need at least one byte */
415 else if (delta < 270)
419 debug("insufficient space to encode option delta %d", delta);
424 opt[++skip] = delta - 13;
430 debug("insufficient space to encode option delta %d", delta);
435 opt[++skip] = ((delta - 269) >> 8) & 0xff;
436 opt[++skip] = (delta - 269) & 0xff;
441 opt[0] |= length & 0x0f;
443 else if (length < 270)
445 if (maxlen < skip + 1)
447 debug("insufficient space to encode option length %d", length);
452 opt[++skip] = length - 13;
456 if (maxlen < skip + 2)
458 debug("insufficient space to encode option delta %d", delta);
463 opt[++skip] = ((length - 269) >> 8) & 0xff;
464 opt[++skip] = (length - 269) & 0xff;
470 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
471 const unsigned char *val, size_t length)
475 l = coap_opt_setheader(opt, maxlen, delta, length);
480 debug("coap_opt_encode: cannot set option header\n");
489 debug("coap_opt_encode: option too large for buffer\n");
493 if (val) /* better be safe here */
494 memcpy(opt, val, length);
499 static coap_option_def_t coap_option_def[] = {
500 { COAP_OPTION_IF_MATCH, 'o', 0, 8 },
501 { COAP_OPTION_URI_HOST, 's', 1, 255 },
502 { COAP_OPTION_ETAG, 'o', 1, 8 },
503 { COAP_OPTION_IF_NONE_MATCH, 'e', 0, 0 },
504 { COAP_OPTION_URI_PORT, 'u', 0, 2 },
505 { COAP_OPTION_LOCATION_PATH, 's', 0, 255 },
506 { COAP_OPTION_URI_PATH, 's', 0, 255 },
507 { COAP_OPTION_CONTENT_TYPE, 'u', 0, 2 },
508 { COAP_OPTION_MAXAGE, 'u', 0, 4 },
509 { COAP_OPTION_URI_QUERY, 's', 1, 255 },
510 { COAP_OPTION_ACCEPT, 'u', 0, 2 },
511 { COAP_OPTION_LOCATION_QUERY, 's', 0, 255 },
512 { COAP_OPTION_PROXY_URI, 's', 1,1034 },
513 { COAP_OPTION_PROXY_SCHEME, 's', 1, 255 },
514 { COAP_OPTION_SIZE1, 'u', 0, 4 },
515 { COAP_OPTION_SIZE2, 'u', 0, 4 },
516 { COAP_OPTION_OBSERVE, 'u', 0, 3 },
517 { COAP_OPTION_BLOCK2, 'u', 0, 3 },
518 { COAP_OPTION_BLOCK1, 'u', 0, 3 },
522 coap_option_def_t* coap_opt_def(unsigned short key)
526 if (COAP_MAX_OPT < key)
530 for (i = 0; i < (int)(sizeof(coap_option_def)/sizeof(coap_option_def_t)); i++)
532 if (key == coap_option_def[i].key)
533 return &(coap_option_def[i]);
535 debug("coap_opt_def: add key:[%d] to coap_is_var_bytes", key);