Initial merge-commit of the OIC code. Should successfully do discovery for single...
[platform/upstream/iotivity.git] / csdk / 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
11 #include "config.h"
12
13 #if defined(HAVE_ASSERT_H) && !defined(assert)
14 # include <assert.h>
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "option.h"
21 #include "debug.h"
22
23 coap_opt_t *
24 options_start(coap_pdu_t *pdu) {
25
26   if (pdu && pdu->hdr && 
27       (pdu->hdr->token + pdu->hdr->token_length 
28        < (unsigned char *)pdu->hdr + pdu->length)) {
29
30     coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
31     return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
32   
33   } else 
34     return NULL;
35 }
36
37 size_t
38 coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
39
40   const coap_opt_t *opt_start = opt; /* store where parsing starts  */
41
42   assert(opt); assert(result);
43
44 #define ADVANCE_OPT(o,e,step) if ((e) < step) {                 \
45     debug("cannot advance opt past end\n");                     \
46     return 0;                                                   \
47   } else {                                                      \
48     (e) -= step;                                                \
49     (o) = ((unsigned char *)(o)) + step;                        \
50   }
51
52   if (length < 1)
53     return 0;
54
55   result->delta = (*opt & 0xf0) >> 4;
56   result->length = *opt & 0x0f;
57
58   switch(result->delta) {
59   case 15:
60     if (*opt != COAP_PAYLOAD_START)
61       debug("ignored reserved option delta 15\n");
62     return 0;
63   case 14:
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");
71       return 0;
72     }
73     /* fall through */
74   case 13:
75     ADVANCE_OPT(opt,length,1);
76     result->delta += *opt & 0xff;
77     break;
78     
79   default:
80     ;
81   }
82
83   switch(result->length) {
84   case 15:
85     debug("found reserved option length 15\n");
86     return 0;
87   case 14:
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;
93     /* fall through */
94   case 13:
95     ADVANCE_OPT(opt,length,1);
96     result->length += *opt & 0xff;
97     break;
98     
99   default:
100     ;
101   }
102
103   ADVANCE_OPT(opt,length,1);
104   /* opt now points to value, if present */
105
106   result->value = (unsigned char *)opt;
107   if (length < result->length) {
108     debug("invalid option length\n");
109     return 0;
110   }
111
112 #undef ADVANCE_OPT
113
114   return (opt + result->length) - opt_start;
115 }
116
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) {
120   assert(pdu); 
121   assert(pdu->hdr);
122   assert(oi);
123   
124   memset(oi, 0, sizeof(coap_opt_iterator_t));
125
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) {
129     oi->bad = 1;
130     return NULL;
131   }
132
133   assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
134
135   oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
136
137   if (filter) {
138     memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
139     oi->filtered = 1;
140   }
141   return oi;
142 }
143
144 static inline int
145 opt_finished(coap_opt_iterator_t *oi) {
146   assert(oi);
147
148   if (oi->bad || oi->length == 0 || 
149       !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
150     oi->bad = 1;
151   }
152
153   return oi->bad;
154 }
155
156 coap_opt_t *
157 coap_option_next(coap_opt_iterator_t *oi) {
158   coap_option_t option;
159   coap_opt_t *current_opt = NULL;
160   size_t optsize;
161   int b;                   /* to store result of coap_option_getb() */
162
163   assert(oi);
164
165   if (opt_finished(oi))
166     return NULL;
167
168   while (1) {
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;
173     
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);
177     if (optsize) {
178       assert(optsize <= oi->length);
179       
180       oi->next_option += optsize;
181       oi->length -= optsize;
182       
183       oi->type += option.delta;
184     } else {                    /* current option is malformed */
185       oi->bad = 1;
186       return NULL;
187     }
188
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 
193      */
194     if (!oi->filtered ||
195         (b = coap_option_getb(oi->filter, oi->type)) > 0)
196       break;
197     else if (b < 0) {           /* filter too small, cannot proceed */
198       oi->bad = 1;
199       return NULL;
200     }
201   }
202
203   return current_opt;
204 }
205
206 coap_opt_t *
207 coap_check_option(coap_pdu_t *pdu, unsigned char type, 
208                   coap_opt_iterator_t *oi) {
209   coap_opt_filter_t f;
210   
211   coap_option_filter_clear(f);
212   coap_option_setb(f, type);
213
214   coap_option_iterator_init(pdu, oi, f);
215
216   return coap_option_next(oi);
217 }
218
219 unsigned short
220 coap_opt_delta(const coap_opt_t *opt) {
221   unsigned short n;
222
223   n = (*opt++ & 0xf0) >> 4;
224
225   switch (n) {
226   case 15: /* error */
227     warn("coap_opt_delta: illegal option delta\n");
228
229     /* This case usually should not happen, hence we do not have a
230      * proper way to indicate an error. */
231     return 0;
232   case 14: 
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;
237     /* fall through */
238   case 13:
239     n += *opt & 0xff;
240     break;
241   default: /* n already contains the actual delta value */
242     ;
243   }
244
245   return n;
246 }
247
248 unsigned short
249 coap_opt_length(const coap_opt_t *opt) {
250   unsigned short length;
251
252   length = *opt & 0x0f;
253   switch (*opt & 0xf0) {
254   case 0xf0:
255     debug("illegal option delta\n");
256     return 0;
257   case 0xe0:
258     ++opt;
259     /* fall through to skip another byte */
260   case 0xd0:
261     ++opt;
262     /* fall through to skip another byte */
263   default:
264     ++opt;
265   }
266
267   switch (length) {
268   case 0x0f:
269     debug("illegal option length\n");
270     return 0;
271   case 0x0e:
272     length = (*opt++ << 8) + 269;
273     /* fall through */
274   case 0x0d:
275     length += *opt++;
276     break;
277   default:
278     ;
279   }
280   return length;
281 }
282
283 unsigned char *
284 coap_opt_value(coap_opt_t *opt) {
285   size_t ofs = 1;
286
287   switch (*opt & 0xf0) {
288   case 0xf0:
289     debug("illegal option delta\n");
290     return 0;
291   case 0xe0:
292     ++ofs;
293     /* fall through */
294   case 0xd0:
295     ++ofs;
296     break;
297   default:
298     ;
299   }
300
301   switch (*opt & 0x0f) {
302   case 0x0f:
303     debug("illegal option length\n");
304     return 0;
305   case 0x0e:
306     ++ofs;
307     /* fall through */
308   case 0x0d:
309     ++ofs;
310     break;
311   default:
312     ;
313   }
314
315   return (unsigned char *)opt + ofs;
316 }
317
318 size_t
319 coap_opt_size(const coap_opt_t *opt) {
320   coap_option_t option;
321
322   /* we must assume that opt is encoded correctly */
323   return coap_opt_parse(opt, (size_t)-1, &option);
324 }
325
326 size_t
327 coap_opt_setheader(coap_opt_t *opt, size_t maxlen, 
328                    unsigned short delta, size_t length) {
329   size_t skip = 0;
330
331   assert(opt);
332
333   if (maxlen == 0)              /* need at least one byte */
334     return 0;
335
336   if (delta < 13) {
337     opt[0] = delta << 4;
338   } else if (delta < 270) {
339     if (maxlen < 2) {
340       debug("insufficient space to encode option delta %d", delta);
341       return 0;
342     }
343
344     opt[0] = 0xd0;
345     opt[++skip] = delta - 13;
346   } else {
347     if (maxlen < 3) {
348       debug("insufficient space to encode option delta %d", delta);
349       return 0;
350     }
351
352     opt[0] = 0xe0;
353     opt[++skip] = ((delta - 269) >> 8) & 0xff;
354     opt[++skip] = (delta - 269) & 0xff;    
355   }
356     
357   if (length < 13) {
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);
362       return 0;
363     }
364     
365     opt[0] |= 0x0d;
366     opt[++skip] = length - 13;
367   } else {
368     if (maxlen < skip + 2) {
369       debug("insufficient space to encode option delta %d", delta);
370       return 0;
371     }
372
373     opt[0] |= 0x0e;
374     opt[++skip] = ((length - 269) >> 8) & 0xff;
375     opt[++skip] = (length - 269) & 0xff;    
376   }
377
378   return skip + 1;
379 }
380
381 size_t
382 coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
383                 const unsigned char *val, size_t length) {
384   size_t l = 1;
385
386   l = coap_opt_setheader(opt, maxlen, delta, length);
387   assert(l <= maxlen);
388   
389   if (!l) {
390     debug("coap_opt_encode: cannot set option header\n");
391     return 0;
392   }
393   
394   maxlen -= l;
395   opt += l;
396
397   if (maxlen < length) {
398     debug("coap_opt_encode: option too large for buffer\n");
399     return 0;
400   }
401
402   if (val)                      /* better be safe here */
403     memcpy(opt, val, length);
404
405   return l + length;
406 }
407