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)
78 debug("ignored reserved option delta 15\n");
82 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
83 * After that, the option pointer is advanced to the LSB which is handled
84 * just like case delta == 13. */
85 ADVANCE_OPT(opt, length, 1);
86 result->delta = ((*opt & 0xff) << 8) + 269;
87 if (result->delta < 269)
89 debug("delta too large\n");
94 ADVANCE_OPT(opt, length, 1);
95 result->delta += *opt & 0xff;
102 switch (result->length)
105 debug("found reserved option length 15\n");
108 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
109 * After that, the option pointer is advanced to the LSB which is handled
110 * just like case delta == 13. */
111 ADVANCE_OPT(opt, length, 1);
112 result->length = ((*opt & 0xff) << 8) + 269;
115 ADVANCE_OPT(opt, length, 1);
116 result->length += *opt & 0xff;
123 ADVANCE_OPT(opt, length, 1);
124 /* opt now points to value, if present */
126 result->value = (unsigned char *) opt;
127 if (length < result->length)
129 debug("invalid option length\n");
132 //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
136 return (opt + result->length) - opt_start;
139 coap_opt_iterator_t *
140 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
141 const coap_opt_filter_t filter, coap_transport_type transport)
147 memset(oi, 0, sizeof(coap_opt_iterator_t));
149 unsigned int token_length;
150 unsigned int headerSize;
156 token_length = (pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f;
157 headerSize = COAP_TCP_HEADER_NO_FIELD;
160 token_length = (pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0]) & 0x0f;
161 headerSize = COAP_TCP_HEADER_8_BIT;
164 token_length = (pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
165 headerSize = COAP_TCP_HEADER_16_BIT;
168 token_length = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] & 0x0f;
169 headerSize = COAP_TCP_HEADER_32_BIT;
173 token_length = pdu->hdr->coap_hdr_udp_t.token_length;
174 headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
178 oi->next_option = (unsigned char *) pdu->hdr + headerSize + token_length;
180 if (coap_udp == transport)
182 if ((unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length <= oi->next_option)
191 if ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length <= oi->next_option)
199 assert((headerSize + token_length) <= pdu->length);
201 oi->length = pdu->length - (headerSize + token_length);
205 memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
211 static inline int opt_finished(coap_opt_iterator_t *oi)
215 if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
224 coap_option_next(coap_opt_iterator_t *oi)
226 coap_option_t option;
227 coap_opt_t *current_opt = NULL;
229 int b; /* to store result of coap_option_getb() */
233 if (opt_finished(oi))
238 /* oi->option always points to the next option to deliver; as
239 * opt_finished() filters out any bad conditions, we can assume that
240 * oi->option is valid. */
241 current_opt = oi->next_option;
243 /* Advance internal pointer to next option, skipping any option that
244 * is not included in oi->filter. */
245 optsize = coap_opt_parse(oi->next_option, oi->length, &option);
248 assert(optsize <= oi->length);
250 oi->next_option += optsize;
251 oi->length -= optsize;
253 oi->type += option.delta;
256 { /* current option is malformed */
261 /* Exit the while loop when:
262 * - no filtering is done at all
263 * - the filter matches for the current option
264 * - the filter is too small for the current option number
266 if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
269 { /* filter too small, cannot proceed */
279 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
283 coap_option_filter_clear(f);
284 coap_option_setb(f, type);
286 coap_option_iterator_init(pdu, oi, f, coap_udp);
288 return coap_option_next(oi);
291 unsigned short coap_opt_delta(const coap_opt_t *opt)
295 n = (*opt++ & 0xf0) >> 4;
300 warn("coap_opt_delta: illegal option delta\n");
302 /* This case usually should not happen, hence we do not have a
303 * proper way to indicate an error. */
306 /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
307 * After that, the option pointer is advanced to the LSB which is handled
308 * just like case delta == 13. */
309 n = ((*opt++ & 0xff) << 8) + 269;
314 default: /* n already contains the actual delta value */
321 unsigned short coap_opt_length(const coap_opt_t *opt)
323 unsigned short length;
325 length = *opt & 0x0f;
329 debug("illegal option delta\n");
333 /* fall through to skip another byte */
336 /* fall through to skip another byte */
344 debug("illegal option length\n");
347 length = (*opt++ << 8) + 269;
359 coap_opt_value(coap_opt_t *opt)
366 debug("illegal option delta\n");
381 debug("illegal option length\n");
393 return (unsigned char *) opt + ofs;
396 size_t coap_opt_size(const coap_opt_t *opt)
398 coap_option_t option;
400 /* we must assume that opt is encoded correctly */
401 return coap_opt_parse(opt, (size_t) - 1, &option);
404 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
410 if (maxlen == 0) /* need at least one byte */
417 else if (delta < 270)
421 debug("insufficient space to encode option delta %d", delta);
426 opt[++skip] = delta - 13;
432 debug("insufficient space to encode option delta %d", delta);
437 opt[++skip] = ((delta - 269) >> 8) & 0xff;
438 opt[++skip] = (delta - 269) & 0xff;
443 opt[0] |= length & 0x0f;
445 else if (length < 270)
447 if (maxlen < skip + 1)
449 debug("insufficient space to encode option length %d", length);
454 opt[++skip] = length - 13;
458 if (maxlen < skip + 2)
460 debug("insufficient space to encode option delta %d", delta);
465 opt[++skip] = ((length - 269) >> 8) & 0xff;
466 opt[++skip] = (length - 269) & 0xff;
472 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
473 const unsigned char *val, size_t length)
477 l = coap_opt_setheader(opt, maxlen, delta, length);
482 debug("coap_opt_encode: cannot set option header\n");
491 debug("coap_opt_encode: option too large for buffer\n");
495 if (val) /* better be safe here */
496 memcpy(opt, val, length);
501 static coap_option_def_t coap_option_def[] = {
502 { COAP_OPTION_IF_MATCH, 'o', 0, 8 },
503 { COAP_OPTION_URI_HOST, 's', 1, 255 },
504 { COAP_OPTION_ETAG, 'o', 1, 8 },
505 { COAP_OPTION_IF_NONE_MATCH, 'e', 0, 0 },
506 { COAP_OPTION_URI_PORT, 'u', 0, 2 },
507 { COAP_OPTION_LOCATION_PATH, 's', 0, 255 },
508 { COAP_OPTION_URI_PATH, 's', 0, 255 },
509 { COAP_OPTION_CONTENT_TYPE, 'u', 0, 2 },
510 { COAP_OPTION_MAXAGE, 'u', 0, 4 },
511 { COAP_OPTION_URI_QUERY, 's', 1, 255 },
512 { COAP_OPTION_ACCEPT, 'u', 0, 2 },
513 { COAP_OPTION_LOCATION_QUERY, 's', 0, 255 },
514 { COAP_OPTION_PROXY_URI, 's', 1,1034 },
515 { COAP_OPTION_PROXY_SCHEME, 's', 1, 255 },
516 { COAP_OPTION_SIZE1, 'u', 0, 4 },
517 { COAP_OPTION_SIZE2, 'u', 0, 4 },
518 { COAP_OPTION_OBSERVE, 'u', 0, 3 },
519 { COAP_OPTION_BLOCK2, 'u', 0, 3 },
520 { COAP_OPTION_BLOCK1, 'u', 0, 3 },
524 coap_option_def_t* coap_opt_def(unsigned short key)
528 if (COAP_MAX_OPT < key)
532 for (i = 0; i < (int)(sizeof(coap_option_def)/sizeof(coap_option_def_t)); i++)
534 if (key == coap_option_def[i].key)
535 return &(coap_option_def[i]);
537 debug("coap_opt_def: add key:[%d] to coap_is_var_bytes", key);