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.
13 #if defined(HAVE_ASSERT_H) && !defined(assert)
24 options_start(coap_pdu_t *pdu) {
26 if (pdu && pdu->hdr &&
27 (pdu->hdr->token + pdu->hdr->token_length
28 < (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 coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
40 const coap_opt_t *opt_start = opt; /* store where parsing starts */
42 assert(opt); assert(result);
44 #define ADVANCE_OPT(o,e,step) if ((e) < step) { \
45 debug("cannot advance opt past end\n"); \
49 (o) = ((unsigned char *)(o)) + step; \
55 result->delta = (*opt & 0xf0) >> 4;
56 result->length = *opt & 0x0f;
58 switch(result->delta) {
60 if (*opt != COAP_PAYLOAD_START)
61 debug("ignored reserved option delta 15\n");
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");
75 ADVANCE_OPT(opt,length,1);
76 result->delta += *opt & 0xff;
83 switch(result->length) {
85 debug("found reserved option length 15\n");
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;
95 ADVANCE_OPT(opt,length,1);
96 result->length += *opt & 0xff;
103 ADVANCE_OPT(opt,length,1);
104 /* opt now points to value, if present */
106 result->value = (unsigned char *)opt;
107 if (length < result->length) {
108 debug("invalid option length\n");
114 return (opt + result->length) - opt_start;
117 coap_opt_iterator_t *
118 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
119 const coap_opt_filter_t filter) {
124 memset(oi, 0, sizeof(coap_opt_iterator_t));
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) {
133 assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
135 oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
138 memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
145 opt_finished(coap_opt_iterator_t *oi) {
148 if (oi->bad || oi->length == 0 ||
149 !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
157 coap_option_next(coap_opt_iterator_t *oi) {
158 coap_option_t option;
159 coap_opt_t *current_opt = NULL;
161 int b; /* to store result of coap_option_getb() */
165 if (opt_finished(oi))
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;
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);
178 assert(optsize <= oi->length);
180 oi->next_option += optsize;
181 oi->length -= optsize;
183 oi->type += option.delta;
184 } else { /* current option is malformed */
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
195 (b = coap_option_getb(oi->filter, oi->type)) > 0)
197 else if (b < 0) { /* filter too small, cannot proceed */
207 coap_check_option(coap_pdu_t *pdu, unsigned char type,
208 coap_opt_iterator_t *oi) {
211 coap_option_filter_clear(f);
212 coap_option_setb(f, type);
214 coap_option_iterator_init(pdu, oi, f);
216 return coap_option_next(oi);
220 coap_opt_delta(const coap_opt_t *opt) {
223 n = (*opt++ & 0xf0) >> 4;
227 warn("coap_opt_delta: illegal option delta\n");
229 /* This case usually should not happen, hence we do not have a
230 * proper way to indicate an error. */
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;
241 default: /* n already contains the actual delta value */
249 coap_opt_length(const coap_opt_t *opt) {
250 unsigned short length;
252 length = *opt & 0x0f;
253 switch (*opt & 0xf0) {
255 debug("illegal option delta\n");
259 /* fall through to skip another byte */
262 /* fall through to skip another byte */
269 debug("illegal option length\n");
272 length = (*opt++ << 8) + 269;
284 coap_opt_value(coap_opt_t *opt) {
287 switch (*opt & 0xf0) {
289 debug("illegal option delta\n");
301 switch (*opt & 0x0f) {
303 debug("illegal option length\n");
315 return (unsigned char *)opt + ofs;
319 coap_opt_size(const coap_opt_t *opt) {
320 coap_option_t option;
322 /* we must assume that opt is encoded correctly */
323 return coap_opt_parse(opt, (size_t)-1, &option);
327 coap_opt_setheader(coap_opt_t *opt, size_t maxlen,
328 unsigned short delta, size_t length) {
333 if (maxlen == 0) /* need at least one byte */
338 } else if (delta < 270) {
340 debug("insufficient space to encode option delta %d", delta);
345 opt[++skip] = delta - 13;
348 debug("insufficient space to encode option delta %d", delta);
353 opt[++skip] = ((delta - 269) >> 8) & 0xff;
354 opt[++skip] = (delta - 269) & 0xff;
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);
366 opt[++skip] = length - 13;
368 if (maxlen < skip + 2) {
369 debug("insufficient space to encode option delta %d", delta);
374 opt[++skip] = ((length - 269) >> 8) & 0xff;
375 opt[++skip] = (length - 269) & 0xff;
382 coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
383 const unsigned char *val, size_t length) {
386 l = coap_opt_setheader(opt, maxlen, delta, length);
390 debug("coap_opt_encode: cannot set option header\n");
397 if (maxlen < length) {
398 debug("coap_opt_encode: option too large for buffer\n");
402 if (val) /* better be safe here */
403 memcpy(opt, val, length);