8cf2ae6a0a4c811b59eecacc2c045a7df780f752
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / option.c
1 /*
2  * option.c -- helpers for handling options in CoAP PDUs
3  *
4  * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see
7  * README for terms of use.
8  */
9
10 #include "config.h"
11
12 #if defined(HAVE_ASSERT_H) && !defined(assert)
13 # include <assert.h>
14 #endif
15
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "option.h"
20 #include "debug.h"
21 #include "pdu.h"
22
23 coap_opt_t *
24 options_start(coap_pdu_t *pdu, coap_transport_type transport)
25 {
26     if (pdu && pdu->hdr)
27     {
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))
31         {
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;
35         }
36 #ifdef WITH_TCP
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))
40         {
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;
44         }
45 #endif
46         return NULL;
47     }
48     else
49         return NULL;
50 }
51
52 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
53 {
54
55     const coap_opt_t *opt_start = opt; /* store where parsing starts  */
56     assert(opt);
57     assert(result);
58
59 #define ADVANCE_OPT(o,e,step) if ((e) < step) {         \
60     debug("cannot advance opt past end\n");         \
61     return 0;                           \
62   } else {                          \
63     (e) -= step;                        \
64     (o) = ((unsigned char *)(o)) + step;            \
65   }
66
67     if (length < 1)
68         return 0;
69
70     result->delta = (*opt & 0xf0) >> 4;
71     result->length = *opt & 0x0f;
72
73     switch (result->delta)
74     {
75         case 15:
76             if (*opt != COAP_PAYLOAD_START)
77                 debug("ignored reserved option delta 15\n");
78             return 0;
79         case 14:
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)
86             {
87                 debug("delta too large\n");
88                 return 0;
89             }
90             /* fall through */
91         case 13:
92             ADVANCE_OPT(opt, length, 1);
93             result->delta += *opt & 0xff;
94             break;
95
96         default:
97             ;
98     }
99
100     switch (result->length)
101     {
102         case 15:
103             debug("found reserved option length 15\n");
104             return 0;
105         case 14:
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;
111             /* fall through */
112         case 13:
113             ADVANCE_OPT(opt, length, 1);
114             result->length += *opt & 0xff;
115             break;
116
117         default:
118             ;
119     }
120
121     ADVANCE_OPT(opt, length, 1);
122     /* opt now points to value, if present */
123
124     result->value = (unsigned char *) opt;
125     if (length < result->length)
126     {
127         debug("invalid option length\n");
128         return 0;
129     }
130     //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
131
132 #undef ADVANCE_OPT
133
134     return (opt + result->length) - opt_start;
135 }
136
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)
140 {
141     assert(pdu);
142     assert(pdu->hdr);
143     assert(oi);
144
145     memset(oi, 0, sizeof(coap_opt_iterator_t));
146
147     unsigned int token_length;
148     unsigned int headerSize;
149
150     switch(transport)
151     {
152 #ifdef WITH_TCP
153         case coap_tcp:
154             token_length = (pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f;
155             headerSize = COAP_TCP_HEADER_NO_FIELD;
156             break;
157         case coap_tcp_8bit:
158             token_length = (pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0]) & 0x0f;
159             headerSize = COAP_TCP_HEADER_8_BIT;
160             break;
161         case coap_tcp_16bit:
162             token_length = (pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
163             headerSize = COAP_TCP_HEADER_16_BIT;
164             break;
165         case coap_tcp_32bit:
166             token_length = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] & 0x0f;
167             headerSize = COAP_TCP_HEADER_32_BIT;
168             break;
169 #endif
170         default:
171             token_length = pdu->hdr->coap_hdr_udp_t.token_length;
172             headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
173             break;
174     }
175
176     oi->next_option = (unsigned char *) pdu->hdr + headerSize + token_length;
177
178     if (coap_udp == transport)
179     {
180         if ((unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length <= oi->next_option)
181         {
182             oi->bad = 1;
183             return NULL;
184         }
185     }
186 #ifdef WITH_TCP
187     else
188     {
189         if ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length <= oi->next_option)
190         {
191             oi->bad = 1;
192             return NULL;
193         }
194     }
195 #endif
196
197     assert((headerSize + token_length) <= pdu->length);
198
199     oi->length = pdu->length - (headerSize + token_length);
200
201     if (filter)
202     {
203         memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
204         oi->filtered = 1;
205     }
206     return oi;
207 }
208
209 static inline int opt_finished(coap_opt_iterator_t *oi)
210 {
211     assert(oi);
212
213     if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
214     {
215         oi->bad = 1;
216     }
217
218     return oi->bad;
219 }
220
221 coap_opt_t *
222 coap_option_next(coap_opt_iterator_t *oi)
223 {
224     coap_option_t option;
225     coap_opt_t *current_opt = NULL;
226     size_t optsize;
227     int b; /* to store result of coap_option_getb() */
228
229     assert(oi);
230
231     if (opt_finished(oi))
232         return NULL;
233
234     while (1)
235     {
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;
240
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);
244         if (optsize)
245         {
246             assert(optsize <= oi->length);
247
248             oi->next_option += optsize;
249             oi->length -= optsize;
250
251             oi->type += option.delta;
252         }
253         else
254         { /* current option is malformed */
255             oi->bad = 1;
256             return NULL;
257         }
258
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
263          */
264         if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
265             break;
266         else if (b < 0)
267         { /* filter too small, cannot proceed */
268             oi->bad = 1;
269             return NULL;
270         }
271     }
272
273     return current_opt;
274 }
275
276 coap_opt_t *
277 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
278 {
279     coap_opt_filter_t f;
280
281     coap_option_filter_clear(f);
282     coap_option_setb(f, type);
283
284     coap_option_iterator_init(pdu, oi, f, coap_udp);
285
286     return coap_option_next(oi);
287 }
288
289 unsigned short coap_opt_delta(const coap_opt_t *opt)
290 {
291     unsigned short n;
292
293     n = (*opt++ & 0xf0) >> 4;
294
295     switch (n)
296     {
297         case 15: /* error */
298             warn("coap_opt_delta: illegal option delta\n");
299
300             /* This case usually should not happen, hence we do not have a
301              * proper way to indicate an error. */
302             return 0;
303         case 14:
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;
308             /* fall through */
309         case 13:
310             n += *opt & 0xff;
311             break;
312         default: /* n already contains the actual delta value */
313             ;
314     }
315
316     return n;
317 }
318
319 unsigned short coap_opt_length(const coap_opt_t *opt)
320 {
321     unsigned short length;
322
323     length = *opt & 0x0f;
324     switch (*opt & 0xf0)
325     {
326         case 0xf0:
327             debug("illegal option delta\n");
328             return 0;
329         case 0xe0:
330             ++opt;
331             /* fall through to skip another byte */
332         case 0xd0:
333             ++opt;
334             /* fall through to skip another byte */
335         default:
336             ++opt;
337     }
338
339     switch (length)
340     {
341         case 0x0f:
342             debug("illegal option length\n");
343             return 0;
344         case 0x0e:
345             length = (*opt++ << 8) + 269;
346             /* fall through */
347         case 0x0d:
348             length += *opt++;
349             break;
350         default:
351             ;
352     }
353     return length;
354 }
355
356 unsigned char *
357 coap_opt_value(coap_opt_t *opt)
358 {
359     size_t ofs = 1;
360
361     switch (*opt & 0xf0)
362     {
363         case 0xf0:
364             debug("illegal option delta\n");
365             return 0;
366         case 0xe0:
367             ++ofs;
368             /* fall through */
369         case 0xd0:
370             ++ofs;
371             break;
372         default:
373             ;
374     }
375
376     switch (*opt & 0x0f)
377     {
378         case 0x0f:
379             debug("illegal option length\n");
380             return 0;
381         case 0x0e:
382             ++ofs;
383             /* fall through */
384         case 0x0d:
385             ++ofs;
386             break;
387         default:
388             ;
389     }
390
391     return (unsigned char *) opt + ofs;
392 }
393
394 size_t coap_opt_size(const coap_opt_t *opt)
395 {
396     coap_option_t option;
397
398     /* we must assume that opt is encoded correctly */
399     return coap_opt_parse(opt, (size_t) - 1, &option);
400 }
401
402 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
403 {
404     size_t skip = 0;
405
406     assert(opt);
407
408     if (maxlen == 0) /* need at least one byte */
409         return 0;
410
411     if (delta < 13)
412     {
413         opt[0] = delta << 4;
414     }
415     else if (delta < 270)
416     {
417         if (maxlen < 2)
418         {
419             debug("insufficient space to encode option delta %d", delta);
420             return 0;
421         }
422
423         opt[0] = 0xd0;
424         opt[++skip] = delta - 13;
425     }
426     else
427     {
428         if (maxlen < 3)
429         {
430             debug("insufficient space to encode option delta %d", delta);
431             return 0;
432         }
433
434         opt[0] = 0xe0;
435         opt[++skip] = ((delta - 269) >> 8) & 0xff;
436         opt[++skip] = (delta - 269) & 0xff;
437     }
438
439     if (length < 13)
440     {
441         opt[0] |= length & 0x0f;
442     }
443     else if (length < 270)
444     {
445         if (maxlen < skip + 1)
446         {
447             debug("insufficient space to encode option length %d", length);
448             return 0;
449         }
450
451         opt[0] |= 0x0d;
452         opt[++skip] = length - 13;
453     }
454     else
455     {
456         if (maxlen < skip + 2)
457         {
458             debug("insufficient space to encode option delta %d", delta);
459             return 0;
460         }
461
462         opt[0] |= 0x0e;
463         opt[++skip] = ((length - 269) >> 8) & 0xff;
464         opt[++skip] = (length - 269) & 0xff;
465     }
466
467     return skip + 1;
468 }
469
470 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
471         const unsigned char *val, size_t length)
472 {
473     size_t l = 1;
474
475     l = coap_opt_setheader(opt, maxlen, delta, length);
476     assert(l <= maxlen);
477
478     if (!l)
479     {
480         debug("coap_opt_encode: cannot set option header\n");
481         return 0;
482     }
483
484     maxlen -= l;
485     opt += l;
486
487     if (maxlen < length)
488     {
489         debug("coap_opt_encode: option too large for buffer\n");
490         return 0;
491     }
492
493     if (val) /* better be safe here */
494         memcpy(opt, val, length);
495
496     return l + length;
497 }
498
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 },
519 };
520
521
522 coap_option_def_t* coap_opt_def(unsigned short key)
523 {
524     int i;
525
526     if (COAP_MAX_OPT < key)
527     {
528         return NULL;
529     }
530     for (i = 0; i < (int)(sizeof(coap_option_def)/sizeof(coap_option_def_t)); i++)
531     {
532         if (key == coap_option_def[i].key)
533             return &(coap_option_def[i]);
534     }
535     debug("coap_opt_def: add key:[%d] to coap_is_var_bytes", key);
536     return NULL;
537 }