2 * Routines for CoAP packet disassembly
3 * draft-ietf-core-coap-14.txt
4 * draft-ietf-core-block-10.txt
5 * draft-ietf-core-observe-16.txt
6 * draft-ietf-core-link-format-06.txt
7 * Shoichi Sakane <sakane@tanu.org>
9 * Changes for draft-ietf-core-coap-17.txt
10 * Hauke Mehrtens <hauke@hauke-m.de>
12 * Support for CoAP over TCP, TLS and WebSockets
13 * https://tools.ietf.org/html/rfc8323
14 * Peter Wu <peter@lekensteyn.nl>
16 * Wireshark - Network traffic analyzer
17 * By Gerald Combs <gerald@wireshark.org>
18 * Copyright 1998 Gerald Combs
20 * SPDX-License-Identifier: GPL-2.0-or-later
26 #include <epan/conversation.h>
27 #include <epan/packet.h>
28 #include <epan/reassemble.h>
29 #include <epan/proto_data.h>
30 #include <epan/expert.h>
31 #include <epan/wmem_scopes.h>
32 #include <epan/to_str.h>
33 #include <epan/strutil.h>
34 #include <wsutil/array.h>
35 #include "packet-dtls.h"
36 #include "packet-coap.h"
37 #include "packet-media-type.h"
38 #include "packet-tcp.h"
39 #include "packet-tls.h"
41 void proto_register_coap(void);
43 static dissector_table_t coap_tmf_media_type_dissector_table
;
44 static dissector_table_t media_type_dissector_table
;
46 static int proto_coap
;
48 * Used only to register the "CoAP for Thread Management Framework"
49 * dissector, which uses the same protocol and field IDs as the
50 * regular CoAP dissector, as it's just "CoAP except that we interpret
51 * application/octet-stream as meaning Thread Management Framework
52 * messages", because the Thread protocol, for whatever reasons (trying
53 * to keep the CoAP layer of their messages as short and simple to parse
54 * as possible, to save power and reduce the chances of low-power
55 * transmissions being misreceived?), did not register a media type for
56 * its messages and a 'cf' value for that media type.
58 static int proto_coap_for_tmf
;
60 static int hf_coap_length
;
61 static int hf_coap_version
;
62 static int hf_coap_ttype
;
63 static int hf_coap_token_len
;
64 static int hf_coap_token
;
65 static int hf_coap_mid
;
67 static int hf_coap_response_in
;
68 static int hf_coap_response_to
;
69 static int hf_coap_response_time
;
70 static int hf_coap_request_resend_in
;
71 static int hf_coap_response_resend_in
;
72 static int hf_coap_oscore_kid
;
73 static int hf_coap_oscore_kid_context
;
74 static int hf_coap_oscore_piv
;
76 static int hf_block_payload
;
77 static int hf_block_length
;
81 static int hf_block_overlap
;
82 static int hf_block_overlap_conflicts
;
83 static int hf_block_multiple_tails
;
84 static int hf_block_too_long
;
85 static int hf_block_error
;
86 static int hf_block_count
;
87 static int hf_block_reassembled_in
;
88 static int hf_block_reassembled_length
;
93 static int ett_blocks
;
95 static expert_field ei_retransmitted
;
97 static COAP_COMMON_LIST_T(dissect_coap_hf
);
99 static dissector_handle_t coap_tcp_tls_handle
;
100 static dissector_handle_t coap_other_handle
;
101 static dissector_handle_t coap_for_tmf_handle
;
102 static dissector_handle_t oscore_handle
;
104 /* CoAP's IANA-assigned TCP/UDP port numbers */
105 #define DEFAULT_COAP_PORT 5683
106 #define DEFAULT_COAPS_PORT 5684
108 /* indicators whether those are to be showed or not */
109 #define DEFAULT_COAP_CTYPE_VALUE ~0U
110 #define DEFAULT_COAP_BLOCK_NUMBER ~0U
112 /* Macros specific to the OCF version options */
113 #define COAP_OCF_VERSION_SUB_MASK 0x3F
114 #define COAP_OCF_VERSION_MINOR_MASK 0x7C0
115 #define COAP_OCF_VERSION_MAJOR_MASK 0xF800
117 #define COAP_OCF_VERSION_MINOR_OFFSET 6
118 #define COAP_OCF_VERSION_MAJOR_OFFSET 11
123 #define TT_CON 0 // Confirmable
124 #define TT_NON 1 // Non-Confirmable
125 static const value_string vals_ttype
[] = {
126 { 0, "Confirmable" },
127 { 1, "Non-Confirmable" },
128 { 2, "Acknowledgement" },
132 static const value_string vals_ttype_short
[] = {
143 * "c.dd" denotes (c << 5) | dd
145 static const value_string vals_code
[] = {
146 { 0, "Empty Message" },
153 { 5, "FETCH" }, /* RFC 8132 */
154 { 6, "PATCH" }, /* RFC 8132 */
155 { 7, "iPATCH" }, /* RFC 8132 */
158 { 65, "2.01 Created" },
159 { 66, "2.02 Deleted" },
160 { 67, "2.03 Valid" },
161 { 68, "2.04 Changed" },
162 { 69, "2.05 Content" },
163 { 95, "2.31 Continue" },
164 { 128, "4.00 Bad Request" },
165 { 129, "4.01 Unauthorized" },
166 { 130, "4.02 Bad Option" },
167 { 131, "4.03 Forbidden" },
168 { 132, "4.04 Not Found" },
169 { 133, "4.05 Method Not Allowed" },
170 { 134, "4.06 Not Acceptable" },
171 { 136, "4.08 Request Entity Incomplete" }, /* RFC 7959 */
172 { 137, "4.09 Conflict" }, /* RFC 8132 */
173 { 140, "4.12 Precondition Failed" },
174 { 141, "4.13 Request Entity Too Large" },
175 { 143, "4.15 Unsupported Content-Format" },
176 { 150, "4.22 Unprocessable Entity" }, /* RFC 8132 */
177 { 157, "4.29 Too Many Requests" }, /* RFC 8516 */
178 { 160, "5.00 Internal Server Error" },
179 { 161, "5.01 Not Implemented" },
180 { 162, "5.02 Bad Gateway" },
181 { 163, "5.03 Service Unavailable" },
182 { 164, "5.04 Gateway Timeout" },
183 { 165, "5.05 Proxying Not Supported" },
184 { 168, "5.08 Hop Limit Reached" }, /* RFC 8768 */
186 /* Signalling Codes */
187 { 225, "7.01 CSM" }, /* RFC 8323 */
188 { 226, "7.02 Ping" }, /* RFC 8323 */
189 { 227, "7.03 Pong" }, /* RFC 8323 */
190 { 228, "7.04 Release" }, /* RFC 8323 */
191 { 229, "7.05 Abort" }, /* RFC 8323 */
195 value_string_ext coap_vals_code_ext
= VALUE_STRING_EXT_INIT(vals_code
);
197 const value_string coap_vals_observe_options
[] = {
205 * No-Option must not be included in this structure, is handled in the function
206 * of the dissector, especially.
208 #define COAP_OPT_IF_MATCH 1
209 #define COAP_OPT_URI_HOST 3
210 #define COAP_OPT_ETAG 4
211 #define COAP_OPT_IF_NONE_MATCH 5
212 #define COAP_OPT_OBSERVE 6 /* RFC 7641 / RFC 8613 */
213 #define COAP_OPT_URI_PORT 7
214 #define COAP_OPT_LOCATION_PATH 8
215 #define COAP_OPT_OBJECT_SECURITY 9 /* RFC 8613 */
216 #define COAP_OPT_URI_PATH 11
217 #define COAP_OPT_CONTENT_TYPE 12
218 #define COAP_OPT_MAX_AGE 14
219 #define COAP_OPT_URI_QUERY 15
220 #define COAP_OPT_HOP_LIMIT 16 /* RFC 8768 */
221 #define COAP_OPT_ACCEPT 17
222 #define COAP_OPT_QBLOCK1 19 /* RFC 9177 */
223 #define COAP_OPT_LOCATION_QUERY 20
224 #define COAP_OPT_EDHOC 21 /* draft-ietf-core-oscore-edhoc*/
225 #define COAP_OPT_BLOCK2 23 /* RFC 7959 / RFC 8323 */
226 #define COAP_OPT_BLOCK1 27 /* RFC 7959 / RFC 8323 */
227 #define COAP_OPT_SIZE2 28 /* RFC 7959 */
228 #define COAP_OPT_QBLOCK2 31 /* RFC 9177 */
229 #define COAP_OPT_PROXY_URI 35
230 #define COAP_OPT_PROXY_SCHEME 39
231 #define COAP_OPT_SIZE1 60
232 #define COAP_OPT_ECHO 252 /* RFC 9175*/
233 #define COAP_OPT_NO_RESPONSE 258 /* RFC 7967 / RFC 8613 */
234 #define COAP_OPT_REQUEST_TAG 292 /* RFC 9175 */
235 #define COAP_OPT_OCF_ACCEPT 2049 /* OCF Core specification */
236 #define COAP_OPT_OCF_CONTENT 2053 /* OCF Core specification */
238 static const value_string vals_opt_type
[] = {
239 { COAP_OPT_IF_MATCH
, "If-Match" },
240 { COAP_OPT_URI_HOST
, "Uri-Host" },
241 { COAP_OPT_ETAG
, "Etag" },
242 { COAP_OPT_IF_NONE_MATCH
, "If-None-Match" },
243 { COAP_OPT_URI_PORT
, "Uri-Port" },
244 { COAP_OPT_LOCATION_PATH
, "Location-Path" },
245 { COAP_OPT_OBJECT_SECURITY
,"OSCORE" },
246 { COAP_OPT_URI_PATH
, "Uri-Path" },
247 { COAP_OPT_CONTENT_TYPE
, "Content-Format" },
248 { COAP_OPT_MAX_AGE
, "Max-age" },
249 { COAP_OPT_URI_QUERY
, "Uri-Query" },
250 { COAP_OPT_HOP_LIMIT
, "Hop-Limit" },
251 { COAP_OPT_ACCEPT
, "Accept" },
252 { COAP_OPT_QBLOCK1
, "Q-Block1" },
253 { COAP_OPT_LOCATION_QUERY
, "Location-Query" },
254 { COAP_OPT_EDHOC
, "EDHOC" },
255 { COAP_OPT_PROXY_URI
, "Proxy-Uri" },
256 { COAP_OPT_PROXY_SCHEME
, "Proxy-Scheme" },
257 { COAP_OPT_SIZE1
, "Size1" },
258 { COAP_OPT_OBSERVE
, "Observe" },
259 { COAP_OPT_BLOCK2
, "Block2" },
260 { COAP_OPT_BLOCK1
, "Block1" },
261 { COAP_OPT_SIZE2
, "Size2" },
262 { COAP_OPT_QBLOCK2
, "Q-Block2" },
263 { COAP_OPT_ECHO
, "Echo" },
264 { COAP_OPT_NO_RESPONSE
, "No-Response" },
265 { COAP_OPT_REQUEST_TAG
, "Request-Tag" },
266 { COAP_OPT_OCF_ACCEPT
, "OCF-Accept-Content-Format-Version" },
267 { COAP_OPT_OCF_CONTENT
, "OCF-Content-Format-Version" },
271 struct coap_option_range_t
{
276 { COAP_OPT_IF_MATCH
, 0, 8 },
277 { COAP_OPT_URI_HOST
, 1, 255 },
278 { COAP_OPT_ETAG
, 1, 8 },
279 { COAP_OPT_IF_NONE_MATCH
, 0, 0 },
280 { COAP_OPT_URI_PORT
, 0, 2 },
281 { COAP_OPT_LOCATION_PATH
, 0, 255 },
282 { COAP_OPT_OBJECT_SECURITY
, 0, 255 },
283 { COAP_OPT_URI_PATH
, 0, 255 },
284 { COAP_OPT_CONTENT_TYPE
, 0, 2 },
285 { COAP_OPT_MAX_AGE
, 0, 4 },
286 { COAP_OPT_URI_QUERY
, 1, 255 },
287 { COAP_OPT_HOP_LIMIT
, 1, 1 },
288 { COAP_OPT_ACCEPT
, 0, 2 },
289 { COAP_OPT_QBLOCK1
, 0, 3 },
290 { COAP_OPT_LOCATION_QUERY
, 0, 255 },
291 { COAP_OPT_EDHOC
, 0, 0 },
292 { COAP_OPT_PROXY_URI
, 1,1034 },
293 { COAP_OPT_PROXY_SCHEME
, 1, 255 },
294 { COAP_OPT_SIZE1
, 0, 4 },
295 { COAP_OPT_OBSERVE
, 0, 3 },
296 { COAP_OPT_BLOCK2
, 0, 3 },
297 { COAP_OPT_BLOCK1
, 0, 3 },
298 { COAP_OPT_SIZE2
, 0, 4 },
299 { COAP_OPT_QBLOCK2
, 0, 3 },
300 { COAP_OPT_ECHO
, 1, 40 },
301 { COAP_OPT_NO_RESPONSE
, 0, 1 },
302 { COAP_OPT_REQUEST_TAG
, 0, 8 },
303 { COAP_OPT_OCF_ACCEPT
, 2, 2 },
304 { COAP_OPT_OCF_CONTENT
, 2, 2 },
307 static const value_string vals_ctype
[] = {
308 { 0, "text/plain; charset=utf-8" },
309 { 16, "application/cose; cose-type=\"cose-encrypt0\"" },
310 { 17, "application/cose; cose-type=\"cose-mac0\"" },
311 { 18, "application/cose; cose-type=\"cose-sign1\"" },
312 { 19, "application/ace+cbor" },
314 { 22, "image/jpeg" },
316 { 40, "application/link-format" },
317 { 41, "application/xml" },
318 { 42, "application/octet-stream" },
319 { 47, "application/exi" },
320 { 50, "application/json" },
321 { 51, "application/json-patch+json" },
322 { 52, "application/merge-patch+json" },
323 { 60, "application/cbor" },
324 { 61, "application/cwt" },
325 { 62, "application/multipart-core" },
326 { 63, "application/cbor-seq" },
327 { 96, "application/cose; cose-type=\"cose-encrypt\"" },
328 { 97, "application/cose; cose-type=\"cose-mac\"" },
329 { 98, "application/cose; cose-type=\"cose-sign\"" },
330 { 101, "application/cose-key" },
331 { 102, "application/cose-key-set" },
332 { 110, "application/senml+json" },
333 { 111, "application/sensml+json" },
334 { 112, "application/senml+cbor" },
335 { 113, "application/sensml+cbor" },
336 { 114, "application/senml-exi" },
337 { 115, "application/sensml-exi" },
338 { 140, "application/yang-data+cbor; id=sid" },
339 { 256, "application/coap-group+json" },
340 { 257, "application/concise-problem-details+cbor" },
341 { 258, "application/swid+cbor" },
342 { 271, "application/dots+cbor" },
343 { 272, "application/missing-blocks+cbor-seq" },
344 { 280, "application/pkcs7-mime; smime-type=server-generated-key" },
345 { 281, "application/pkcs7-mime; smime-type=certs-only" },
346 { 284, "application/pkcs8" },
347 { 285, "application/csrattrs" },
348 { 286, "application/pkcs10" },
349 { 287, "application/pkix-cert" },
350 { 290, "application/aif+cbor" },
351 { 291, "application/aif+json" },
352 { 310, "application/senml+xml" },
353 { 311, "application/sensml+xml" },
354 { 320, "application/senml-etch+json" },
355 { 322, "application/senml-etch+cbor" },
356 { 340, "application/yang-data+cbor" },
357 { 341, "application/yang-data+cbor; id=name" },
358 { 432, "application/td+json" },
359 { 433, "application/tm+json" },
360 { 1542, "application/vnd.oma.lwm2m+tlv" },
361 { 1543, "application/vnd.oma.lwm2m+json" },
362 { 10000, "application/vnd.ocf+cbor" },
363 { 10001, "application/oscore" },
364 { 10002, "application/javascript" },
365 { 11050, "application/json (Content Coding: deflate)" },
366 { 11060, "application/cbor (Content Coding: deflate)" },
367 { 11542, "application/vnd.oma.lwm2m+tlv" },
368 { 11543, "application/vnd.oma.lwm2m+json" },
369 { 20000, "text/css" },
370 { 30000, "image/svg+xml" },
374 static const char *nullstr
= "(null)";
376 static reassembly_table coap_block_reassembly_table
;
378 static const fragment_items coap_block_frag_items
= {
379 /* Fragment subtrees */
382 /* Fragment fields */
386 &hf_block_overlap_conflicts
,
387 &hf_block_multiple_tails
,
391 /* Reassembled in field */
392 &hf_block_reassembled_in
,
393 /* Reassembled length field */
394 &hf_block_reassembled_length
,
395 /* Reassembled data field */
401 void proto_reg_handoff_coap(void);
403 static conversation_t
*
404 find_or_create_conversation_noaddrb(packet_info
*pinfo
, bool request
)
406 conversation_t
*conv
=NULL
;
412 if (pinfo
->ptype
!= PT_TCP
) {
414 addr_a
= &pinfo
->src
;
415 addr_b
= &pinfo
->dst
;
416 port_a
= pinfo
->srcport
;
417 port_b
= pinfo
->destport
;
419 addr_a
= &pinfo
->dst
;
420 addr_b
= &pinfo
->src
;
421 port_a
= pinfo
->destport
;
422 port_b
= pinfo
->srcport
;
424 /* Have we seen this conversation before? */
425 if((conv
= find_conversation(pinfo
->num
, addr_a
, addr_b
,
426 conversation_pt_to_conversation_type(pinfo
->ptype
), port_a
,
427 port_b
, NO_ADDR_B
|NO_PORT_B
)) != NULL
) {
428 if (pinfo
->num
> conv
->last_frame
) {
429 conv
->last_frame
= pinfo
->num
;
432 /* No, this is a new conversation. */
433 conv
= conversation_new(pinfo
->num
, &pinfo
->src
,
434 &pinfo
->dst
, conversation_pt_to_conversation_type(pinfo
->ptype
),
435 pinfo
->srcport
, pinfo
->destport
, NO_ADDR2
|NO_PORT2
);
438 /* fetch the conversation created by the TCP dissector */
439 conv
= find_conversation_pinfo(pinfo
, 0);
440 DISSECTOR_ASSERT(conv
);
446 coap_get_opt_uint(tvbuff_t
*tvb
, int offset
, int length
)
452 return (unsigned)tvb_get_uint8(tvb
, offset
);
454 return (unsigned)tvb_get_ntohs(tvb
, offset
);
456 return (unsigned)tvb_get_ntoh24(tvb
, offset
);
458 return (unsigned)tvb_get_ntohl(tvb
, offset
);
465 coap_opt_check(packet_info
*pinfo
, proto_tree
*subtree
, unsigned opt_num
, int opt_length
, coap_common_dissect_t
*dissect_hf
)
469 for (i
= 0; i
< (int)(array_length(coi
)); i
++) {
470 if (coi
[i
].type
== opt_num
)
473 if (i
== (int)(array_length(coi
))) {
474 if (opt_num
>= 2048 && opt_num
<= 65535) {
475 /* private, vendor-specific or reserved for experiments */
476 expert_add_info_format(pinfo
, subtree
, &dissect_hf
->ei
.opt_unknown_number
,
477 "Unknown Option Number %u", opt_num
);
479 expert_add_info_format(pinfo
, subtree
, &dissect_hf
->ei
.opt_invalid_number
,
480 "Invalid Option Number %u", opt_num
);
484 if (opt_length
< coi
[i
].min
|| opt_length
> coi
[i
].max
) {
485 expert_add_info_format(pinfo
, subtree
, &dissect_hf
->ei
.opt_invalid_range
,
486 "Invalid Option Range: %d (%d < x < %d)", opt_length
, coi
[i
].min
, coi
[i
].max
);
493 dissect_coap_opt_hex_string(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
500 str
= tvb_bytes_to_str_punct(pinfo
->pool
, tvb
, offset
, opt_length
, ' ');
502 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_NA
);
504 /* add info to the head of the packet detail */
505 proto_item_append_text(item
, ": %s", str
);
509 dissect_coap_opt_uint(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
513 if (opt_length
!= 0) {
514 i
= coap_get_opt_uint(tvb
, offset
, opt_length
);
517 proto_tree_add_uint(subtree
, hf
, tvb
, offset
, opt_length
, i
);
519 /* add info to the head of the packet detail */
520 proto_item_append_text(head_item
, ": %u", i
);
524 dissect_coap_opt_uri_host(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, coap_info
*coinfo
, int hf
)
528 proto_tree_add_item_ret_string(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
, pinfo
->pool
, &str
);
530 /* add info to the head of the packet detail */
531 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
533 /* forming a uri-string
534 * If the 'uri host' looks an IPv6 address, assuming that the address has
535 * to be enclosed by brackets.
537 if (strchr(str
, ':') == NULL
) {
538 wmem_strbuf_append_printf(coinfo
->uri_str_strbuf
, "coap://%s", str
);
540 wmem_strbuf_append_printf(coinfo
->uri_str_strbuf
, "coap://[%s]", str
);
545 dissect_coap_opt_uri_path(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, coap_info
*coinfo
, int hf
)
547 const uint8_t *str
= NULL
;
549 wmem_strbuf_append_c(coinfo
->uri_str_strbuf
, '/');
551 if (opt_length
== 0) {
554 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
555 wmem_strbuf_append(coinfo
->uri_str_strbuf
, str
);
558 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
560 /* add info to the head of the packet detail */
561 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
565 dissect_coap_opt_uri_query(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, coap_info
*coinfo
, int hf
)
567 const uint8_t *str
= NULL
;
569 wmem_strbuf_append_c(coinfo
->uri_query_strbuf
,
570 (wmem_strbuf_get_len(coinfo
->uri_query_strbuf
) == 0) ? '?' : '&');
572 if (opt_length
== 0) {
575 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
576 wmem_strbuf_append(coinfo
->uri_query_strbuf
, str
);
579 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
581 /* add info to the head of the packet detail */
582 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
586 dissect_coap_opt_location_path(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
588 const uint8_t *str
= NULL
;
590 if (opt_length
== 0) {
593 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
596 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
598 /* add info to the head of the packet detail */
599 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
603 dissect_coap_opt_location_query(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
605 const uint8_t *str
= NULL
;
607 if (opt_length
== 0) {
610 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
613 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
615 /* add info to the head of the packet detail */
616 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
621 dissect_coap_opt_object_security(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, packet_info
*pinfo
, coap_info
*coinfo
, coap_common_dissect_t
*dissect_hf
, uint8_t code_class
)
623 uint8_t flag_byte
= 0;
624 bool reserved
= false;
625 bool kid_context_present
= false;
626 bool kid_present
= false;
628 uint8_t kid_context_len
= 0;
631 coinfo
->object_security
= true;
633 coinfo
->oscore_info
->piv
= NULL
;
634 coinfo
->oscore_info
->piv_len
= 0;
635 coinfo
->oscore_info
->request_piv
= NULL
;
636 coinfo
->oscore_info
->request_piv_len
= 0;
637 coinfo
->oscore_info
->kid_context
= NULL
;
638 coinfo
->oscore_info
->kid_context_len
= 0;
639 coinfo
->oscore_info
->kid
= NULL
;
640 coinfo
->oscore_info
->kid_len
= 0;
641 coinfo
->oscore_info
->response
= false;
643 if (opt_length
== 0) { /* option length is zero, means flag byte is 0x00*/
644 /* add info to the head of the packet detail */
645 proto_item_append_text(head_item
, ": 00 (no Flag Byte)");
647 flag_byte
= tvb_get_uint8(tvb
, offset
);
649 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_reserved
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
650 reserved
= flag_byte
& COAP_OBJECT_SECURITY_RESERVED_MASK
;
652 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_kid_context_present
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
653 kid_context_present
= flag_byte
& COAP_OBJECT_SECURITY_KID_CONTEXT_MASK
;
655 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_kid_present
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
656 kid_present
= flag_byte
& COAP_OBJECT_SECURITY_KID_MASK
;
658 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_piv_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
659 piv_len
= (flag_byte
& COAP_OBJECT_SECURITY_PIVLEN_MASK
) >> 0;
661 /* kid_len is what remains in the option after all other fields are parsed
662 we calculate kid_len by subtracting from option length as we parse individual fields */
663 kid_len
= opt_length
;
669 /* how these bits are handled is not yet specified */
670 expert_add_info_format(pinfo
, subtree
, &dissect_hf
->ei
.opt_object_security_bad
, "Unsupported format");
674 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_piv
, tvb
, offset
, piv_len
, ENC_NA
);
675 coinfo
->oscore_info
->piv
= (uint8_t *) tvb_memdup(pinfo
->pool
, tvb
, offset
, piv_len
);
676 coinfo
->oscore_info
->piv_len
= piv_len
;
678 if (code_class
== 0) {
679 /* If this is a request, copy PIV to request_piv */
680 coinfo
->oscore_info
->request_piv
= (uint8_t *) tvb_memdup(pinfo
->pool
, tvb
, offset
, piv_len
);
681 coinfo
->oscore_info
->request_piv_len
= piv_len
;
688 if (kid_context_present
) {
689 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_kid_context_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
690 kid_context_len
= tvb_get_uint8(tvb
, offset
);
695 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_kid_context
, tvb
, offset
, kid_context_len
, ENC_NA
);
696 coinfo
->oscore_info
->kid_context
= (uint8_t *) tvb_memdup(pinfo
->pool
, tvb
, offset
, kid_context_len
);
697 coinfo
->oscore_info
->kid_context_len
= kid_context_len
;
699 offset
+= kid_context_len
;
700 kid_len
-= kid_context_len
;
704 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_object_security_kid
, tvb
, offset
, kid_len
, ENC_NA
);
705 coinfo
->oscore_info
->kid
= (uint8_t *) tvb_memdup(pinfo
->pool
, tvb
, offset
, kid_len
);
706 coinfo
->oscore_info
->kid_len
= kid_len
;
710 proto_item_append_text(head_item
, ": Key ID:%s, Key ID Context:%s, Partial IV:%s",
711 coinfo
->oscore_info
->kid
== NULL
? nullstr
: bytes_to_str(pinfo
->pool
, coinfo
->oscore_info
->kid
, coinfo
->oscore_info
->kid_len
),
712 coinfo
->oscore_info
->kid_context
== NULL
? nullstr
: bytes_to_str(pinfo
->pool
, coinfo
->oscore_info
->kid_context
, coinfo
->oscore_info
->kid_context_len
),
713 coinfo
->oscore_info
->piv
== NULL
? nullstr
: bytes_to_str(pinfo
->pool
, coinfo
->oscore_info
->piv
, coinfo
->oscore_info
->piv_len
));
718 dissect_coap_opt_proxy_uri(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
720 const uint8_t *str
= NULL
;
722 if (opt_length
== 0) {
725 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
728 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
730 /* add info to the head of the packet detail */
731 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
735 dissect_coap_opt_proxy_scheme(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
737 const uint8_t *str
= NULL
;
739 if (opt_length
== 0) {
742 str
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, opt_length
, ENC_ASCII
);
745 proto_tree_add_item(subtree
, hf
, tvb
, offset
, opt_length
, ENC_ASCII
);
747 /* add info to the head of the packet detail */
748 proto_item_append_text(head_item
, ": %s", format_text_string(pinfo
->pool
, str
));
752 dissect_coap_opt_ctype(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
, coap_info
*coinfo
)
754 if (opt_length
== 0) {
755 coinfo
->ctype_value
= 0;
757 coinfo
->ctype_value
= coap_get_opt_uint(tvb
, offset
, opt_length
);
760 coinfo
->ctype_str
= val_to_str(coinfo
->ctype_value
, vals_ctype
, "Unknown Type %u");
762 proto_tree_add_string(subtree
, hf
, tvb
, offset
, opt_length
, coinfo
->ctype_str
);
764 /* add info to the head of the packet detail */
765 proto_item_append_text(head_item
, ": %s", coinfo
->ctype_str
);
769 dissect_coap_opt_accept(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hf
)
771 const uint8_t *str
= NULL
;
773 if (opt_length
== 0) {
776 unsigned value
= coap_get_opt_uint(tvb
, offset
, opt_length
);
777 str
= val_to_str(value
, vals_ctype
, "Unknown Type %u");
780 proto_tree_add_string(subtree
, hf
, tvb
, offset
, opt_length
, str
);
782 /* add info to the head of the packet detail */
783 proto_item_append_text(head_item
, ": %s", str
);
787 dissect_coap_opt_block(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, coap_info
*coinfo
, coap_common_dissect_t
*dissect_hf
)
790 unsigned encoded_block_size
;
791 unsigned block_esize
;
793 if (opt_length
== 0) {
794 coinfo
->block_number
= 0;
797 coinfo
->block_number
= coap_get_opt_uint(tvb
, offset
, opt_length
) >> 4;
798 val
= tvb_get_uint8(tvb
, offset
+ opt_length
- 1) & 0x0f;
801 proto_tree_add_uint(subtree
, dissect_hf
->hf
.opt_block_number
,
802 tvb
, offset
, opt_length
, coinfo
->block_number
);
804 /* More flag in the end of the option */
805 coinfo
->block_mflag
= (val
& COAP_BLOCK_MFLAG_MASK
) >> 3;
806 proto_tree_add_uint(subtree
, dissect_hf
->hf
.opt_block_mflag
,
807 tvb
, offset
+ opt_length
- 1, 1, val
);
810 encoded_block_size
= val
& COAP_BLOCK_SIZE_MASK
;
811 block_esize
= 1 << (encoded_block_size
+ 4);
812 proto_tree_add_uint_format(subtree
, dissect_hf
->hf
.opt_block_size
,
813 tvb
, offset
+ opt_length
- 1, 1, encoded_block_size
, "Block Size: %u (%u encoded)", block_esize
, encoded_block_size
);
815 /* add info to the head of the packet detail */
816 proto_item_append_text(head_item
, ": NUM:%u, M:%u, SZ:%u",
817 coinfo
->block_number
, coinfo
->block_mflag
, block_esize
);
821 dissect_coap_opt_ocf_version(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, int hfindex
)
823 unsigned option_value
= coap_get_opt_uint(tvb
, offset
, opt_length
);
825 unsigned sub_version
= option_value
& COAP_OCF_VERSION_SUB_MASK
;
826 unsigned minor_version
= (option_value
& COAP_OCF_VERSION_MINOR_MASK
) >> COAP_OCF_VERSION_MINOR_OFFSET
;
827 unsigned major_version
= (option_value
& COAP_OCF_VERSION_MAJOR_MASK
) >> COAP_OCF_VERSION_MAJOR_OFFSET
;
829 proto_tree_add_uint(subtree
, hfindex
, tvb
, offset
, opt_length
, option_value
);
831 /* add info to the head of the packet detail */
832 proto_item_append_text(head_item
, ": %u.%u.%u",
833 major_version
, minor_version
, sub_version
);
837 dissect_coap_opt_uri_port(tvbuff_t
*tvb
, proto_item
*head_item
, proto_tree
*subtree
, int offset
, int opt_length
, coap_info
*coinfo
, int hf
)
841 if (opt_length
!= 0) {
842 port
= coap_get_opt_uint(tvb
, offset
, opt_length
);
845 proto_tree_add_uint(subtree
, hf
, tvb
, offset
, opt_length
, port
);
847 proto_item_append_text(head_item
, ": %u", port
);
849 /* forming a uri-string */
850 wmem_strbuf_append_printf(coinfo
->uri_str_strbuf
, ":%u", port
);
854 * dissector for each option of CoAP.
855 * return the total length of the option including the header (e.g. delta and length).
858 dissect_coap_options_main(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*coap_tree
, int offset
, uint8_t opt_count
, unsigned *opt_num
, int offset_end
, uint8_t code_class
, coap_info
*coinfo
, coap_common_dissect_t
*dissect_hf
)
861 int opt_length
, opt_length_ext
, opt_delta
, opt_delta_ext
;
862 int opt_length_ext_off
= 0;
863 int8_t opt_length_ext_len
= 0;
864 int opt_delta_ext_off
= 0;
865 int8_t opt_delta_ext_len
= 0;
866 int orig_offset
= offset
;
871 opt_jump
= tvb_get_uint8(tvb
, offset
);
872 if (0xff == opt_jump
)
877 * section 3.1 in coap-17:
878 * Option Delta: 4-bit unsigned integer. A value between 0 and 12
879 * indicates the Option Delta. Three values are reserved for special
882 * 13: An 8-bit unsigned integer follows the initial byte and
883 * indicates the Option Delta minus 13.
885 * 14: A 16-bit unsigned integer in network byte order follows the
886 * initial byte and indicates the Option Delta minus 269.
888 * 15: Reserved for the Payload Marker. If the field is set to this
889 * value but the entire byte is not the payload marker, this MUST
890 * be processed as a message format error.
892 switch (opt_jump
& 0xf0) {
894 opt_delta_ext
= tvb_get_uint8(tvb
, offset
);
895 opt_delta_ext_off
= offset
;
896 opt_delta_ext_len
= 1;
900 opt_delta
+= opt_delta_ext
;
903 opt_delta_ext
= coap_get_opt_uint(tvb
, offset
, 2);
904 opt_delta_ext_off
= offset
;
905 opt_delta_ext_len
= 2;
909 opt_delta
+= opt_delta_ext
;
912 expert_add_info_format(pinfo
, coap_tree
, &dissect_hf
->ei
.opt_length_bad
,
913 "end-of-options marker found, but option length isn't 15");
916 opt_delta
= ((opt_jump
& 0xf0) >> 4);
919 *opt_num
+= opt_delta
;
922 * section 3.1 in coap-17:
923 * Option Length: 4-bit unsigned integer. A value between 0 and 12
924 * indicates the length of the Option Value, in bytes. Three values
925 * are reserved for special constructs:
927 * 13: An 8-bit unsigned integer precedes the Option Value and
928 * indicates the Option Length minus 13.
930 * 14: A 16-bit unsigned integer in network byte order precedes the
931 * Option Value and indicates the Option Length minus 269.
933 * 15: Reserved for future use. If the field is set to this value,
934 * it MUST be processed as a message format error.
936 switch (opt_jump
& 0x0f) {
938 opt_length_ext
= tvb_get_uint8(tvb
, offset
);
939 opt_length_ext_off
= offset
;
940 opt_length_ext_len
= 1;
944 opt_length
+= opt_length_ext
;
947 opt_length_ext
= coap_get_opt_uint(tvb
, offset
, 2);
948 opt_length_ext_off
= offset
;
949 opt_length_ext_len
= 2;
953 opt_length
+= opt_length_ext
;
956 expert_add_info_format(pinfo
, coap_tree
, &dissect_hf
->ei
.opt_length_bad
,
957 "end-of-options marker found, but option delta isn't 15");
960 opt_length
= (opt_jump
& 0x0f);
963 if (opt_length
> offset_end
- offset
) {
964 expert_add_info_format(pinfo
, coap_tree
, &dissect_hf
->ei
.opt_length_bad
,
965 "option longer than the package");
969 snprintf(strbuf
, sizeof(strbuf
),
970 "#%u: %s", opt_count
, val_to_str(*opt_num
, vals_opt_type
,
971 *opt_num
% 14 == 0 ? "No-Op" : "Unknown Option (%d)"));
972 item
= proto_tree_add_string(coap_tree
, dissect_hf
->hf
.opt_name
,
973 tvb
, orig_offset
, offset
- orig_offset
+ opt_length
, strbuf
);
974 subtree
= proto_item_add_subtree(item
, dissect_hf
->ett
.option
);
976 coap_opt_check(pinfo
, subtree
, *opt_num
, opt_length
, dissect_hf
);
978 snprintf(strbuf
, sizeof(strbuf
),
979 "Type %u, %s, %s%s", *opt_num
,
980 (*opt_num
& 1) ? "Critical" : "Elective",
981 (*opt_num
& 2) ? "Unsafe" : "Safe",
982 ((*opt_num
& 0x1e) == 0x1c) ? ", NoCacheKey" : "");
983 proto_tree_add_string(subtree
, dissect_hf
->hf
.opt_desc
,
984 tvb
, orig_offset
, offset
- orig_offset
+ opt_length
, strbuf
);
986 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_delta
, tvb
, orig_offset
, 1, ENC_BIG_ENDIAN
);
987 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_length
, tvb
, orig_offset
, 1, ENC_BIG_ENDIAN
);
989 if (opt_delta_ext_off
&& opt_delta_ext_len
)
990 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_delta_ext
, tvb
, opt_delta_ext_off
, opt_delta_ext_len
, ENC_BIG_ENDIAN
);
992 if (opt_length_ext_off
&& opt_length_ext_len
)
993 proto_tree_add_item(subtree
, dissect_hf
->hf
.opt_length_ext
, tvb
, opt_length_ext_off
, opt_length_ext_len
, ENC_BIG_ENDIAN
);
995 /* offset points the next to its option header */
997 case COAP_OPT_CONTENT_TYPE
:
998 dissect_coap_opt_ctype(tvb
, item
, subtree
, offset
,
999 opt_length
, dissect_hf
->hf
.opt_ctype
, coinfo
);
1001 case COAP_OPT_MAX_AGE
:
1002 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1003 opt_length
, dissect_hf
->hf
.opt_max_age
);
1005 case COAP_OPT_PROXY_URI
:
1006 dissect_coap_opt_proxy_uri(tvb
, pinfo
, item
, subtree
, offset
,
1007 opt_length
, dissect_hf
->hf
.opt_proxy_uri
);
1009 case COAP_OPT_PROXY_SCHEME
:
1010 dissect_coap_opt_proxy_scheme(tvb
, pinfo
, item
, subtree
, offset
,
1011 opt_length
, dissect_hf
->hf
.opt_proxy_scheme
);
1013 case COAP_OPT_SIZE1
:
1014 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1015 opt_length
, dissect_hf
->hf
.opt_size1
);
1018 dissect_coap_opt_hex_string(tvb
, pinfo
, item
, subtree
, offset
,
1019 opt_length
, dissect_hf
->hf
.opt_etag
);
1021 case COAP_OPT_URI_HOST
:
1022 dissect_coap_opt_uri_host(tvb
, pinfo
, item
, subtree
, offset
,
1023 opt_length
, coinfo
, dissect_hf
->hf
.opt_uri_host
);
1025 case COAP_OPT_LOCATION_PATH
:
1026 dissect_coap_opt_location_path(tvb
, pinfo
, item
, subtree
, offset
,
1027 opt_length
, dissect_hf
->hf
.opt_location_path
);
1029 case COAP_OPT_URI_PORT
:
1030 dissect_coap_opt_uri_port(tvb
, item
, subtree
, offset
,
1031 opt_length
, coinfo
, dissect_hf
->hf
.opt_uri_port
);
1033 case COAP_OPT_LOCATION_QUERY
:
1034 dissect_coap_opt_location_query(tvb
, pinfo
, item
, subtree
, offset
,
1035 opt_length
, dissect_hf
->hf
.opt_location_query
);
1037 case COAP_OPT_OBJECT_SECURITY
:
1038 dissect_coap_opt_object_security(tvb
, item
, subtree
, offset
,
1039 opt_length
, pinfo
, coinfo
, dissect_hf
, code_class
);
1041 case COAP_OPT_URI_PATH
:
1042 dissect_coap_opt_uri_path(tvb
, pinfo
, item
, subtree
, offset
,
1043 opt_length
, coinfo
, dissect_hf
->hf
.opt_uri_path
);
1045 case COAP_OPT_OBSERVE
:
1046 if (code_class
== 0) {
1048 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1049 opt_length
, dissect_hf
->hf
.opt_observe_req
);
1052 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1053 opt_length
, dissect_hf
->hf
.opt_observe_rsp
);
1056 case COAP_OPT_HOP_LIMIT
:
1057 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1058 opt_length
, dissect_hf
->hf
.opt_hop_limit
);
1060 case COAP_OPT_ACCEPT
:
1061 dissect_coap_opt_accept(tvb
, item
, subtree
, offset
,
1062 opt_length
, dissect_hf
->hf
.opt_accept
);
1064 case COAP_OPT_IF_MATCH
:
1065 dissect_coap_opt_hex_string(tvb
, pinfo
, item
, subtree
, offset
,
1066 opt_length
, dissect_hf
->hf
.opt_if_match
);
1068 case COAP_OPT_URI_QUERY
:
1069 dissect_coap_opt_uri_query(tvb
, pinfo
, item
, subtree
, offset
,
1070 opt_length
, coinfo
, dissect_hf
->hf
.opt_uri_query
);
1073 dissect_coap_opt_hex_string(tvb
, pinfo
, item
, subtree
, offset
,
1074 opt_length
, dissect_hf
->hf
.opt_echo
);
1076 case COAP_OPT_REQUEST_TAG
:
1077 dissect_coap_opt_hex_string(tvb
, pinfo
, item
, subtree
, offset
,
1078 opt_length
, dissect_hf
->hf
.opt_request_tag
);
1080 case COAP_OPT_NO_RESPONSE
:
1081 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1082 opt_length
, dissect_hf
->hf
.opt_no_response
);
1084 case COAP_OPT_BLOCK2
:
1085 coinfo
->block_option
= 2;
1086 dissect_coap_opt_block(tvb
, item
, subtree
, offset
,
1087 opt_length
, coinfo
, dissect_hf
);
1089 case COAP_OPT_BLOCK1
:
1090 coinfo
->block_option
= 1;
1091 dissect_coap_opt_block(tvb
, item
, subtree
, offset
,
1092 opt_length
, coinfo
, dissect_hf
);
1094 case COAP_OPT_QBLOCK2
:
1095 coinfo
->block_option
= 2;
1096 dissect_coap_opt_block(tvb
, item
, subtree
, offset
,
1097 opt_length
, coinfo
, dissect_hf
);
1099 case COAP_OPT_QBLOCK1
:
1100 coinfo
->block_option
= 1;
1101 dissect_coap_opt_block(tvb
, item
, subtree
, offset
,
1102 opt_length
, coinfo
, dissect_hf
);
1104 case COAP_OPT_IF_NONE_MATCH
:
1106 case COAP_OPT_EDHOC
:
1108 case COAP_OPT_SIZE2
:
1109 dissect_coap_opt_uint(tvb
, item
, subtree
, offset
,
1110 opt_length
, dissect_hf
->hf
.opt_block_size
);
1112 case COAP_OPT_OCF_CONTENT
:
1113 dissect_coap_opt_ocf_version(tvb
, item
, subtree
, offset
,
1114 opt_length
, dissect_hf
->hf
.opt_ocf_version
);
1116 case COAP_OPT_OCF_ACCEPT
:
1117 dissect_coap_opt_ocf_version(tvb
, item
, subtree
, offset
,
1118 opt_length
, dissect_hf
->hf
.opt_ocf_accept_version
);
1121 dissect_coap_opt_hex_string(tvb
, pinfo
, item
, subtree
, offset
,
1122 opt_length
, dissect_hf
->hf
.opt_unknown
);
1126 return offset
+ opt_length
;
1130 * options dissector.
1131 * return offset pointing the next of options. (i.e. the top of the paylaod
1132 * or the end of the data.
1135 dissect_coap_options(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*coap_tree
, int offset
, int offset_end
, uint8_t code_class
, coap_info
*coinfo
, coap_common_dissect_t
*dissect_hf
)
1137 unsigned opt_num
= 0;
1141 /* loop for dissecting options */
1142 for (i
= 1; offset
< offset_end
; i
++) {
1143 offset
= dissect_coap_options_main(tvb
, pinfo
, coap_tree
,
1144 offset
, i
, &opt_num
, offset_end
, code_class
, coinfo
, dissect_hf
);
1147 if (offset
>= offset_end
)
1149 endmarker
= tvb_get_uint8(tvb
, offset
);
1150 if (endmarker
== 0xff) {
1151 proto_tree_add_item(coap_tree
, dissect_hf
->hf
.opt_end_marker
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1161 * CoAP code dissector.
1162 * return code value and updates the offset
1165 dissect_coap_code(tvbuff_t
*tvb
, proto_tree
*tree
, int *offset
, coap_common_dissect_t
*dissect_hf
, uint8_t *code_class
)
1169 proto_tree_add_item(tree
, dissect_hf
->hf
.code
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
1170 code
= tvb_get_uint8(tvb
, *offset
);
1171 *code_class
= code
>> 5;
1178 dissect_coap_payload(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*coap_tree
, proto_tree
*parent_tree
, int offset
, int offset_end
, uint8_t code_class
, coap_info
*coinfo
, coap_common_dissect_t
*dissect_hf
, bool oscore
)
1180 proto_tree
*payload_tree
;
1181 proto_item
*payload_item
, *length_item
;
1182 tvbuff_t
*payload_tvb
;
1183 unsigned payload_length
= offset_end
- offset
;
1184 const char *coap_ctype_str_dis
;
1185 media_content_info_t content_info
= {0};
1186 char str_payload
[80];
1189 /* coinfo->ctype_value == DEFAULT_COAP_CTYPE_VALUE: No Content-Format option present */
1190 if (coinfo
->ctype_value
== DEFAULT_COAP_CTYPE_VALUE
) {
1192 * 5.5.2. Diagnostic Payload
1194 * If no Content-Format option is given, the payload of responses
1195 * indicating a client or server error is a brief human-readable
1196 * diagnostic message, explaining the error situation. This diagnostic
1197 * message MUST be encoded using UTF-8 [RFC3629], more specifically
1198 * using Net-Unicode form [RFC5198].
1200 if ((code_class
>= 4) && (code_class
<= 5)) {
1201 coinfo
->ctype_str
= "text/plain; charset=utf-8";
1202 coap_ctype_str_dis
= "text/plain";
1204 /* Assume no Content-Format is opaque octet stream */
1205 coinfo
->ctype_str
= "application/octet-stream";
1206 coap_ctype_str_dis
= coinfo
->ctype_str
;
1209 /* coinfo->ctype_value == 0: Content-Format option present with length 0 */
1210 else if (coinfo
->ctype_value
== 0) {
1211 /* coinfo->ctype_str is already set by option parsing routine */
1212 coap_ctype_str_dis
= "text/plain";
1214 coap_ctype_str_dis
= coinfo
->ctype_str
;
1217 snprintf(str_payload
, sizeof(str_payload
),
1218 "Payload Content-Format: %s%s, Length: %u",
1219 coinfo
->ctype_str
, coinfo
->ctype_value
== DEFAULT_COAP_CTYPE_VALUE
?
1220 " (no Content-Format)" : "", payload_length
);
1222 payload_item
= proto_tree_add_string(coap_tree
, dissect_hf
->hf
.payload
,
1223 tvb
, offset
, payload_length
,
1225 payload_tree
= proto_item_add_subtree(payload_item
, dissect_hf
->ett
.payload
);
1227 proto_tree_add_string(payload_tree
, dissect_hf
->hf
.payload_desc
, tvb
, offset
, 0, coinfo
->ctype_str
);
1228 length_item
= proto_tree_add_uint(payload_tree
, dissect_hf
->hf
.payload_length
, tvb
, offset
, 0, payload_length
);
1229 proto_item_set_generated(length_item
);
1230 payload_tvb
= tvb_new_subset_length(tvb
, offset
, payload_length
);
1232 content_info
.type
= MEDIA_CONTAINER_HTTP_OTHERS
;
1233 content_info
.media_str
= wmem_strbuf_get_str(coinfo
->uri_str_strbuf
);
1235 * The Thread protocol uses application/octet-stream for its
1236 * messages, rather than having its own media type for those
1237 * messages, as, for example, the Internet Printing Protocol
1240 * Handle "application/octet-stream" specially if this is
1241 * being dissected by the "CoAP for Thread Management Framework"
1244 if (coinfo
->is_coap_for_tmf
) {
1246 * Try the media type dissector table for CoAP-TMF first.
1248 result
= dissector_try_string_with_data(coap_tmf_media_type_dissector_table
,
1249 coap_ctype_str_dis
, payload_tvb
, pinfo
, parent_tree
, true,
1254 * That either failed or we didn't try it.
1255 * Now try the regular media type table.
1257 dissector_try_string_with_data(media_type_dissector_table
,
1258 coap_ctype_str_dis
, payload_tvb
, pinfo
, parent_tree
, true,
1261 if (coinfo
->object_security
&& !oscore
) {
1262 proto_item_set_text(payload_item
, "Encrypted OSCORE Data");
1263 call_dissector_with_data(oscore_handle
, payload_tvb
, pinfo
, parent_tree
, coinfo
->oscore_info
);
1268 coap_frame_length(tvbuff_t
*tvb
, unsigned offset
, int *size
)
1271 * Decode Len and Extended Length according to
1272 * https://tools.ietf.org/html/rfc8323#page-10
1274 uint8_t len
= tvb_get_uint8(tvb
, offset
) >> 4;
1280 if (tvb_reported_length_remaining(tvb
, offset
) < 2) {
1285 return tvb_get_uint8(tvb
, offset
+ 1) + 13;
1287 if (tvb_reported_length_remaining(tvb
, offset
) < 3) {
1292 return tvb_get_ntohs(tvb
, offset
+ 1) + 269;
1294 if (tvb_reported_length_remaining(tvb
, offset
) < 5) {
1299 return tvb_get_ntohl(tvb
, offset
+ 1) + 65805;
1304 dissect_coap_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, coap_parent_protocol parent_protocol
, bool is_coap_for_tmf
)
1307 proto_item
*coap_root
;
1309 proto_tree
*coap_tree
;
1310 int length_size
= 0;
1311 uint8_t ttype
= UINT8_MAX
;
1317 char *coap_token_str
;
1319 conversation_t
*conversation
;
1320 coap_conv_info
*ccinfo
;
1321 coap_transaction
*coap_trans
= NULL
;
1322 coap_request_response
*coap_req_rsp
= NULL
;
1324 // TODO support TCP/WebSocket/TCP with more than one PDU per packet.
1325 // These probably require a unique coinfo for each.
1327 /* Allocate information for upper layers */
1328 coinfo
= (coap_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_coap
, 0);
1332 coinfo
= wmem_new0(wmem_file_scope(), coap_info
);
1333 p_add_proto_data(wmem_file_scope(), pinfo
, proto_coap
, 0, coinfo
);
1336 // coinfo->parent_protocol = parent_protocol;
1337 coinfo
->is_coap_for_tmf
= is_coap_for_tmf
;
1338 /* check if trel is previously dissected */
1339 if (coinfo
->is_coap_for_tmf
== 0)
1341 unsigned id2
= proto_get_id_by_short_name("TREL");
1342 wmem_list_frame_t
* ptr2
= wmem_list_find(pinfo
->layers
, GUINT_TO_POINTER(id2
));
1345 coinfo
->is_coap_for_tmf
= 1;
1348 /* initialize the CoAP length and the content-Format */
1350 * The length of CoAP message is not specified in the CoAP header using
1351 * UDP or WebSockets. The lower layers provide it. For TCP/TLS, an
1352 * explicit length is present.
1354 coap_length
= tvb_reported_length(tvb
);
1355 if (parent_protocol
== PARENT_TCP_TLS
) {
1356 token_len
= tvb_get_uint8(tvb
, offset
) & 0xf;
1357 coap_length
= coap_frame_length(tvb
, offset
, &length_size
);
1358 if (length_size
< 0) {
1359 pinfo
->desegment_offset
= offset
;
1360 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
1361 return tvb_reported_length(tvb
);
1364 * Length of the whole CoAP frame includes the (Extended) Length fields
1365 * (1 to 4 bytes), the Code (1 byte) and token length (normally 0 to 8
1366 * bytes), plus everything afterwards.
1368 coap_length
+= 1 + token_len
+ length_size
;
1369 if (coap_length
> tvb_reported_length_remaining(tvb
, offset
)) {
1370 pinfo
->desegment_offset
= offset
;
1371 pinfo
->desegment_len
= coap_length
- tvb_reported_length_remaining(tvb
, offset
);
1372 return tvb_reported_length(tvb
);
1375 coinfo
->ctype_str
= "";
1376 coinfo
->ctype_value
= DEFAULT_COAP_CTYPE_VALUE
;
1378 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CoAP");
1379 col_clear(pinfo
->cinfo
, COL_INFO
);
1381 coap_root
= proto_tree_add_item(parent_tree
, proto_coap
, tvb
, offset
, -1, ENC_NA
);
1382 coap_tree
= proto_item_add_subtree(coap_root
, ett_coap
);
1384 if (parent_protocol
== PARENT_OTHER
) {
1385 proto_tree_add_item(coap_tree
, hf_coap_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1387 proto_tree_add_item(coap_tree
, hf_coap_ttype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1388 ttype
= (tvb_get_uint8(tvb
, offset
) & COAP_TYPE_MASK
) >> 4;
1390 proto_tree_add_item_ret_uint(coap_tree
, hf_coap_token_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &token_len
);
1393 code
= dissect_coap_code(tvb
, coap_tree
, &offset
, &dissect_coap_hf
, &code_class
);
1395 proto_tree_add_item(coap_tree
, hf_coap_mid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1396 mid
= tvb_get_ntohs(tvb
, offset
);
1399 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
1401 val_to_str(ttype
, vals_ttype_short
, "Unknown %u"),
1403 val_to_str_ext(code
, &coap_vals_code_ext
, "Unknown %u"));
1405 /* append the header information */
1406 proto_item_append_text(coap_root
,
1408 val_to_str(ttype
, vals_ttype
, "Unknown %u"),
1409 val_to_str_ext(code
, &coap_vals_code_ext
, "Unknown %u"),
1412 unsigned len
= coap_length
;
1413 if (parent_protocol
== PARENT_WEBSOCKETS
) {
1414 len
= tvb_get_uint8(tvb
, offset
) >> 4;
1417 proto_tree_add_uint(coap_tree
, hf_coap_length
, tvb
, offset
, length_size
, len
);
1419 proto_tree_add_item_ret_uint(coap_tree
, hf_coap_token_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &token_len
);
1420 offset
+= length_size
;
1422 code
= dissect_coap_code(tvb
, coap_tree
, &offset
, &dissect_coap_hf
, &code_class
);
1424 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
,
1425 val_to_str_ext(code
, &coap_vals_code_ext
, "Unknown %u"));
1427 /* append the header information */
1428 proto_item_append_text(coap_root
,
1430 val_to_str_ext(code
, &coap_vals_code_ext
, "Unknown %u"));
1433 /* initialize the external value */
1434 coinfo
->block_option
= 0;
1435 coinfo
->block_number
= DEFAULT_COAP_BLOCK_NUMBER
;
1436 coinfo
->block_mflag
= 0;
1437 coinfo
->uri_str_strbuf
= wmem_strbuf_create(pinfo
->pool
);
1438 coinfo
->uri_query_strbuf
= wmem_strbuf_create(pinfo
->pool
);
1439 /* Allocate pointers and static elements of oscore_info_t, arrays are allocated only if object security option is found during option parsing */
1440 coinfo
->oscore_info
= wmem_new0(pinfo
->pool
, oscore_info_t
);
1441 coinfo
->object_security
= false;
1442 coap_token_str
= NULL
;
1446 /* This has to be file scope as the token string is stored in the map
1447 * for conversation lookup */
1448 coap_token_str
= tvb_bytes_to_str_punct(wmem_file_scope(), tvb
, offset
, token_len
, ' ');
1449 proto_tree_add_item(coap_tree
, hf_coap_token
,
1450 tvb
, offset
, token_len
, ENC_NA
);
1451 offset
+= token_len
;
1454 /* process options */
1455 offset
= dissect_coap_options(tvb
, pinfo
, coap_tree
, offset
, coap_length
, code_class
, coinfo
, &dissect_coap_hf
);
1457 return tvb_captured_length(tvb
);
1459 /* Use conversations to track state for request/response */
1460 conversation
= find_or_create_conversation_noaddrb(pinfo
, (code_class
== 0));
1462 /* Retrieve or create state structure for this conversation */
1463 ccinfo
= (coap_conv_info
*)conversation_get_proto_data(conversation
, proto_coap
);
1465 /* No state structure - create it */
1466 ccinfo
= wmem_new(wmem_file_scope(), coap_conv_info
);
1467 ccinfo
->messages
= wmem_map_new(wmem_file_scope(), g_str_hash
, g_str_equal
);
1468 conversation_add_proto_data(conversation
, proto_coap
, ccinfo
);
1471 /* Everything based on tokens */
1472 if (coap_token_str
!= NULL
) {
1473 /* Process request/response in conversation */
1474 if (code
!= 0) { /* Ignore empty messages */
1475 /* Try and look up a matching token. If it's the first
1476 * sight of a request, there shouldn't be one */
1477 coap_trans
= (coap_transaction
*)wmem_map_lookup(ccinfo
->messages
, coap_token_str
);
1479 if ((!PINFO_FD_VISITED(pinfo
)) && (code_class
== 0)) {
1480 /* New request - log it */
1481 coap_trans
= wmem_new0(wmem_file_scope(), coap_transaction
);
1482 coap_trans
->req_rsp
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
1483 if (coinfo
->uri_str_strbuf
) {
1484 /* Store the URI into CoAP transaction info */
1485 coap_trans
->uri_str_strbuf
= wmem_strbuf_new(wmem_file_scope(), wmem_strbuf_get_str(coinfo
->uri_str_strbuf
));
1487 if (coinfo
->oscore_info
) {
1488 coap_trans
->oscore_info
= (oscore_info_t
*) wmem_memdup(wmem_file_scope(), coinfo
->oscore_info
, sizeof(oscore_info_t
));
1489 if (coinfo
->oscore_info
->kid
) {
1490 coap_trans
->oscore_info
->kid
= (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo
->oscore_info
->kid
, coinfo
->oscore_info
->kid_len
);
1492 if (coinfo
->oscore_info
->kid_context
) {
1493 coap_trans
->oscore_info
->kid_context
= (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo
->oscore_info
->kid_context
, coinfo
->oscore_info
->kid_context_len
);
1495 if (coinfo
->oscore_info
->piv
) {
1496 coap_trans
->oscore_info
->request_piv
= (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo
->oscore_info
->request_piv
, coinfo
->oscore_info
->request_piv_len
);
1499 wmem_map_insert(ccinfo
->messages
, coap_token_str
, (void *)coap_trans
);
1502 if ((code_class
>= 2) && (code_class
<= 5)) {
1503 if (coap_trans
->uri_str_strbuf
) {
1504 /* Copy the URI stored in matching transaction info into CoAP packet info */
1505 coinfo
->uri_str_strbuf
= wmem_strbuf_new(pinfo
->pool
, wmem_strbuf_get_str(coap_trans
->uri_str_strbuf
));
1507 if (coap_trans
->oscore_info
) {
1508 /* Copy OSCORE info in matching transaction info into CoAP packet info */
1509 if (coap_trans
->oscore_info
->kid
) {
1510 coinfo
->oscore_info
->kid
= (uint8_t *) wmem_memdup(pinfo
->pool
, coap_trans
->oscore_info
->kid
, coap_trans
->oscore_info
->kid_len
);
1512 coinfo
->oscore_info
->kid_len
= coap_trans
->oscore_info
->kid_len
;
1514 if (coap_trans
->oscore_info
->kid_context
) {
1515 coinfo
->oscore_info
->kid_context
= (uint8_t *) wmem_memdup(pinfo
->pool
, coap_trans
->oscore_info
->kid_context
, coap_trans
->oscore_info
->kid_context_len
);
1517 coinfo
->oscore_info
->kid_context_len
= coap_trans
->oscore_info
->kid_context_len
;
1519 if (coap_trans
->oscore_info
->request_piv
) {
1520 coinfo
->oscore_info
->request_piv
= (uint8_t *) wmem_memdup(pinfo
->pool
, coap_trans
->oscore_info
->request_piv
, coap_trans
->oscore_info
->request_piv_len
);
1522 coinfo
->oscore_info
->request_piv_len
= coap_trans
->oscore_info
->request_piv_len
;
1523 coinfo
->oscore_info
->response
= true;
1530 coap_req_rsp
= (coap_request_response
*)wmem_map_lookup(coap_trans
->req_rsp
, GINT_TO_POINTER(mid
));
1531 if (!PINFO_FD_VISITED(pinfo
)) {
1532 if (!coap_req_rsp
) {
1533 coap_req_rsp
= wmem_new0(wmem_file_scope(), coap_request_response
);
1534 wmem_map_insert(coap_trans
->req_rsp
, GINT_TO_POINTER(mid
), (void *)coap_req_rsp
);
1536 if (code_class
== 0) {
1537 /* This is a request */
1538 if (coap_req_rsp
->req_frame
== 0) {
1539 /* Log the first request frame */
1540 coap_req_rsp
->req_frame
= pinfo
->num
;
1541 coap_req_rsp
->req_time
= pinfo
->abs_ts
;
1543 } else if ((code_class
>= 2) && (code_class
<= 5)) {
1544 /* This is a reply */
1545 if (coap_req_rsp
->rsp_frame
== 0) {
1546 /* Log the first matching response frame */
1547 coap_req_rsp
->rsp_frame
= pinfo
->num
;
1555 /* dissect the payload */
1556 if (coap_length
> offset
) {
1557 if (coinfo
->block_number
== DEFAULT_COAP_BLOCK_NUMBER
) {
1558 dissect_coap_payload(tvb
, pinfo
, coap_tree
, parent_tree
, offset
, coap_length
,
1559 code_class
, coinfo
, &dissect_coap_hf
, false);
1561 proto_tree_add_bytes_format(coap_tree
, hf_block_payload
, tvb
, offset
,
1562 coap_length
- offset
, NULL
, "Block Payload");
1563 pi
= proto_tree_add_uint(coap_tree
, hf_block_length
, tvb
, offset
, 0, coap_length
- offset
);
1564 proto_item_set_generated(pi
);
1566 fragment_head
*frag_msg
= fragment_add_seq_check(&coap_block_reassembly_table
, tvb
, offset
,
1567 pinfo
, 0, NULL
, coinfo
->block_number
,
1568 coap_length
- offset
, coinfo
->block_mflag
);
1569 tvbuff_t
*frag_tvb
= process_reassembled_data(tvb
, offset
, pinfo
, "Reassembled CoAP blocks",
1570 frag_msg
, &coap_block_frag_items
, NULL
, coap_tree
);
1573 dissect_coap_payload(frag_tvb
, pinfo
, coap_tree
, parent_tree
, 0, tvb_reported_length(frag_tvb
),
1574 code_class
, coinfo
, &dissect_coap_hf
, false);
1579 /* add informations to the packet list */
1580 if (coap_token_str
!= NULL
)
1581 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", TKN:%s", coap_token_str
);
1582 if (coinfo
->block_number
!= DEFAULT_COAP_BLOCK_NUMBER
) {
1583 /* The M bit is used in Block1 Option in a request and in Block2 Option in a response */
1584 bool mflag_is_used
= (((coinfo
->block_option
== 1) && (code_class
== 0)) ||
1585 ((coinfo
->block_option
== 2) && (code_class
>= 2) && (code_class
<= 5)));
1586 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %sBlock #%u",
1587 (coinfo
->block_mflag
|| !mflag_is_used
) ? "" : "End of ", coinfo
->block_number
);
1589 if (wmem_strbuf_get_len(coinfo
->uri_str_strbuf
) > 0) {
1590 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", format_text(pinfo
->pool
, wmem_strbuf_get_str(coinfo
->uri_str_strbuf
), wmem_strbuf_get_len(coinfo
->uri_str_strbuf
)));
1591 /* Add a generated protocol item as well */
1592 pi
= proto_tree_add_string(coap_tree
, dissect_coap_hf
.hf
.opt_uri_path_recon
, tvb
, 0, 0, wmem_strbuf_get_str(coinfo
->uri_str_strbuf
));
1593 proto_item_set_generated(pi
);
1595 if (wmem_strbuf_get_len(coinfo
->uri_query_strbuf
) > 0)
1596 col_append_str(pinfo
->cinfo
, COL_INFO
, format_text(pinfo
->pool
, wmem_strbuf_get_str(coinfo
->uri_query_strbuf
), wmem_strbuf_get_len(coinfo
->uri_query_strbuf
)));
1598 if (coap_req_rsp
!= NULL
) {
1599 /* Print state tracking in the tree */
1600 if (code_class
== 0) {
1601 /* This is a request */
1602 if (coap_req_rsp
->rsp_frame
) {
1603 pi
= proto_tree_add_uint(coap_tree
, hf_coap_response_in
,
1604 tvb
, 0, 0, coap_req_rsp
->rsp_frame
);
1605 proto_item_set_generated(pi
);
1607 if ((ttype
== TT_CON
|| ttype
== TT_NON
) && (coap_req_rsp
->req_frame
!= pinfo
->num
)) {
1608 col_append_str(pinfo
->cinfo
, COL_INFO
, " [Retransmission]");
1609 pi
= proto_tree_add_uint(coap_tree
, hf_coap_request_resend_in
,
1610 tvb
, 0, 0, coap_req_rsp
->req_frame
);
1611 proto_item_set_generated(pi
);
1612 expert_add_info(pinfo
, pi
, &ei_retransmitted
);
1614 } else if ((code_class
>= 2) && (code_class
<= 5)) {
1615 /* This is a reply */
1616 if (coap_req_rsp
->req_frame
) {
1619 pi
= proto_tree_add_uint(coap_tree
, hf_coap_response_to
,
1620 tvb
, 0, 0, coap_req_rsp
->req_frame
);
1621 proto_item_set_generated(pi
);
1623 nstime_delta(&ns
, &pinfo
->abs_ts
, &coap_req_rsp
->req_time
);
1624 pi
= proto_tree_add_time(coap_tree
, hf_coap_response_time
, tvb
, 0, 0, &ns
);
1625 proto_item_set_generated(pi
);
1627 if ((ttype
== TT_CON
|| ttype
== TT_NON
) && (coap_req_rsp
->rsp_frame
!= pinfo
->num
)) {
1628 col_append_str(pinfo
->cinfo
, COL_INFO
, " [Retransmission]");
1629 pi
= proto_tree_add_uint(coap_tree
, hf_coap_response_resend_in
,
1630 tvb
, 0, 0, coap_req_rsp
->rsp_frame
);
1631 proto_item_set_generated(pi
);
1632 expert_add_info(pinfo
, pi
, &ei_retransmitted
);
1637 if (coap_trans
!= NULL
) {
1638 if ((code_class
>= 2) && (code_class
<= 5)) {
1639 /* This is a reply */
1640 if (coinfo
->object_security
&& coap_trans
->oscore_info
) {
1641 pi
= proto_tree_add_bytes(coap_tree
, hf_coap_oscore_kid
, tvb
, 0, coap_trans
->oscore_info
->kid_len
, coap_trans
->oscore_info
->kid
);
1642 proto_item_set_generated(pi
);
1644 pi
= proto_tree_add_bytes(coap_tree
, hf_coap_oscore_kid_context
, tvb
, 0, coap_trans
->oscore_info
->kid_context_len
, coap_trans
->oscore_info
->kid_context
);
1645 proto_item_set_generated(pi
);
1647 if (coinfo
->oscore_info
->piv_len
) {
1648 pi
= proto_tree_add_bytes(coap_tree
, hf_coap_oscore_piv
, tvb
, 0, coinfo
->oscore_info
->piv_len
, coinfo
->oscore_info
->piv
);
1650 pi
= proto_tree_add_bytes(coap_tree
, hf_coap_oscore_piv
, tvb
, 0, coinfo
->oscore_info
->request_piv_len
, coinfo
->oscore_info
->request_piv
);
1652 proto_item_set_generated(pi
);
1661 dissect_coap_tcp_tls(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1663 return dissect_coap_message(tvb
, pinfo
, tree
, PARENT_TCP_TLS
, false);
1667 dissect_coap_websockets(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1669 return dissect_coap_message(tvb
, pinfo
, tree
, PARENT_WEBSOCKETS
, false);
1673 dissect_coap_other(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1675 return dissect_coap_message(tvb
, pinfo
, tree
, PARENT_OTHER
, false);
1679 dissect_coap_for_tmf(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1681 return dissect_coap_message(tvb
, pinfo
, tree
, PARENT_OTHER
, true);
1685 * Protocol initialization
1688 proto_register_coap(void)
1690 static hf_register_info hf
[] = {
1692 { "Length", "coap.length",
1693 FT_UINT32
, BASE_DEC
, NULL
, 0,
1694 "Length of the CoAP frame, combining Len and Extended Length (if any) fields", HFILL
}
1697 { "Version", "coap.version",
1698 FT_UINT8
, BASE_DEC
, NULL
, COAP_VERSION_MASK
,
1702 { "Type", "coap.type",
1703 FT_UINT8
, BASE_DEC
, VALS(vals_ttype
), COAP_TYPE_MASK
,
1706 { &hf_coap_token_len
,
1707 { "Token Length", "coap.token_len",
1708 FT_UINT8
, BASE_DEC
, NULL
, COAP_TOKEN_LEN_MASK
,
1712 { "Token", "coap.token",
1713 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1717 { "Message ID", "coap.mid",
1718 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1721 { &hf_coap_response_in
,
1722 { "Response In", "coap.response_in",
1723 FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0,
1724 "The response to this CoAP request is in this frame", HFILL
}
1726 { &hf_coap_response_to
,
1727 { "Request In", "coap.response_to",
1728 FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0,
1729 "This is a response to the CoAP request in this frame", HFILL
}
1731 { &hf_coap_response_time
,
1732 { "Response Time", "coap.response_time",
1733 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
1734 "The time between the Call and the Reply", HFILL
}
1736 { &hf_coap_request_resend_in
,
1737 { "Retransmission of request in", "coap.request_first_in",
1738 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1739 "This request was first sent in this frame", HFILL
}
1741 { &hf_coap_response_resend_in
,
1742 { "Retransmission of response in", "coap.response_first_in",
1743 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1744 "This response was first sent in this frame", HFILL
}
1746 { &hf_coap_oscore_kid
,
1747 { "OSCORE Key ID", "coap.oscore_kid", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1748 "Matched OSCORE Key ID", HFILL
}
1750 { &hf_coap_oscore_kid_context
,
1751 { "OSCORE Key ID Context", "coap.oscore_kid_context", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1752 "Matched OSCORE Key ID Context", HFILL
}
1754 { &hf_coap_oscore_piv
,
1755 { "OSCORE Partial IV", "coap.oscore_piv", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1756 "Matched OSCORE Partial IV", HFILL
}
1758 { &hf_block_payload
,
1759 { "Block Payload", "coap.block_payload",
1760 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
1764 { "Block Length", "coap.block_length",
1765 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
1769 { "Blocks", "coap.blocks",
1770 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1774 { "Block", "coap.block",
1775 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
1778 { &hf_block_overlap
,
1779 { "Block overlap", "coap.block.overlap",
1780 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1783 { &hf_block_overlap_conflicts
,
1784 { "Block overlapping with conflicting data", "coap.block.overlap.conflicts",
1785 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1788 { &hf_block_multiple_tails
,
1789 { "Block has multiple tails", "coap.block.multiple_tails",
1790 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1793 { &hf_block_too_long
,
1794 { "Block too long", "coap.block.too_long",
1795 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1799 { "Block defragmentation error", "coap.block.error",
1800 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
1804 { "Block count", "coap.block.count",
1805 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
1808 { &hf_block_reassembled_in
,
1809 { "Reassembled in", "coap.block.reassembled.in",
1810 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
1813 { &hf_block_reassembled_length
,
1814 { "Reassembled block length", "coap.block.reassembled.length",
1815 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
1818 COAP_COMMON_HF_LIST(dissect_coap_hf
, "coap")
1821 static int *ett
[] = {
1825 COAP_COMMON_ETT_LIST(dissect_coap_hf
)
1828 static ei_register_info ei
[] = {
1829 { &ei_retransmitted
,
1830 { "coap.retransmitted", PI_SEQUENCE
, PI_NOTE
,
1831 "Retransmitted", EXPFILL
}
1833 COAP_COMMON_EI_LIST(dissect_coap_hf
, "coap")
1836 expert_module_t
*expert_coap
;
1838 proto_coap
= proto_register_protocol("Constrained Application Protocol", "CoAP", "coap");
1839 proto_register_field_array(proto_coap
, hf
, array_length(hf
));
1840 proto_register_subtree_array(ett
, array_length(ett
));
1841 expert_coap
= expert_register_protocol(proto_coap
);
1842 expert_register_field_array(expert_coap
, ei
, array_length(ei
));
1844 reassembly_table_register (&coap_block_reassembly_table
, &addresses_reassembly_table_functions
);
1846 coap_other_handle
= register_dissector("coap", dissect_coap_other
, proto_coap
);
1847 coap_tcp_tls_handle
= register_dissector("coap_tcp_tls", dissect_coap_tcp_tls
, proto_coap
);
1848 coap_for_tmf_handle
= register_dissector_with_description("coap_for_tmf", "CoAP-TMF", dissect_coap_for_tmf
, proto_coap_for_tmf
);
1851 * Set up a subdissector table for media types for CoAP-TMF.
1853 coap_tmf_media_type_dissector_table
=
1854 register_dissector_table("coap_tmf_media_type",
1855 "Internet media type for CoAP-TMF", proto_coap
, FT_STRING
, STRING_CASE_INSENSITIVE
);
1859 proto_reg_handoff_coap(void)
1861 dissector_handle_t coap_websockets_handle
;
1863 media_type_dissector_table
= find_dissector_table("media_type");
1866 dissector_add_uint_with_preference("udp.port", DEFAULT_COAP_PORT
, coap_other_handle
);
1867 dtls_dissector_add(DEFAULT_COAPS_PORT
, coap_other_handle
);
1870 dissector_add_uint_with_preference("tcp.port", DEFAULT_COAP_PORT
, coap_tcp_tls_handle
);
1871 ssl_dissector_add(DEFAULT_COAPS_PORT
, coap_tcp_tls_handle
);
1872 dissector_add_string("tls.alpn", "coap", coap_tcp_tls_handle
);
1874 /* WebSockets (RFC 8323) */
1875 coap_websockets_handle
= create_dissector_handle(dissect_coap_websockets
, proto_coap
);
1876 dissector_add_string("ws.protocol", "coap", coap_websockets_handle
);
1878 /* CoAP for Thread Management Framework */
1879 dissector_add_for_decode_as("udp.port", coap_for_tmf_handle
);
1881 oscore_handle
= find_dissector("oscore");
1885 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1890 * indent-tabs-mode: t
1893 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1894 * :indentSize=8:tabSize=8:noTabs=false: