• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_internal.h"
10 
11 #if defined(HAVE_LIMITS_H)
12 #include <limits.h>
13 #endif
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
21 #ifdef HAVE_WINSOCK2_H
22 #include <winsock2.h>
23 #endif
24 
25 #ifndef min
26 #define min(a,b) ((a) < (b) ? (a) : (b))
27 #endif
28 
29 #ifndef max
30 #define max(a,b) ((a) > (b) ? (a) : (b))
31 #endif
32 
33 void
coap_pdu_clear(coap_pdu_t * pdu,size_t size)34 coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
35   assert(pdu);
36   assert(pdu->token);
37   assert(pdu->max_hdr_size >= COAP_PDU_MAX_UDP_HEADER_SIZE);
38   if (pdu->alloc_size > size)
39     pdu->alloc_size = size;
40   pdu->type = 0;
41   pdu->code = 0;
42   pdu->hdr_size = 0;
43   pdu->token_length = 0;
44   pdu->tid = 0;
45   pdu->max_delta = 0;
46   pdu->max_size = size;
47   pdu->used_size = 0;
48   pdu->data = NULL;
49 }
50 
51 #ifdef WITH_LWIP
52 coap_pdu_t *
coap_pdu_from_pbuf(struct pbuf * pbuf)53 coap_pdu_from_pbuf( struct pbuf *pbuf )
54 {
55   coap_pdu_t *pdu;
56 
57   if (pbuf == NULL) return NULL;
58 
59   LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
60   LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
61 
62   pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t) );
63   if (!pdu) {
64     pbuf_free(pbuf);
65     return NULL;
66   }
67 
68   pdu->max_hdr_size = COAP_PDU_MAX_UDP_HEADER_SIZE;
69   pdu->pbuf = pbuf;
70   pdu->token = (uint8_t *)pbuf->payload + pdu->max_hdr_size;
71   pdu->alloc_size = pbuf->tot_len - pdu->max_hdr_size;
72   coap_pdu_clear(pdu, pdu->alloc_size);
73 
74   return pdu;
75 }
76 #endif
77 
78 coap_pdu_t *
coap_pdu_init(uint8_t type,uint8_t code,uint16_t tid,size_t size)79 coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size) {
80   coap_pdu_t *pdu;
81 
82   pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
83   if (!pdu) return NULL;
84 
85 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
86   assert(size <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4);
87   if (size > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
88     return NULL;
89   pdu->max_hdr_size = COAP_PDU_MAX_UDP_HEADER_SIZE;
90 #else
91   pdu->max_hdr_size = COAP_PDU_MAX_TCP_HEADER_SIZE;
92 #endif
93 
94 #ifdef WITH_LWIP
95   pdu->pbuf = pbuf_alloc(PBUF_TRANSPORT, size + pdu->max_hdr_size, PBUF_RAM);
96   if (pdu->pbuf == NULL) {
97     coap_free_type(COAP_PDU, pdu);
98     return NULL;
99   }
100   pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
101 #else /* WITH_LWIP */
102   uint8_t *buf;
103   pdu->alloc_size = min(size, 256);
104   buf = coap_malloc_type(COAP_PDU_BUF, pdu->alloc_size + pdu->max_hdr_size);
105   if (buf == NULL) {
106     coap_free_type(COAP_PDU, pdu);
107     return NULL;
108   }
109   pdu->token = buf + pdu->max_hdr_size;
110 #endif /* WITH_LWIP */
111   coap_pdu_clear(pdu, size);
112   pdu->tid = tid;
113   pdu->type = type;
114   pdu->code = code;
115   return pdu;
116 }
117 
118 coap_pdu_t *
coap_new_pdu(const struct coap_session_t * session)119 coap_new_pdu(const struct coap_session_t *session) {
120   coap_pdu_t *pdu = coap_pdu_init(0, 0, 0, coap_session_max_pdu_size(session));
121   if (!pdu)
122     coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
123   return pdu;
124 }
125 
126 void
coap_delete_pdu(coap_pdu_t * pdu)127 coap_delete_pdu(coap_pdu_t *pdu) {
128   if (pdu != NULL) {
129 #ifdef WITH_LWIP
130     pbuf_free(pdu->pbuf);
131 #else
132     if (pdu->token != NULL)
133       coap_free_type(COAP_PDU_BUF, pdu->token - pdu->max_hdr_size);
134 #endif
135     coap_free_type(COAP_PDU, pdu);
136   }
137 }
138 
139 int
coap_pdu_resize(coap_pdu_t * pdu,size_t new_size)140 coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
141   if (new_size > pdu->alloc_size) {
142 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
143     uint8_t *new_hdr;
144     size_t offset;
145 #endif
146     if (pdu->max_size && new_size > pdu->max_size) {
147       coap_log(LOG_WARNING, "coap_pdu_resize: pdu too big\n");
148       return 0;
149     }
150 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
151     if (pdu->data != NULL) {
152       assert(pdu->data > pdu->token);
153       offset = pdu->data - pdu->token;
154     } else {
155       offset = 0;
156     }
157     new_hdr = (uint8_t*)realloc(pdu->token - pdu->max_hdr_size, new_size + pdu->max_hdr_size);
158     if (new_hdr == NULL) {
159       coap_log(LOG_WARNING, "coap_pdu_resize: realloc failed\n");
160       return 0;
161     }
162     pdu->token = new_hdr + pdu->max_hdr_size;
163     if (offset > 0)
164       pdu->data = pdu->token + offset;
165     else
166       pdu->data = NULL;
167 #endif
168   }
169   pdu->alloc_size = new_size;
170   return 1;
171 }
172 
173 static int
coap_pdu_check_resize(coap_pdu_t * pdu,size_t size)174 coap_pdu_check_resize(coap_pdu_t *pdu, size_t size) {
175   if (size > pdu->alloc_size) {
176     size_t new_size = max(256, pdu->alloc_size * 2);
177     while (size > new_size)
178       new_size *= 2;
179     if (pdu->max_size && new_size > pdu->max_size) {
180       new_size = pdu->max_size;
181       if (new_size < size)
182         return 0;
183     }
184     if (!coap_pdu_resize(pdu, new_size))
185       return 0;
186   }
187   return 1;
188 }
189 
190 int
coap_add_token(coap_pdu_t * pdu,size_t len,const uint8_t * data)191 coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
192   /* must allow for pdu == NULL as callers may rely on this */
193   if (!pdu || len > 8)
194     return 0;
195 
196   if (pdu->used_size) {
197     coap_log(LOG_WARNING,
198              "coap_add_token: The token must defined first. Token ignored\n");
199     return 0;
200   }
201   if (!coap_pdu_check_resize(pdu, len))
202     return 0;
203   pdu->token_length = (uint8_t)len;
204   if (len)
205     memcpy(pdu->token, data, len);
206   pdu->max_delta = 0;
207   pdu->used_size = len;
208   pdu->data = NULL;
209 
210   return 1;
211 }
212 
213 /* FIXME: de-duplicate code with coap_add_option_later */
214 size_t
coap_add_option(coap_pdu_t * pdu,uint16_t type,size_t len,const uint8_t * data)215 coap_add_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data) {
216   size_t optsize;
217   coap_opt_t *opt;
218 
219   assert(pdu);
220   pdu->data = NULL;
221 
222   if (type < pdu->max_delta) {
223     coap_log(LOG_WARNING,
224              "coap_add_option: options are not in correct order\n");
225     return 0;
226   }
227 
228   if (!coap_pdu_check_resize(pdu,
229       pdu->used_size + coap_opt_encode_size(type - pdu->max_delta, len)))
230     return 0;
231 
232   opt = pdu->token + pdu->used_size;
233 
234   /* encode option and check length */
235   optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
236                             type - pdu->max_delta, data, len);
237 
238   if (!optsize) {
239     coap_log(LOG_WARNING, "coap_add_option: cannot add option\n");
240     /* error */
241     return 0;
242   } else {
243     pdu->max_delta = type;
244     pdu->used_size += optsize;
245   }
246 
247   return optsize;
248 }
249 
250 /* FIXME: de-duplicate code with coap_add_option */
251 uint8_t*
coap_add_option_later(coap_pdu_t * pdu,uint16_t type,size_t len)252 coap_add_option_later(coap_pdu_t *pdu, uint16_t type, size_t len) {
253   size_t optsize;
254   coap_opt_t *opt;
255 
256   assert(pdu);
257   pdu->data = NULL;
258 
259   if (type < pdu->max_delta) {
260     coap_log(LOG_WARNING,
261              "coap_add_option: options are not in correct order\n");
262     return NULL;
263   }
264 
265   if (!coap_pdu_check_resize(pdu,
266       pdu->used_size + coap_opt_encode_size(type - pdu->max_delta, len)))
267     return 0;
268 
269   opt = pdu->token + pdu->used_size;
270 
271   /* encode option and check length */
272   optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
273                             type - pdu->max_delta, NULL, len);
274 
275   if (!optsize) {
276     coap_log(LOG_WARNING, "coap_add_option: cannot add option\n");
277     /* error */
278     return NULL;
279   } else {
280     pdu->max_delta = type;
281     pdu->used_size += (uint16_t)optsize;
282   }
283 
284   return opt + optsize - len;
285 }
286 
287 int
coap_add_data(coap_pdu_t * pdu,size_t len,const uint8_t * data)288 coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
289   if (len == 0) {
290     return 1;
291   } else {
292     uint8_t *payload = coap_add_data_after(pdu, len);
293     if (payload != NULL)
294       memcpy(payload, data, len);
295     return payload != NULL;
296   }
297 }
298 
299 uint8_t *
coap_add_data_after(coap_pdu_t * pdu,size_t len)300 coap_add_data_after(coap_pdu_t *pdu, size_t len) {
301   assert(pdu);
302   assert(pdu->data == NULL);
303 
304   pdu->data = NULL;
305 
306   if (len == 0)
307     return NULL;
308 
309   if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
310     return 0;
311   pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
312   pdu->data = pdu->token + pdu->used_size;
313   pdu->used_size += len;
314   return pdu->data;
315 }
316 
317 int
coap_get_data(const coap_pdu_t * pdu,size_t * len,uint8_t ** data)318 coap_get_data(const coap_pdu_t *pdu, size_t *len, uint8_t **data) {
319   assert(pdu);
320   assert(len);
321   assert(data);
322 
323   *data = pdu->data;
324   if(pdu->data == NULL) {
325      *len = 0;
326      return 0;
327   }
328 
329   *len = pdu->used_size - (pdu->data - pdu->token);
330 
331   return 1;
332 }
333 
334 #ifndef SHORT_ERROR_RESPONSE
335 typedef struct {
336   unsigned char code;
337   const char *phrase;
338 } error_desc_t;
339 
340 /* if you change anything here, make sure, that the longest string does not
341  * exceed COAP_ERROR_PHRASE_LENGTH. */
342 error_desc_t coap_error[] = {
343   { COAP_RESPONSE_CODE(201), "Created" },
344   { COAP_RESPONSE_CODE(202), "Deleted" },
345   { COAP_RESPONSE_CODE(203), "Valid" },
346   { COAP_RESPONSE_CODE(204), "Changed" },
347   { COAP_RESPONSE_CODE(205), "Content" },
348   { COAP_RESPONSE_CODE(231), "Continue" },
349   { COAP_RESPONSE_CODE(400), "Bad Request" },
350   { COAP_RESPONSE_CODE(401), "Unauthorized" },
351   { COAP_RESPONSE_CODE(402), "Bad Option" },
352   { COAP_RESPONSE_CODE(403), "Forbidden" },
353   { COAP_RESPONSE_CODE(404), "Not Found" },
354   { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
355   { COAP_RESPONSE_CODE(406), "Not Acceptable" },
356   { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
357   { COAP_RESPONSE_CODE(412), "Precondition Failed" },
358   { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
359   { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
360   { COAP_RESPONSE_CODE(500), "Internal Server Error" },
361   { COAP_RESPONSE_CODE(501), "Not Implemented" },
362   { COAP_RESPONSE_CODE(502), "Bad Gateway" },
363   { COAP_RESPONSE_CODE(503), "Service Unavailable" },
364   { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
365   { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
366   { 0, NULL }                        /* end marker */
367 };
368 
369 const char *
coap_response_phrase(unsigned char code)370 coap_response_phrase(unsigned char code) {
371   int i;
372   for (i = 0; coap_error[i].code; ++i) {
373     if (coap_error[i].code == code)
374       return coap_error[i].phrase;
375   }
376   return NULL;
377 }
378 #endif
379 
380 /**
381  * Advances *optp to next option if still in PDU. This function
382  * returns the number of bytes opt has been advanced or @c 0
383  * on error.
384  */
385 static size_t
next_option_safe(coap_opt_t ** optp,size_t * length)386 next_option_safe(coap_opt_t **optp, size_t *length) {
387   coap_option_t option;
388   size_t optsize;
389 
390   assert(optp); assert(*optp);
391   assert(length);
392 
393   optsize = coap_opt_parse(*optp, *length, &option);
394   if (optsize) {
395     assert(optsize <= *length);
396 
397     *optp += optsize;
398     *length -= optsize;
399   }
400 
401   return optsize;
402 }
403 
404 size_t
coap_pdu_parse_header_size(coap_proto_t proto,const uint8_t * data)405 coap_pdu_parse_header_size(coap_proto_t proto,
406                            const uint8_t *data) {
407   assert(data);
408   size_t header_size = 0;
409 
410   if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
411     uint8_t len = *data >> 4;
412     if (len < 13)
413       header_size = 2;
414     else if (len==13)
415       header_size = 3;
416     else if (len==14)
417       header_size = 4;
418     else
419       header_size = 6;
420   } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
421     header_size = 4;
422   }
423 
424   return header_size;
425 }
426 
427 size_t
coap_pdu_parse_size(coap_proto_t proto,const uint8_t * data,size_t length)428 coap_pdu_parse_size(coap_proto_t proto,
429                     const uint8_t *data,
430                     size_t length) {
431   assert(data);
432   assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS);
433   assert(coap_pdu_parse_header_size(proto, data) <= length );
434 
435   size_t size = 0;
436 
437   if ((proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) && length >= 1) {
438     uint8_t len = *data >> 4;
439     if (len < 13) {
440       size = len;
441     } else if (length >= 2) {
442       if (len==13) {
443         size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
444       } else if (length >= 3) {
445         if (len==14) {
446           size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
447         } else if (length >= 5) {
448           size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
449                + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
450         }
451       }
452     }
453     size += data[0] & 0x0f;
454   }
455 
456   return size;
457 }
458 
459 int
coap_pdu_parse_header(coap_pdu_t * pdu,coap_proto_t proto)460 coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto) {
461   uint8_t *hdr = pdu->token - pdu->hdr_size;
462   if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
463     assert(pdu->hdr_size == 4);
464     if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
465       coap_log(LOG_DEBUG, "coap_pdu_parse: UDP version not supported\n");
466       return 0;
467     }
468     pdu->type = (hdr[0] >> 4) & 0x03;
469     pdu->token_length = hdr[0] & 0x0f;
470     pdu->code = hdr[1];
471     pdu->tid = (uint16_t)hdr[2] << 8 | hdr[3];
472   } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
473     assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
474     pdu->type = COAP_MESSAGE_CON;
475     pdu->token_length = hdr[0] & 0x0f;
476     pdu->code = hdr[pdu->hdr_size-1];
477     pdu->tid = 0;
478   } else {
479     coap_log(LOG_DEBUG, "coap_pdu_parse: unsupported protocol\n");
480     return 0;
481   }
482   if (pdu->token_length > pdu->alloc_size) {
483     /* Invalid PDU provided - not wise to assert here though */
484     coap_log(LOG_DEBUG, "coap_pdu_parse: PDU header token size broken\n");
485     pdu->token_length = (uint8_t)pdu->alloc_size;
486     return 0;
487   }
488   return 1;
489 }
490 
491 int
coap_pdu_parse_opt(coap_pdu_t * pdu)492 coap_pdu_parse_opt(coap_pdu_t *pdu) {
493 
494   /* sanity checks */
495   if (pdu->code == 0) {
496     if (pdu->used_size != 0 || pdu->token_length) {
497       coap_log(LOG_DEBUG, "coap_pdu_parse: empty message is not empty\n");
498       return 0;
499     }
500   }
501 
502   if (pdu->token_length > pdu->used_size || pdu->token_length > 8) {
503     coap_log(LOG_DEBUG, "coap_pdu_parse: invalid Token\n");
504     return 0;
505   }
506 
507   if (pdu->code == 0) {
508     /* empty packet */
509     pdu->used_size = 0;
510     pdu->data = NULL;
511   } else {
512     /* skip header + token */
513     coap_opt_t *opt = pdu->token + pdu->token_length;
514     size_t length = pdu->used_size - pdu->token_length;
515 
516     while (length > 0 && *opt != COAP_PAYLOAD_START) {
517       if ( !next_option_safe( &opt, (size_t *)&length ) ) {
518         coap_log(LOG_DEBUG, "coap_pdu_parse: missing payload start code\n");
519         return 0;
520       }
521     }
522 
523     if (length > 0) {
524       assert(*opt == COAP_PAYLOAD_START);
525       opt++; length--;
526 
527       if (length == 0) {
528         coap_log(LOG_DEBUG,
529                  "coap_pdu_parse: message ending in payload start marker\n");
530         return 0;
531       }
532     }
533     if (length > 0)
534                 pdu->data = (uint8_t*)opt;
535     else
536       pdu->data = NULL;
537   }
538 
539   return 1;
540 }
541 
542 int
coap_pdu_parse(coap_proto_t proto,const uint8_t * data,size_t length,coap_pdu_t * pdu)543 coap_pdu_parse(coap_proto_t proto,
544                const uint8_t *data,
545                size_t length,
546                coap_pdu_t *pdu)
547 {
548   size_t hdr_size;
549 
550   if (length == 0)
551     return 0;
552   hdr_size = coap_pdu_parse_header_size(proto, data);
553   if (!hdr_size || hdr_size > length)
554     return 0;
555   if (hdr_size > pdu->max_hdr_size)
556     return 0;
557   if (!coap_pdu_resize(pdu, length - hdr_size))
558     return 0;
559 #ifndef WITH_LWIP
560   memcpy(pdu->token - hdr_size, data, length);
561 #endif
562   pdu->hdr_size = (uint8_t)hdr_size;
563   pdu->used_size = length - hdr_size;
564   return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu);
565 }
566 
567 size_t
coap_pdu_encode_header(coap_pdu_t * pdu,coap_proto_t proto)568 coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto) {
569   if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
570     assert(pdu->max_hdr_size >= 4);
571     if (pdu->max_hdr_size < 4) {
572       coap_log(LOG_WARNING,
573            "coap_pdu_encode_header: not enough space for UDP-style header\n");
574       return 0;
575     }
576     pdu->token[-4] = COAP_DEFAULT_VERSION << 6
577                    | pdu->type << 4
578                    | pdu->token_length;
579     pdu->token[-3] = pdu->code;
580     pdu->token[-2] = (uint8_t)(pdu->tid >> 8);
581     pdu->token[-1] = (uint8_t)(pdu->tid);
582     pdu->hdr_size = 4;
583   } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
584     size_t len;
585     assert(pdu->used_size >= pdu->token_length);
586     if (pdu->used_size < pdu->token_length) {
587       coap_log(LOG_WARNING, "coap_pdu_encode_header: corrupted PDU\n");
588       return 0;
589     }
590     len = pdu->used_size - pdu->token_length;
591     if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
592       assert(pdu->max_hdr_size >= 2);
593       if (pdu->max_hdr_size < 2) {
594         coap_log(LOG_WARNING,
595               "coap_pdu_encode_header: not enough space for TCP0 header\n");
596         return 0;
597       }
598       pdu->token[-2] = (uint8_t)len << 4
599                      | pdu->token_length;
600       pdu->token[-1] = pdu->code;
601       pdu->hdr_size = 2;
602     } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
603       assert(pdu->max_hdr_size >= 3);
604       if (pdu->max_hdr_size < 3) {
605         coap_log(LOG_WARNING,
606               "coap_pdu_encode_header: not enough space for TCP8 header\n");
607         return 0;
608       }
609       pdu->token[-3] = 13 << 4 | pdu->token_length;
610       pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
611       pdu->token[-1] = pdu->code;
612       pdu->hdr_size = 3;
613     } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
614       assert(pdu->max_hdr_size >= 4);
615       if (pdu->max_hdr_size < 4) {
616         coap_log(LOG_WARNING,
617               "coap_pdu_encode_header: not enough space for TCP16 header\n");
618         return 0;
619       }
620       pdu->token[-4] = 14 << 4 | pdu->token_length;
621       pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
622       pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
623       pdu->token[-1] = pdu->code;
624       pdu->hdr_size = 4;
625     } else {
626       assert(pdu->max_hdr_size >= 6);
627       if (pdu->max_hdr_size < 6) {
628         coap_log(LOG_WARNING,
629               "coap_pdu_encode_header: not enough space for TCP32 header\n");
630         return 0;
631       }
632       pdu->token[-6] = 15 << 4 | pdu->token_length;
633       pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
634       pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
635       pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
636       pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
637       pdu->token[-1] = pdu->code;
638       pdu->hdr_size = 6;
639     }
640   } else {
641     coap_log(LOG_WARNING, "coap_pdu_encode_header: unsupported protocol\n");
642   }
643   return pdu->hdr_size;
644 }
645