Contiki-NG
Loading...
Searching...
No Matches
coap.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 */
31
32/**
33 * \file
34 * An implementation of the Constrained Application Protocol (RFC).
35 * \author
36 * Matthias Kovatsch <kovatsch@inf.ethz.ch>
37 *
38 * Joakim Eriksson, joakim.eriksson@ri.se
39 * Niclas Finne, niclas.finne@ri.se
40 */
41
42/**
43 * \addtogroup coap
44 * @{
45 */
46
47
48#include <string.h>
49#include <stdlib.h>
50#include <inttypes.h>
51#include "sys/cc.h"
52#include "lib/random.h"
53
54#include "coap.h"
55#include "coap-transactions.h"
56
57/* Log configuration */
58#include "coap-log.h"
59#define LOG_MODULE "coap"
60#define LOG_LEVEL LOG_LEVEL_COAP
61
62/*---------------------------------------------------------------------------*/
63/*- Variables ---------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65static uint16_t current_mid = 0;
66
67coap_status_t coap_status_code = NO_ERROR;
68#if COAP_MESSAGE_ON_ERROR
69const char *coap_error_message = "";
70#endif
71/*---------------------------------------------------------------------------*/
72/*- Local helper functions --------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
74static uint16_t
75coap_log_2(uint16_t value)
76{
77 uint16_t result = 0;
78
79 do {
80 value = value >> 1;
81 result++;
82 } while(value);
83
84 return result ? result - 1 : result;
85}
86/*---------------------------------------------------------------------------*/
87static uint32_t
88coap_parse_int_option(const uint8_t *bytes, size_t length)
89{
90 uint32_t var = 0;
91 int i = 0;
92
93 while(i < length) {
94 var <<= 8;
95 var |= bytes[i++];
96 }
97 return var;
98}
99/*---------------------------------------------------------------------------*/
100static uint8_t
101coap_option_nibble(unsigned int value)
102{
103 if(value < 13) {
104 return value;
105 } else if(value <= 0xFF + 13) {
106 return 13;
107 } else {
108 return 14;
109 }
110}
111/*---------------------------------------------------------------------------*/
112static size_t
113coap_set_option_header(unsigned int delta, size_t length, uint8_t *buffer)
114{
115 size_t written = 0;
116
117 buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length);
118
119 if(delta > 268) {
120 buffer[++written] = ((delta - 269) >> 8) & 0xff;
121 buffer[++written] = (delta - 269) & 0xff;
122 } else if(delta > 12) {
123 buffer[++written] = (delta - 13);
124 }
125
126 if(length > 268) {
127 buffer[++written] = ((length - 269) >> 8) & 0xff;
128 buffer[++written] = (length - 269) & 0xff;
129 } else if(length > 12) {
130 buffer[++written] = (length - 13);
131 }
132
133 LOG_DBG("WRITTEN %zu B opt header\n", 1 + written);
134
135 return ++written;
136}
137/*---------------------------------------------------------------------------*/
138static size_t
139coap_serialize_int_option(unsigned int number, unsigned int current_number,
140 uint8_t *buffer, uint32_t value)
141{
142 size_t i = 0;
143
144 if(0xFF000000 & value) {
145 ++i;
146 }
147 if(0xFFFF0000 & value) {
148 ++i;
149 }
150 if(0xFFFFFF00 & value) {
151 ++i;
152 }
153 if(0xFFFFFFFF & value) {
154 ++i;
155 }
156 LOG_DBG("OPTION %u (delta %u, len %zu)\n", number, number - current_number,
157 i);
158
159 i = coap_set_option_header(number - current_number, i, buffer);
160
161 if(0xFF000000 & value) {
162 buffer[i++] = (uint8_t)(value >> 24);
163 }
164 if(0xFFFF0000 & value) {
165 buffer[i++] = (uint8_t)(value >> 16);
166 }
167 if(0xFFFFFF00 & value) {
168 buffer[i++] = (uint8_t)(value >> 8);
169 }
170 if(0xFFFFFFFF & value) {
171 buffer[i++] = (uint8_t)(value);
172 }
173 return i;
174}
175/*---------------------------------------------------------------------------*/
176static size_t
177coap_serialize_array_option(unsigned int number, unsigned int current_number,
178 uint8_t *buffer, uint8_t *array, size_t length,
179 char split_char)
180{
181 size_t i = 0;
182
183 LOG_DBG("ARRAY type %u, len %zu, full [", number, length);
184 LOG_DBG_COAP_STRING((const char *)array, length);
185 LOG_DBG_("]\n");
186
187 if(split_char != '\0') {
188 int j;
189 uint8_t *part_start = array;
190 uint8_t *part_end = NULL;
191 size_t temp_length;
192
193 for(j = 0; j <= length + 1; ++j) {
194 LOG_DBG("STEP %u/%zu (%c)\n", j, length, array[j]);
195 if(array[j] == split_char || j == length) {
196 part_end = array + j;
197 temp_length = part_end - part_start;
198
199 i += coap_set_option_header(number - current_number, temp_length,
200 &buffer[i]);
201 memcpy(&buffer[i], part_start, temp_length);
202 i += temp_length;
203
204 LOG_DBG("OPTION type %u, delta %u, len %zu, part [", number,
205 number - current_number, i);
206 LOG_DBG_COAP_STRING((const char *)part_start, temp_length);
207 LOG_DBG_("]\n");
208 ++j; /* skip the splitter */
209 current_number = number;
210 part_start = array + j;
211 }
212 } /* for */
213 } else {
214 i += coap_set_option_header(number - current_number, length, &buffer[i]);
215 memcpy(&buffer[i], array, length);
216 i += length;
217
218 LOG_DBG("OPTION type %u, delta %u, len %zu\n", number,
219 number - current_number, length);
220 }
221
222 return i;
223}
224/*---------------------------------------------------------------------------*/
225static void
226coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option,
227 size_t option_len, char separator)
228{
229 /* merge multiple options */
230 if(*dst_len > 0) {
231 /* dst already contains an option: concatenate */
232 (*dst)[*dst_len] = separator;
233 *dst_len += 1;
234
235 /* memmove handles 2-byte option headers */
236 memmove((*dst) + (*dst_len), option, option_len);
237
238 *dst_len += option_len;
239 } else {
240 /* dst is empty: set to option */
241 *dst = (char *)option;
242 *dst_len = option_len;
243 }
244}
245/*---------------------------------------------------------------------------*/
246static int
247coap_get_variable(const char *buffer, size_t length, const char *name,
248 const char **output)
249{
250 const char *start = NULL;
251 const char *end = NULL;
252 const char *value_end = NULL;
253 size_t name_len = 0;
254
255 /*initialize the output buffer first */
256 *output = 0;
257
258 name_len = strlen(name);
259 end = buffer + length;
260
261 for(start = buffer; start + name_len < end; ++start) {
262 if((start == buffer || start[-1] == '&') && start[name_len] == '='
263 && strncmp(name, start, name_len) == 0) {
264
265 /* Point start to variable value */
266 start += name_len + 1;
267
268 /* Point end to the end of the value */
269 value_end = (const char *)memchr(start, '&', end - start);
270 if(value_end == NULL) {
271 value_end = end;
272 }
273 *output = start;
274
275 return value_end - start;
276 }
277 }
278 return 0;
279}
280/*---------------------------------------------------------------------------*/
281/*- Internal API ------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
283void
284coap_init_connection(void)
285{
286 /* initialize transaction ID */
287 current_mid = random_rand();
288}
289/*---------------------------------------------------------------------------*/
290uint16_t
291coap_get_mid()
292{
293 return ++current_mid;
294}
295/*---------------------------------------------------------------------------*/
296void
297coap_init_message(coap_message_t *coap_pkt, coap_message_type_t type,
298 uint8_t code, uint16_t mid)
299{
300 /* Important thing */
301 memset(coap_pkt, 0, sizeof(coap_message_t));
302
303 coap_pkt->type = type;
304 coap_pkt->code = code;
305 coap_pkt->mid = mid;
306}
307/*---------------------------------------------------------------------------*/
308size_t
309coap_serialize_message(coap_message_t *coap_pkt, uint8_t *buffer)
310{
311 uint8_t *option;
312 unsigned int current_number = 0;
313
314 /* Initialize */
315 coap_pkt->buffer = buffer;
316 coap_pkt->version = 1;
317
318 LOG_DBG("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer);
319
320 /* set header fields */
321 coap_pkt->buffer[0] = 0x00;
322 coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK
323 & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION;
324 coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK
325 & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION;
326 coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK
327 & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION;
328 coap_pkt->buffer[1] = coap_pkt->code;
329 coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8);
330 coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid);
331
332 /* empty message, dont need to do more stuff */
333 if(!coap_pkt->code) {
334 LOG_DBG_("-Done serializing empty message at %p-\n", coap_pkt->buffer);
335 return 4;
336 }
337
338 /* set Token */
339 LOG_DBG_("Token (len %u)", coap_pkt->token_len);
340 option = coap_pkt->buffer + COAP_HEADER_LEN;
341 for(current_number = 0; current_number < coap_pkt->token_len;
342 ++current_number) {
343 LOG_DBG_(" %02X", coap_pkt->token[current_number]);
344 *option = coap_pkt->token[current_number];
345 ++option;
346 }
347 LOG_DBG_("-\n");
348
349 /* Serialize options */
350 current_number = 0;
351
352 LOG_DBG("-Serializing options at %p-\n", option);
353
354 /* The options must be serialized in the order of their number */
355 COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match");
356 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0',
357 "Uri-Host");
358 COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag");
359 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH,
360 content_format -
361 coap_pkt->
362 content_format /* hack to get a zero field */,
363 "If-None-Match");
364 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe");
365 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port");
366 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/',
367 "Location-Path");
368 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/',
369 "Uri-Path");
370 LOG_DBG("Serialize content format: %d\n", coap_pkt->content_format);
371 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format,
372 "Content-Format");
373 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age");
374 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&',
375 "Uri-Query");
376 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept");
377 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query,
378 '&', "Location-Query");
379 COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2");
380 COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1");
381 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2");
382 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0',
383 "Proxy-Uri");
384 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0',
385 "Proxy-Scheme");
386 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1");
387
388 LOG_DBG("-Done serializing at %p----\n", option);
389
390 /* Pack payload */
391 if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) {
392 /* Payload marker */
393 if(coap_pkt->payload_len) {
394 *option = 0xFF;
395 ++option;
396 }
397 memmove(option, coap_pkt->payload, coap_pkt->payload_len);
398 } else {
399 /* an error occurred: caller must check for !=0 */
400 coap_pkt->buffer = NULL;
401#if COAP_MESSAGE_ON_ERROR
402 coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE";
403#endif
404 return 0;
405 }
406
407 LOG_DBG("-Done %u B (header len %u, payload len %u)-\n",
408 (unsigned int)(coap_pkt->payload_len + option - buffer),
409 (unsigned int)(option - buffer),
410 (unsigned int)coap_pkt->payload_len);
411
412 LOG_DBG("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n",
413 coap_pkt->buffer[0], coap_pkt->buffer[1], coap_pkt->buffer[2],
414 coap_pkt->buffer[3], coap_pkt->buffer[4], coap_pkt->buffer[5],
415 coap_pkt->buffer[6], coap_pkt->buffer[7]);
416
417 return (option - buffer) + coap_pkt->payload_len; /* message length */
418}
419/*---------------------------------------------------------------------------*/
420coap_status_t
421coap_parse_message(coap_message_t *coap_pkt, uint8_t *data, uint16_t data_len)
422{
423#define CHECK_OPTION_BOUNDARY(byte_count) \
424 do { \
425 if(current_option + (byte_count) > data + data_len) { \
426 LOG_WARN("BAD REQUEST: option delta outside buffer (%u > %u)\n", \
427 (unsigned)(current_option + (byte_count) - data), \
428 data_len); \
429 return BAD_REQUEST_4_00; \
430 } \
431 } while (0)
432
433 if(data_len < COAP_HEADER_LEN) {
434 /* Too short - malformed CoAP message */
435 LOG_WARN("BAD REQUEST: message too short\n");
436 return BAD_REQUEST_4_00;
437 }
438
439 /* initialize message */
440 memset(coap_pkt, 0, sizeof(coap_message_t));
441
442 /* pointer to message bytes */
443 coap_pkt->buffer = data;
444
445 /* parse header fields */
446 coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])
447 >> COAP_HEADER_VERSION_POSITION;
448 coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])
449 >> COAP_HEADER_TYPE_POSITION;
450 coap_pkt->token_len = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])
451 >> COAP_HEADER_TOKEN_LEN_POSITION;
452 coap_pkt->code = coap_pkt->buffer[1];
453 coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3];
454
455 if(coap_pkt->version != 1) {
456#if COAP_MESSAGE_ON_ERROR
457 coap_error_message = "CoAP version must be 1";
458#endif
459 return BAD_REQUEST_4_00;
460 }
461
462 if(coap_pkt->token_len > COAP_TOKEN_LEN) {
463#if COAP_MESSAGE_ON_ERROR
464 coap_error_message = "Token Length must not be more than 8";
465#endif
466 return BAD_REQUEST_4_00;
467 }
468
469 uint8_t *current_option = data + COAP_HEADER_LEN;
470 CHECK_OPTION_BOUNDARY(coap_pkt->token_len);
471
472 memcpy(coap_pkt->token, current_option, coap_pkt->token_len);
473 LOG_DBG("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
474 coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1],
475 coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4],
476 coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7]
477 ); /* FIXME always prints 8 bytes */
478
479 /* parse options */
480 memset(coap_pkt->options, 0, sizeof(coap_pkt->options));
481 current_option += coap_pkt->token_len;
482
483 /* Use uint32_t so overflow is detectable on 16-bit platforms where
484 * 'unsigned int' and 'size_t' are 16 bits (e.g., MSP430). The
485 * extended delta and length encodings can each produce values up to
486 * 65804 from a single option, and accumulated option numbers must be
487 * checked against the UINT16_MAX cap. */
488 uint32_t option_number = 0;
489 uint32_t option_delta = 0;
490 uint32_t option_length = 0;
491
492 while(current_option < data + data_len) {
493 /* Payload marker. Per RFC 7252 §3.1, the marker is exactly 0xFF;
494 * any other byte with delta or length nibble = 15 is reserved and
495 * MUST be processed as a message format error. The marker followed
496 * by a zero-length payload is also a message format error. */
497 if(current_option[0] == 0xFF) {
498 ++current_option;
499 if(current_option >= data + data_len) {
500 LOG_WARN("BAD REQUEST: payload marker with zero-length payload\n");
501 return BAD_REQUEST_4_00;
502 }
503 coap_pkt->payload = current_option;
504 coap_pkt->payload_len = data_len - (coap_pkt->payload - data);
505
506 /* also for receiving, the Erbium upper bound is COAP_MAX_CHUNK_SIZE */
507 if(coap_pkt->payload_len > COAP_MAX_CHUNK_SIZE) {
508 coap_pkt->payload_len = COAP_MAX_CHUNK_SIZE;
509 /* null-terminate payload */
510 }
511 coap_pkt->payload[coap_pkt->payload_len] = '\0';
512
513 break;
514 }
515
516 option_delta = current_option[0] >> 4;
517 option_length = current_option[0] & 0x0F;
518 ++current_option;
519
520 if(option_delta == 15 || option_length == 15) {
521 /* Reserved nibble values per RFC 7252 §3.1. */
522 LOG_WARN("BAD REQUEST: reserved option delta/length nibble 15\n");
523 return BAD_REQUEST_4_00;
524 }
525
526 if(option_delta == 13) {
527 CHECK_OPTION_BOUNDARY(1);
528 option_delta += current_option[0];
529 ++current_option;
530 } else if(option_delta == 14) {
531 CHECK_OPTION_BOUNDARY(2);
532 option_delta += 255;
533 option_delta += (uint32_t)current_option[0] << 8;
534 ++current_option;
535 option_delta += current_option[0];
536 ++current_option;
537 }
538
539 if(option_length == 13) {
540 CHECK_OPTION_BOUNDARY(1);
541 option_length += current_option[0];
542 ++current_option;
543 } else if(option_length == 14) {
544 CHECK_OPTION_BOUNDARY(2);
545 option_length += 255;
546 option_length += (uint32_t)current_option[0] << 8;
547 ++current_option;
548 option_length += current_option[0];
549 ++current_option;
550 }
551
552 CHECK_OPTION_BOUNDARY(option_length);
553 option_number += option_delta;
554
555 if(option_number > UINT16_MAX) {
556 /* Per RFC 7252, CoAP option numbers are 16-bit (0-UINT16_MAX). */
557 LOG_WARN("BAD REQUEST: option number out of range: %"PRIu32"\n",
558 option_number);
559 return BAD_REQUEST_4_00;
560 }
561
562 LOG_DBG("OPTION %"PRIu32" (delta %"PRIu32", len %"PRIu32"): ",
563 option_number, option_delta, option_length);
564
565 coap_set_option(coap_pkt, option_number);
566
567 switch(option_number) {
568 case COAP_OPTION_CONTENT_FORMAT:
569 coap_pkt->content_format = coap_parse_int_option(current_option,
570 option_length);
571 LOG_DBG_("Content-Format [%u]\n", coap_pkt->content_format);
572 break;
573 case COAP_OPTION_MAX_AGE:
574 coap_pkt->max_age = coap_parse_int_option(current_option,
575 option_length);
576 LOG_DBG_("Max-Age [%"PRIu32"]\n", coap_pkt->max_age);
577 break;
578 case COAP_OPTION_ETAG:
579 coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length);
580 memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len);
581 LOG_DBG_("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
582 coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1],
583 coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4],
584 coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7]
585 ); /*FIXME always prints 8 bytes */
586 break;
587 case COAP_OPTION_ACCEPT:
588 coap_pkt->accept = coap_parse_int_option(current_option, option_length);
589 LOG_DBG_("Accept [%u]\n", coap_pkt->accept);
590 break;
591 case COAP_OPTION_IF_MATCH:
592 /* TODO support multiple ETags */
593 coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length);
594 memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len);
595 LOG_DBG_("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
596 coap_pkt->if_match_len, coap_pkt->if_match[0],
597 coap_pkt->if_match[1], coap_pkt->if_match[2],
598 coap_pkt->if_match[3], coap_pkt->if_match[4],
599 coap_pkt->if_match[5], coap_pkt->if_match[6],
600 coap_pkt->if_match[7]
601 ); /* FIXME always prints 8 bytes */
602 break;
603 case COAP_OPTION_IF_NONE_MATCH:
604 coap_pkt->if_none_match = 1;
605 LOG_DBG_("If-None-Match\n");
606 break;
607
608 case COAP_OPTION_PROXY_URI:
609#if COAP_PROXY_OPTION_PROCESSING
610 coap_pkt->proxy_uri = (char *)current_option;
611 coap_pkt->proxy_uri_len = option_length;
612 LOG_DBG_("Proxy-Uri NOT IMPLEMENTED [");
613 LOG_DBG_COAP_STRING(coap_pkt->proxy_uri, coap_pkt->proxy_uri_len);
614 LOG_DBG_("]\n");
615#endif /* COAP_PROXY_OPTION_PROCESSING */
616#if COAP_MESSAGE_ON_ERROR
617 coap_error_message = "This is a constrained server (Contiki-NG)";
618#endif
619 return PROXYING_NOT_SUPPORTED_5_05;
620 break;
621 case COAP_OPTION_PROXY_SCHEME:
622#if COAP_PROXY_OPTION_PROCESSING
623 coap_pkt->proxy_scheme = (char *)current_option;
624 coap_pkt->proxy_scheme_len = option_length;
625 LOG_DBG_("Proxy-Scheme NOT IMPLEMENTED [");
626 LOG_DBG_COAP_STRING(coap_pkt->proxy_scheme, coap_pkt->proxy_scheme_len);
627 LOG_DBG_("]\n");
628#endif
629#if COAP_MESSAGE_ON_ERROR
630 coap_error_message = "This is a constrained server (Contiki-NG)";
631#endif
632 return PROXYING_NOT_SUPPORTED_5_05;
633 break;
634
635 case COAP_OPTION_URI_HOST:
636 coap_pkt->uri_host = (char *)current_option;
637 coap_pkt->uri_host_len = option_length;
638 LOG_DBG_("Uri-Host [");
639 LOG_DBG_COAP_STRING(coap_pkt->uri_host, coap_pkt->uri_host_len);
640 LOG_DBG_("]\n");
641 break;
642 case COAP_OPTION_URI_PORT:
643 coap_pkt->uri_port = coap_parse_int_option(current_option,
644 option_length);
645 LOG_DBG_("Uri-Port [%u]\n", coap_pkt->uri_port);
646 break;
647 case COAP_OPTION_URI_PATH:
648 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
649 coap_merge_multi_option((char **)&(coap_pkt->uri_path),
650 &(coap_pkt->uri_path_len), current_option,
651 option_length, '/');
652 LOG_DBG_("Uri-Path [");
653 LOG_DBG_COAP_STRING(coap_pkt->uri_path, coap_pkt->uri_path_len);
654 LOG_DBG_("]\n");
655 break;
656 case COAP_OPTION_URI_QUERY:
657 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
658 coap_merge_multi_option((char **)&(coap_pkt->uri_query),
659 &(coap_pkt->uri_query_len), current_option,
660 option_length, '&');
661 LOG_DBG_("Uri-Query[");
662 LOG_DBG_COAP_STRING(coap_pkt->uri_query, coap_pkt->uri_query_len);
663 LOG_DBG_("]\n");
664 break;
665
666 case COAP_OPTION_LOCATION_PATH:
667 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
668 coap_merge_multi_option((char **)&(coap_pkt->location_path),
669 &(coap_pkt->location_path_len), current_option,
670 option_length, '/');
671
672 LOG_DBG_("Location-Path [");
673 LOG_DBG_COAP_STRING(coap_pkt->location_path, coap_pkt->location_path_len);
674 LOG_DBG_("]\n");
675 break;
676 case COAP_OPTION_LOCATION_QUERY:
677 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
678 coap_merge_multi_option((char **)&(coap_pkt->location_query),
679 &(coap_pkt->location_query_len), current_option,
680 option_length, '&');
681 LOG_DBG_("Location-Query [");
682 LOG_DBG_COAP_STRING(coap_pkt->location_query, coap_pkt->location_query_len);
683 LOG_DBG_("]\n");
684 break;
685
686 case COAP_OPTION_OBSERVE:
687 coap_pkt->observe = coap_parse_int_option(current_option,
688 option_length);
689 LOG_DBG_("Observe [%"PRId32"]\n", coap_pkt->observe);
690 break;
691 case COAP_OPTION_BLOCK2:
692 coap_pkt->block2_num = coap_parse_int_option(current_option,
693 option_length);
694 coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3;
695 coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07);
696 coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)
697 << (coap_pkt->block2_num & 0x07);
698 coap_pkt->block2_num >>= 4;
699 LOG_DBG_("Block2 [%lu%s (%u B/blk)]\n",
700 (unsigned long)coap_pkt->block2_num,
701 coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size);
702 break;
703 case COAP_OPTION_BLOCK1:
704 coap_pkt->block1_num = coap_parse_int_option(current_option,
705 option_length);
706 coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3;
707 coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07);
708 coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F)
709 << (coap_pkt->block1_num & 0x07);
710 coap_pkt->block1_num >>= 4;
711 LOG_DBG_("Block1 [%lu%s (%u B/blk)]\n",
712 (unsigned long)coap_pkt->block1_num,
713 coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size);
714 break;
715 case COAP_OPTION_SIZE2:
716 coap_pkt->size2 = coap_parse_int_option(current_option, option_length);
717 LOG_DBG_("Size2 [%"PRIu32"]\n", coap_pkt->size2);
718 break;
719 case COAP_OPTION_SIZE1:
720 coap_pkt->size1 = coap_parse_int_option(current_option, option_length);
721 LOG_DBG_("Size1 [%"PRIu32"]\n", coap_pkt->size1);
722 break;
723 default:
724 LOG_DBG_("unknown (%"PRIu32")\n", option_number);
725 /* check if critical (odd) */
726 if(option_number & 1) {
727#if COAP_MESSAGE_ON_ERROR
728 coap_error_message = "Unsupported critical option";
729#endif
730 return BAD_OPTION_4_02;
731 }
732 }
733
734 current_option += option_length;
735 } /* for */
736 LOG_DBG("-Done parsing-------\n");
737
738 return NO_ERROR;
739}
740/*---------------------------------------------------------------------------*/
741/*- CoAP Engine API ---------------------------------------------------------*/
742/*---------------------------------------------------------------------------*/
743int
744coap_get_query_variable(const coap_message_t *coap_pkt,
745 const char *name, const char **output)
746{
747 if(coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
748 return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len,
749 name, output);
750 }
751 return 0;
752}
753int
754coap_get_post_variable(const coap_message_t *coap_pkt,
755 const char *name, const char **output)
756{
757 if(coap_pkt->payload_len) {
758 return coap_get_variable((const char *)coap_pkt->payload,
759 coap_pkt->payload_len, name, output);
760 }
761 return 0;
762}
763/*---------------------------------------------------------------------------*/
764int
765coap_set_status_code(coap_message_t *message, unsigned int code)
766{
767 if(code <= 0xFF) {
768 message->code = (uint8_t)code;
769 return 1;
770 } else {
771 return 0;
772 }
773}
774/*---------------------------------------------------------------------------*/
775int
776coap_set_token(coap_message_t *coap_pkt, const uint8_t *token, size_t token_len)
777{
778 coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len);
779 memcpy(coap_pkt->token, token, coap_pkt->token_len);
780
781 return coap_pkt->token_len;
782}
783/*---------------------------------------------------------------------------*/
784/*- CoAP Implementation API -------------------------------------------------*/
785/*---------------------------------------------------------------------------*/
786int
787coap_get_header_content_format(const coap_message_t *coap_pkt,
788 unsigned int *format)
789{
790 if(!coap_is_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) {
791 return 0;
792 }
793 *format = coap_pkt->content_format;
794 return 1;
795}
796int
797coap_set_header_content_format(coap_message_t *coap_pkt, unsigned int format)
798{
799 coap_pkt->content_format = format;
800 coap_set_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT);
801 return 1;
802}
803/*---------------------------------------------------------------------------*/
804int
805coap_get_header_accept(const coap_message_t *coap_pkt, unsigned int *accept)
806{
807 if(!coap_is_option(coap_pkt, COAP_OPTION_ACCEPT)) {
808 return 0;
809 }
810 *accept = coap_pkt->accept;
811 return 1;
812}
813int
814coap_set_header_accept(coap_message_t *coap_pkt, unsigned int accept)
815{
816 coap_pkt->accept = accept;
817 coap_set_option(coap_pkt, COAP_OPTION_ACCEPT);
818 return 1;
819}
820/*---------------------------------------------------------------------------*/
821int
822coap_get_header_max_age(const coap_message_t *coap_pkt, uint32_t *age)
823{
824 if(!coap_is_option(coap_pkt, COAP_OPTION_MAX_AGE)) {
825 *age = COAP_DEFAULT_MAX_AGE;
826 } else {
827 *age = coap_pkt->max_age;
828 } return 1;
829}
830int
831coap_set_header_max_age(coap_message_t *coap_pkt, uint32_t age)
832{
833 coap_pkt->max_age = age;
834 coap_set_option(coap_pkt, COAP_OPTION_MAX_AGE);
835 return 1;
836}
837/*---------------------------------------------------------------------------*/
838int
839coap_get_header_etag(const coap_message_t *coap_pkt, const uint8_t **etag)
840{
841 if(!coap_is_option(coap_pkt, COAP_OPTION_ETAG)) {
842 return 0;
843 }
844 *etag = coap_pkt->etag;
845 return coap_pkt->etag_len;
846}
847int
848coap_set_header_etag(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
849{
850 coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len);
851 memcpy(coap_pkt->etag, etag, coap_pkt->etag_len);
852
853 coap_set_option(coap_pkt, COAP_OPTION_ETAG);
854 return coap_pkt->etag_len;
855}
856/*---------------------------------------------------------------------------*/
857/*FIXME support multiple ETags */
858int
859coap_get_header_if_match(const coap_message_t *coap_pkt, const uint8_t **etag)
860{
861 if(!coap_is_option(coap_pkt, COAP_OPTION_IF_MATCH)) {
862 return 0;
863 }
864 *etag = coap_pkt->if_match;
865 return coap_pkt->if_match_len;
866}
867int
868coap_set_header_if_match(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
869{
870 coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len);
871 memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len);
872
873 coap_set_option(coap_pkt, COAP_OPTION_IF_MATCH);
874 return coap_pkt->if_match_len;
875}
876/*---------------------------------------------------------------------------*/
877int
878coap_get_header_if_none_match(const coap_message_t *message)
879{
880 return coap_is_option(message, COAP_OPTION_IF_NONE_MATCH) ? 1 : 0;
881}
882int
883coap_set_header_if_none_match(coap_message_t *message)
884{
885 coap_set_option(message, COAP_OPTION_IF_NONE_MATCH);
886 return 1;
887}
888/*---------------------------------------------------------------------------*/
889int
890coap_get_header_proxy_uri(const coap_message_t *coap_pkt, const char **uri)
891{
892 if(!coap_is_option(coap_pkt, COAP_OPTION_PROXY_URI)) {
893 return 0;
894 }
895 *uri = coap_pkt->proxy_uri;
896 return coap_pkt->proxy_uri_len;
897}
898int
899coap_set_header_proxy_uri(coap_message_t *coap_pkt, const char *uri)
900{
901 /* TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide coap-conf define */
902
903 coap_pkt->proxy_uri = uri;
904 coap_pkt->proxy_uri_len = strlen(uri);
905
906 coap_set_option(coap_pkt, COAP_OPTION_PROXY_URI);
907 return coap_pkt->proxy_uri_len;
908}
909/*---------------------------------------------------------------------------*/
910int
911coap_get_header_uri_host(const coap_message_t *coap_pkt, const char **host)
912{
913 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_HOST)) {
914 return 0;
915 }
916 *host = coap_pkt->uri_host;
917 return coap_pkt->uri_host_len;
918}
919int
920coap_set_header_uri_host(coap_message_t *coap_pkt, const char *host)
921{
922 coap_pkt->uri_host = host;
923 coap_pkt->uri_host_len = strlen(host);
924
925 coap_set_option(coap_pkt, COAP_OPTION_URI_HOST);
926 return coap_pkt->uri_host_len;
927}
928/*---------------------------------------------------------------------------*/
929int
930coap_get_header_uri_path(const coap_message_t *coap_pkt, const char **path)
931{
932 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_PATH)) {
933 return 0;
934 }
935 *path = coap_pkt->uri_path;
936 return coap_pkt->uri_path_len;
937}
938int
939coap_set_header_uri_path(coap_message_t *coap_pkt, const char *path)
940{
941 while(path[0] == '/') {
942 ++path;
943 }
944
945 coap_pkt->uri_path = path;
946 coap_pkt->uri_path_len = strlen(path);
947
948 coap_set_option(coap_pkt, COAP_OPTION_URI_PATH);
949 return coap_pkt->uri_path_len;
950}
951/*---------------------------------------------------------------------------*/
952int
953coap_get_header_uri_query(const coap_message_t *coap_pkt,
954 const char **query)
955{
956 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
957 return 0;
958 }
959 *query = coap_pkt->uri_query;
960 return coap_pkt->uri_query_len;
961}
962int
963coap_set_header_uri_query(coap_message_t *coap_pkt, const char *query)
964{
965 while(query[0] == '?') {
966 ++query;
967 }
968
969 coap_pkt->uri_query = query;
970 coap_pkt->uri_query_len = strlen(query);
971
972 coap_set_option(coap_pkt, COAP_OPTION_URI_QUERY);
973 return coap_pkt->uri_query_len;
974}
975/*---------------------------------------------------------------------------*/
976int
977coap_get_header_location_path(const coap_message_t *coap_pkt,
978 const char **path)
979{
980 if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_PATH)) {
981 return 0;
982 }
983 *path = coap_pkt->location_path;
984 return coap_pkt->location_path_len;
985}
986int
987coap_set_header_location_path(coap_message_t *coap_pkt, const char *path)
988{
989 char *query;
990
991 while(path[0] == '/') {
992 ++path;
993 }
994
995 if((query = strchr(path, '?'))) {
996 coap_set_header_location_query(coap_pkt, query + 1);
997 coap_pkt->location_path_len = query - path;
998 } else {
999 coap_pkt->location_path_len = strlen(path);
1000 } coap_pkt->location_path = path;
1001
1002 if(coap_pkt->location_path_len > 0) {
1003 coap_set_option(coap_pkt, COAP_OPTION_LOCATION_PATH);
1004 }
1005 return coap_pkt->location_path_len;
1006}
1007/*---------------------------------------------------------------------------*/
1008int
1009coap_get_header_location_query(const coap_message_t *coap_pkt,
1010 const char **query)
1011{
1012 if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_QUERY)) {
1013 return 0;
1014 }
1015 *query = coap_pkt->location_query;
1016 return coap_pkt->location_query_len;
1017}
1018int
1019coap_set_header_location_query(coap_message_t *coap_pkt, const char *query)
1020{
1021 while(query[0] == '?') {
1022 ++query;
1023 }
1024
1025 coap_pkt->location_query = query;
1026 coap_pkt->location_query_len = strlen(query);
1027
1028 coap_set_option(coap_pkt, COAP_OPTION_LOCATION_QUERY);
1029 return coap_pkt->location_query_len;
1030}
1031/*---------------------------------------------------------------------------*/
1032int
1033coap_get_header_observe(const coap_message_t *coap_pkt, uint32_t *observe)
1034{
1035 if(!coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) {
1036 return 0;
1037 }
1038 *observe = coap_pkt->observe;
1039 return 1;
1040}
1041int
1042coap_set_header_observe(coap_message_t *coap_pkt, uint32_t observe)
1043{
1044 coap_pkt->observe = observe;
1045 coap_set_option(coap_pkt, COAP_OPTION_OBSERVE);
1046 return 1;
1047}
1048/*---------------------------------------------------------------------------*/
1049int
1050coap_get_header_block2(const coap_message_t *coap_pkt, uint32_t *num,
1051 uint8_t *more, uint16_t *size, uint32_t *offset)
1052{
1053 if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK2)) {
1054 return 0;
1055 }
1056 /* pointers may be NULL to get only specific block parameters */
1057 if(num != NULL) {
1058 *num = coap_pkt->block2_num;
1059 }
1060 if(more != NULL) {
1061 *more = coap_pkt->block2_more;
1062 }
1063 if(size != NULL) {
1064 *size = coap_pkt->block2_size;
1065 }
1066 if(offset != NULL) {
1067 *offset = coap_pkt->block2_offset;
1068 }
1069 return 1;
1070}
1071int
1072coap_set_header_block2(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1073 uint16_t size)
1074{
1075 if(size < 16) {
1076 return 0;
1077 }
1078 if(size > 2048) {
1079 return 0;
1080 }
1081 if(num > 0x0FFFFF) {
1082 return 0;
1083 }
1084 coap_pkt->block2_num = num;
1085 coap_pkt->block2_more = more ? 1 : 0;
1086 coap_pkt->block2_size = size;
1087
1088 coap_set_option(coap_pkt, COAP_OPTION_BLOCK2);
1089 return 1;
1090}
1091/*---------------------------------------------------------------------------*/
1092int
1093coap_get_header_block1(const coap_message_t *coap_pkt, uint32_t *num,
1094 uint8_t *more, uint16_t *size, uint32_t *offset)
1095{
1096 if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK1)) {
1097 return 0;
1098 }
1099 /* pointers may be NULL to get only specific block parameters */
1100 if(num != NULL) {
1101 *num = coap_pkt->block1_num;
1102 }
1103 if(more != NULL) {
1104 *more = coap_pkt->block1_more;
1105 }
1106 if(size != NULL) {
1107 *size = coap_pkt->block1_size;
1108 }
1109 if(offset != NULL) {
1110 *offset = coap_pkt->block1_offset;
1111 }
1112 return 1;
1113}
1114int
1115coap_set_header_block1(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1116 uint16_t size)
1117{
1118 if(size < 16) {
1119 return 0;
1120 }
1121 if(size > 2048) {
1122 return 0;
1123 }
1124 if(num > 0x0FFFFF) {
1125 return 0;
1126 }
1127 coap_pkt->block1_num = num;
1128 coap_pkt->block1_more = more;
1129 coap_pkt->block1_size = size;
1130
1131 coap_set_option(coap_pkt, COAP_OPTION_BLOCK1);
1132 return 1;
1133}
1134/*---------------------------------------------------------------------------*/
1135int
1136coap_get_header_size2(const coap_message_t *coap_pkt, uint32_t *size)
1137{
1138 if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE2)) {
1139 return 0;
1140 }
1141 *size = coap_pkt->size2;
1142 return 1;
1143}
1144int
1145coap_set_header_size2(coap_message_t *coap_pkt, uint32_t size)
1146{
1147 coap_pkt->size2 = size;
1148 coap_set_option(coap_pkt, COAP_OPTION_SIZE2);
1149 return 1;
1150}
1151/*---------------------------------------------------------------------------*/
1152int
1153coap_get_header_size1(const coap_message_t *coap_pkt, uint32_t *size)
1154{
1155 if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE1)) {
1156 return 0;
1157 }
1158 *size = coap_pkt->size1;
1159 return 1;
1160}
1161int
1162coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size)
1163{
1164 coap_pkt->size1 = size;
1165 coap_set_option(coap_pkt, COAP_OPTION_SIZE1);
1166 return 1;
1167}
1168/*---------------------------------------------------------------------------*/
1169int
1170coap_get_payload(const coap_message_t *coap_pkt, const uint8_t **payload)
1171{
1172 if(payload != NULL) {
1173 *payload = coap_pkt->payload;
1174 }
1175 return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0;
1176}
1177int
1178coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length)
1179{
1180 coap_pkt->payload = (uint8_t *)payload;
1181 coap_pkt->payload_len = MIN(COAP_MAX_CHUNK_SIZE, length);
1182
1183 return coap_pkt->payload_len;
1184}
1185/*---------------------------------------------------------------------------*/
1186/** @} */
Default definitions of C compiler quirk work-arounds.
Log support for CoAP.
CoAP module for reliable transport.
An implementation of the Constrained Application Protocol (RFC 7252).
static uint8_t accept(uint8_t in)
Definition mpl.c:1390
static void start(void)
Start measurement.
Header file for generating non-cryptographic random numbers.