| File: | builds/wireshark/wireshark/epan/dissectors/packet-coap.c |
| Warning: | line 1149, column 7 Branch condition evaluates to a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* packet-coap.c | |||
| 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> | |||
| 8 | * | |||
| 9 | * Changes for draft-ietf-core-coap-17.txt | |||
| 10 | * Hauke Mehrtens <hauke@hauke-m.de> | |||
| 11 | * | |||
| 12 | * Support for CoAP over TCP, TLS and WebSockets | |||
| 13 | * https://tools.ietf.org/html/rfc8323 | |||
| 14 | * Peter Wu <peter@lekensteyn.nl> | |||
| 15 | * | |||
| 16 | * Wireshark - Network traffic analyzer | |||
| 17 | * By Gerald Combs <gerald@wireshark.org> | |||
| 18 | * Copyright 1998 Gerald Combs | |||
| 19 | * | |||
| 20 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
| 21 | */ | |||
| 22 | ||||
| 23 | #include "config.h" | |||
| 24 | ||||
| 25 | ||||
| 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" | |||
| 40 | ||||
| 41 | void proto_register_coap(void); | |||
| 42 | ||||
| 43 | static dissector_table_t coap_tmf_media_type_dissector_table; | |||
| 44 | static dissector_table_t coap_uri_path_dissector_table; | |||
| 45 | static dissector_table_t media_type_dissector_table; | |||
| 46 | ||||
| 47 | static int proto_coap; | |||
| 48 | /* | |||
| 49 | * Used only to register the "CoAP for Thread Management Framework" | |||
| 50 | * dissector, which uses the same protocol and field IDs as the | |||
| 51 | * regular CoAP dissector, as it's just "CoAP except that we interpret | |||
| 52 | * application/octet-stream as meaning Thread Management Framework | |||
| 53 | * messages", because the Thread protocol, for whatever reasons (trying | |||
| 54 | * to keep the CoAP layer of their messages as short and simple to parse | |||
| 55 | * as possible, to save power and reduce the chances of low-power | |||
| 56 | * transmissions being misreceived?), did not register a media type for | |||
| 57 | * its messages and a 'cf' value for that media type. | |||
| 58 | */ | |||
| 59 | static int proto_coap_for_tmf; | |||
| 60 | ||||
| 61 | static int hf_coap_length; | |||
| 62 | static int hf_coap_version; | |||
| 63 | static int hf_coap_ttype; | |||
| 64 | static int hf_coap_token_len; | |||
| 65 | static int hf_coap_token; | |||
| 66 | static int hf_coap_mid; | |||
| 67 | ||||
| 68 | static int hf_coap_response_in; | |||
| 69 | static int hf_coap_response_to; | |||
| 70 | static int hf_coap_response_time; | |||
| 71 | static int hf_coap_request_resend_in; | |||
| 72 | static int hf_coap_response_resend_in; | |||
| 73 | static int hf_coap_oscore_kid; | |||
| 74 | static int hf_coap_oscore_kid_context; | |||
| 75 | static int hf_coap_oscore_piv; | |||
| 76 | ||||
| 77 | static int hf_block_payload; | |||
| 78 | static int hf_block_length; | |||
| 79 | ||||
| 80 | static int hf_blocks; | |||
| 81 | static int hf_block; | |||
| 82 | static int hf_block_overlap; | |||
| 83 | static int hf_block_overlap_conflicts; | |||
| 84 | static int hf_block_multiple_tails; | |||
| 85 | static int hf_block_too_long; | |||
| 86 | static int hf_block_error; | |||
| 87 | static int hf_block_count; | |||
| 88 | static int hf_block_reassembled_in; | |||
| 89 | static int hf_block_reassembled_length; | |||
| 90 | ||||
| 91 | static int ett_coap; | |||
| 92 | ||||
| 93 | static int ett_block; | |||
| 94 | static int ett_blocks; | |||
| 95 | ||||
| 96 | static expert_field ei_retransmitted; | |||
| 97 | ||||
| 98 | static COAP_COMMON_LIST_T(dissect_coap_hf)coap_common_dissect_t dissect_coap_hf; | |||
| 99 | ||||
| 100 | static dissector_handle_t coap_tcp_tls_handle; | |||
| 101 | static dissector_handle_t coap_other_handle; | |||
| 102 | static dissector_handle_t coap_for_tmf_handle; | |||
| 103 | static dissector_handle_t oscore_handle; | |||
| 104 | ||||
| 105 | /* CoAP's IANA-assigned TCP/UDP port numbers */ | |||
| 106 | #define DEFAULT_COAP_PORT5683 5683 | |||
| 107 | #define DEFAULT_COAPS_PORT5684 5684 | |||
| 108 | ||||
| 109 | /* indicators whether those are to be showed or not */ | |||
| 110 | #define DEFAULT_COAP_CTYPE_VALUE~0U ~0U | |||
| 111 | #define DEFAULT_COAP_BLOCK_NUMBER~0U ~0U | |||
| 112 | ||||
| 113 | /* Macros specific to the OCF version options */ | |||
| 114 | #define COAP_OCF_VERSION_SUB_MASK0x3F 0x3F | |||
| 115 | #define COAP_OCF_VERSION_MINOR_MASK0x7C0 0x7C0 | |||
| 116 | #define COAP_OCF_VERSION_MAJOR_MASK0xF800 0xF800 | |||
| 117 | ||||
| 118 | #define COAP_OCF_VERSION_MINOR_OFFSET6 6 | |||
| 119 | #define COAP_OCF_VERSION_MAJOR_OFFSET11 11 | |||
| 120 | ||||
| 121 | /* | |||
| 122 | * Transaction Type | |||
| 123 | */ | |||
| 124 | #define TT_CON0 0 // Confirmable | |||
| 125 | #define TT_NON1 1 // Non-Confirmable | |||
| 126 | static const value_string vals_ttype[] = { | |||
| 127 | { 0, "Confirmable" }, | |||
| 128 | { 1, "Non-Confirmable" }, | |||
| 129 | { 2, "Acknowledgement" }, | |||
| 130 | { 3, "Reset" }, | |||
| 131 | { 0, NULL((void*)0) }, | |||
| 132 | }; | |||
| 133 | static const value_string vals_ttype_short[] = { | |||
| 134 | { 0, "CON" }, | |||
| 135 | { 1, "NON" }, | |||
| 136 | { 2, "ACK" }, | |||
| 137 | { 3, "RST" }, | |||
| 138 | { 0, NULL((void*)0) }, | |||
| 139 | }; | |||
| 140 | ||||
| 141 | /* | |||
| 142 | * Method Code | |||
| 143 | * Response Code | |||
| 144 | * "c.dd" denotes (c << 5) | dd | |||
| 145 | */ | |||
| 146 | static const value_string vals_code[] = { | |||
| 147 | { 0, "Empty Message" }, | |||
| 148 | ||||
| 149 | /* Method Codes */ | |||
| 150 | { 1, "GET" }, | |||
| 151 | { 2, "POST" }, | |||
| 152 | { 3, "PUT" }, | |||
| 153 | { 4, "DELETE" }, | |||
| 154 | { 5, "FETCH" }, /* RFC 8132 */ | |||
| 155 | { 6, "PATCH" }, /* RFC 8132 */ | |||
| 156 | { 7, "iPATCH" }, /* RFC 8132 */ | |||
| 157 | ||||
| 158 | /* Response Codes */ | |||
| 159 | { 65, "2.01 Created" }, | |||
| 160 | { 66, "2.02 Deleted" }, | |||
| 161 | { 67, "2.03 Valid" }, | |||
| 162 | { 68, "2.04 Changed" }, | |||
| 163 | { 69, "2.05 Content" }, | |||
| 164 | { 95, "2.31 Continue" }, | |||
| 165 | { 128, "4.00 Bad Request" }, | |||
| 166 | { 129, "4.01 Unauthorized" }, | |||
| 167 | { 130, "4.02 Bad Option" }, | |||
| 168 | { 131, "4.03 Forbidden" }, | |||
| 169 | { 132, "4.04 Not Found" }, | |||
| 170 | { 133, "4.05 Method Not Allowed" }, | |||
| 171 | { 134, "4.06 Not Acceptable" }, | |||
| 172 | { 136, "4.08 Request Entity Incomplete" }, /* RFC 7959 */ | |||
| 173 | { 137, "4.09 Conflict" }, /* RFC 8132 */ | |||
| 174 | { 140, "4.12 Precondition Failed" }, | |||
| 175 | { 141, "4.13 Request Entity Too Large" }, | |||
| 176 | { 143, "4.15 Unsupported Content-Format" }, | |||
| 177 | { 150, "4.22 Unprocessable Entity" }, /* RFC 8132 */ | |||
| 178 | { 157, "4.29 Too Many Requests" }, /* RFC 8516 */ | |||
| 179 | { 160, "5.00 Internal Server Error" }, | |||
| 180 | { 161, "5.01 Not Implemented" }, | |||
| 181 | { 162, "5.02 Bad Gateway" }, | |||
| 182 | { 163, "5.03 Service Unavailable" }, | |||
| 183 | { 164, "5.04 Gateway Timeout" }, | |||
| 184 | { 165, "5.05 Proxying Not Supported" }, | |||
| 185 | { 168, "5.08 Hop Limit Reached" }, /* RFC 8768 */ | |||
| 186 | ||||
| 187 | /* Signalling Codes */ | |||
| 188 | { 225, "7.01 CSM" }, /* RFC 8323 */ | |||
| 189 | { 226, "7.02 Ping" }, /* RFC 8323 */ | |||
| 190 | { 227, "7.03 Pong" }, /* RFC 8323 */ | |||
| 191 | { 228, "7.04 Release" }, /* RFC 8323 */ | |||
| 192 | { 229, "7.05 Abort" }, /* RFC 8323 */ | |||
| 193 | ||||
| 194 | { 0, NULL((void*)0) }, | |||
| 195 | }; | |||
| 196 | value_string_ext coap_vals_code_ext = VALUE_STRING_EXT_INIT(vals_code){ _try_val_to_str_ext_init, 0, (sizeof (vals_code) / sizeof ( (vals_code)[0]))-1, vals_code, "vals_code", ((void*)0) }; | |||
| 197 | ||||
| 198 | const value_string coap_vals_observe_options[] = { | |||
| 199 | { 0, "Register" }, | |||
| 200 | { 1, "Deregister" }, | |||
| 201 | { 0, NULL((void*)0) }, | |||
| 202 | }; | |||
| 203 | ||||
| 204 | /* | |||
| 205 | * Option Headers | |||
| 206 | * No-Option must not be included in this structure, is handled in the function | |||
| 207 | * of the dissector, especially. | |||
| 208 | */ | |||
| 209 | #define COAP_OPT_IF_MATCH1 1 | |||
| 210 | #define COAP_OPT_URI_HOST3 3 | |||
| 211 | #define COAP_OPT_ETAG4 4 | |||
| 212 | #define COAP_OPT_IF_NONE_MATCH5 5 | |||
| 213 | #define COAP_OPT_OBSERVE6 6 /* RFC 7641 / RFC 8613 */ | |||
| 214 | #define COAP_OPT_URI_PORT7 7 | |||
| 215 | #define COAP_OPT_LOCATION_PATH8 8 | |||
| 216 | #define COAP_OPT_OBJECT_SECURITY9 9 /* RFC 8613 */ | |||
| 217 | #define COAP_OPT_URI_PATH11 11 | |||
| 218 | #define COAP_OPT_CONTENT_TYPE12 12 | |||
| 219 | #define COAP_OPT_MAX_AGE14 14 | |||
| 220 | #define COAP_OPT_URI_QUERY15 15 | |||
| 221 | #define COAP_OPT_HOP_LIMIT16 16 /* RFC 8768 */ | |||
| 222 | #define COAP_OPT_ACCEPT17 17 | |||
| 223 | #define COAP_OPT_QBLOCK119 19 /* RFC 9177 */ | |||
| 224 | #define COAP_OPT_LOCATION_QUERY20 20 | |||
| 225 | #define COAP_OPT_EDHOC21 21 /* draft-ietf-core-oscore-edhoc*/ | |||
| 226 | #define COAP_OPT_BLOCK223 23 /* RFC 7959 / RFC 8323 */ | |||
| 227 | #define COAP_OPT_BLOCK127 27 /* RFC 7959 / RFC 8323 */ | |||
| 228 | #define COAP_OPT_SIZE228 28 /* RFC 7959 */ | |||
| 229 | #define COAP_OPT_QBLOCK231 31 /* RFC 9177 */ | |||
| 230 | #define COAP_OPT_PROXY_URI35 35 | |||
| 231 | #define COAP_OPT_PROXY_SCHEME39 39 | |||
| 232 | #define COAP_OPT_SIZE160 60 | |||
| 233 | #define COAP_OPT_ECHO252 252 /* RFC 9175*/ | |||
| 234 | #define COAP_OPT_NO_RESPONSE258 258 /* RFC 7967 / RFC 8613 */ | |||
| 235 | #define COAP_OPT_REQUEST_TAG292 292 /* RFC 9175 */ | |||
| 236 | #define COAP_OPT_OCF_ACCEPT2049 2049 /* OCF Core specification */ | |||
| 237 | #define COAP_OPT_OCF_CONTENT2053 2053 /* OCF Core specification */ | |||
| 238 | ||||
| 239 | static const value_string vals_opt_type[] = { | |||
| 240 | { COAP_OPT_IF_MATCH1, "If-Match" }, | |||
| 241 | { COAP_OPT_URI_HOST3, "Uri-Host" }, | |||
| 242 | { COAP_OPT_ETAG4, "Etag" }, | |||
| 243 | { COAP_OPT_IF_NONE_MATCH5, "If-None-Match" }, | |||
| 244 | { COAP_OPT_URI_PORT7, "Uri-Port" }, | |||
| 245 | { COAP_OPT_LOCATION_PATH8, "Location-Path" }, | |||
| 246 | { COAP_OPT_OBJECT_SECURITY9,"OSCORE" }, | |||
| 247 | { COAP_OPT_URI_PATH11, "Uri-Path" }, | |||
| 248 | { COAP_OPT_CONTENT_TYPE12, "Content-Format" }, | |||
| 249 | { COAP_OPT_MAX_AGE14, "Max-age" }, | |||
| 250 | { COAP_OPT_URI_QUERY15, "Uri-Query" }, | |||
| 251 | { COAP_OPT_HOP_LIMIT16, "Hop-Limit" }, | |||
| 252 | { COAP_OPT_ACCEPT17, "Accept" }, | |||
| 253 | { COAP_OPT_QBLOCK119, "Q-Block1" }, | |||
| 254 | { COAP_OPT_LOCATION_QUERY20, "Location-Query" }, | |||
| 255 | { COAP_OPT_EDHOC21, "EDHOC" }, | |||
| 256 | { COAP_OPT_PROXY_URI35, "Proxy-Uri" }, | |||
| 257 | { COAP_OPT_PROXY_SCHEME39, "Proxy-Scheme" }, | |||
| 258 | { COAP_OPT_SIZE160, "Size1" }, | |||
| 259 | { COAP_OPT_OBSERVE6, "Observe" }, | |||
| 260 | { COAP_OPT_BLOCK223, "Block2" }, | |||
| 261 | { COAP_OPT_BLOCK127, "Block1" }, | |||
| 262 | { COAP_OPT_SIZE228, "Size2" }, | |||
| 263 | { COAP_OPT_QBLOCK231, "Q-Block2" }, | |||
| 264 | { COAP_OPT_ECHO252, "Echo" }, | |||
| 265 | { COAP_OPT_NO_RESPONSE258, "No-Response" }, | |||
| 266 | { COAP_OPT_REQUEST_TAG292, "Request-Tag" }, | |||
| 267 | { COAP_OPT_OCF_ACCEPT2049, "OCF-Accept-Content-Format-Version" }, | |||
| 268 | { COAP_OPT_OCF_CONTENT2053, "OCF-Content-Format-Version" }, | |||
| 269 | { 0, NULL((void*)0) }, | |||
| 270 | }; | |||
| 271 | ||||
| 272 | static const struct coap_option_range_t { | |||
| 273 | unsigned type; | |||
| 274 | int min; | |||
| 275 | int max; | |||
| 276 | } coi[] = { | |||
| 277 | { COAP_OPT_IF_MATCH1, 0, 8 }, | |||
| 278 | { COAP_OPT_URI_HOST3, 1, 255 }, | |||
| 279 | { COAP_OPT_ETAG4, 1, 8 }, | |||
| 280 | { COAP_OPT_IF_NONE_MATCH5, 0, 0 }, | |||
| 281 | { COAP_OPT_URI_PORT7, 0, 2 }, | |||
| 282 | { COAP_OPT_LOCATION_PATH8, 0, 255 }, | |||
| 283 | { COAP_OPT_OBJECT_SECURITY9, 0, 255 }, | |||
| 284 | { COAP_OPT_URI_PATH11, 0, 255 }, | |||
| 285 | { COAP_OPT_CONTENT_TYPE12, 0, 2 }, | |||
| 286 | { COAP_OPT_MAX_AGE14, 0, 4 }, | |||
| 287 | { COAP_OPT_URI_QUERY15, 1, 255 }, | |||
| 288 | { COAP_OPT_HOP_LIMIT16, 1, 1 }, | |||
| 289 | { COAP_OPT_ACCEPT17, 0, 2 }, | |||
| 290 | { COAP_OPT_QBLOCK119, 0, 3 }, | |||
| 291 | { COAP_OPT_LOCATION_QUERY20, 0, 255 }, | |||
| 292 | { COAP_OPT_EDHOC21, 0, 0 }, | |||
| 293 | { COAP_OPT_PROXY_URI35, 1,1034 }, | |||
| 294 | { COAP_OPT_PROXY_SCHEME39, 1, 255 }, | |||
| 295 | { COAP_OPT_SIZE160, 0, 4 }, | |||
| 296 | { COAP_OPT_OBSERVE6, 0, 3 }, | |||
| 297 | { COAP_OPT_BLOCK223, 0, 3 }, | |||
| 298 | { COAP_OPT_BLOCK127, 0, 3 }, | |||
| 299 | { COAP_OPT_SIZE228, 0, 4 }, | |||
| 300 | { COAP_OPT_QBLOCK231, 0, 3 }, | |||
| 301 | { COAP_OPT_ECHO252, 1, 40 }, | |||
| 302 | { COAP_OPT_NO_RESPONSE258, 0, 1 }, | |||
| 303 | { COAP_OPT_REQUEST_TAG292, 0, 8 }, | |||
| 304 | { COAP_OPT_OCF_ACCEPT2049, 2, 2 }, | |||
| 305 | { COAP_OPT_OCF_CONTENT2053, 2, 2 }, | |||
| 306 | }; | |||
| 307 | ||||
| 308 | static const value_string vals_ctype[] = { | |||
| 309 | { 0, "text/plain; charset=utf-8" }, | |||
| 310 | { 16, "application/cose; cose-type=\"cose-encrypt0\"" }, | |||
| 311 | { 17, "application/cose; cose-type=\"cose-mac0\"" }, | |||
| 312 | { 18, "application/cose; cose-type=\"cose-sign1\"" }, | |||
| 313 | { 19, "application/ace+cbor" }, | |||
| 314 | { 21, "image/gif" }, | |||
| 315 | { 22, "image/jpeg" }, | |||
| 316 | { 23, "image/png" }, | |||
| 317 | { 40, "application/link-format" }, | |||
| 318 | { 41, "application/xml" }, | |||
| 319 | { 42, "application/octet-stream" }, | |||
| 320 | { 47, "application/exi" }, | |||
| 321 | { 50, "application/json" }, | |||
| 322 | { 51, "application/json-patch+json" }, | |||
| 323 | { 52, "application/merge-patch+json" }, | |||
| 324 | { 60, "application/cbor" }, | |||
| 325 | { 61, "application/cwt" }, | |||
| 326 | { 62, "application/multipart-core" }, | |||
| 327 | { 63, "application/cbor-seq" }, | |||
| 328 | { 64, "application/edhoc+cbor-seq" }, | |||
| 329 | { 65, "application/cid-edhoc+cbor-seq" }, | |||
| 330 | { 96, "application/cose; cose-type=\"cose-encrypt\"" }, | |||
| 331 | { 97, "application/cose; cose-type=\"cose-mac\"" }, | |||
| 332 | { 98, "application/cose; cose-type=\"cose-sign\"" }, | |||
| 333 | { 101, "application/cose-key" }, | |||
| 334 | { 102, "application/cose-key-set" }, | |||
| 335 | { 110, "application/senml+json" }, | |||
| 336 | { 111, "application/sensml+json" }, | |||
| 337 | { 112, "application/senml+cbor" }, | |||
| 338 | { 113, "application/sensml+cbor" }, | |||
| 339 | { 114, "application/senml-exi" }, | |||
| 340 | { 115, "application/sensml-exi" }, | |||
| 341 | { 140, "application/yang-data+cbor; id=sid" }, | |||
| 342 | { 256, "application/coap-group+json" }, | |||
| 343 | { 257, "application/concise-problem-details+cbor" }, | |||
| 344 | { 258, "application/swid+cbor" }, | |||
| 345 | { 271, "application/dots+cbor" }, | |||
| 346 | { 272, "application/missing-blocks+cbor-seq" }, | |||
| 347 | { 280, "application/pkcs7-mime; smime-type=server-generated-key" }, | |||
| 348 | { 281, "application/pkcs7-mime; smime-type=certs-only" }, | |||
| 349 | { 284, "application/pkcs8" }, | |||
| 350 | { 285, "application/csrattrs" }, | |||
| 351 | { 286, "application/pkcs10" }, | |||
| 352 | { 287, "application/pkix-cert" }, | |||
| 353 | { 290, "application/aif+cbor" }, | |||
| 354 | { 291, "application/aif+json" }, | |||
| 355 | { 310, "application/senml+xml" }, | |||
| 356 | { 311, "application/sensml+xml" }, | |||
| 357 | { 320, "application/senml-etch+json" }, | |||
| 358 | { 322, "application/senml-etch+cbor" }, | |||
| 359 | { 340, "application/yang-data+cbor" }, | |||
| 360 | { 341, "application/yang-data+cbor; id=name" }, | |||
| 361 | { 432, "application/td+json" }, | |||
| 362 | { 433, "application/tm+json" }, | |||
| 363 | { 1542, "application/vnd.oma.lwm2m+tlv" }, | |||
| 364 | { 1543, "application/vnd.oma.lwm2m+json" }, | |||
| 365 | { 10000, "application/vnd.ocf+cbor" }, | |||
| 366 | { 10001, "application/oscore" }, | |||
| 367 | { 10002, "application/javascript" }, | |||
| 368 | { 11050, "application/json (Content Coding: deflate)" }, | |||
| 369 | { 11060, "application/cbor (Content Coding: deflate)" }, | |||
| 370 | { 11542, "application/vnd.oma.lwm2m+tlv" }, | |||
| 371 | { 11543, "application/vnd.oma.lwm2m+json" }, | |||
| 372 | { 20000, "text/css" }, | |||
| 373 | { 30000, "image/svg+xml" }, | |||
| 374 | { 0, NULL((void*)0) }, | |||
| 375 | }; | |||
| 376 | ||||
| 377 | static const char *nullstr = "(null)"; | |||
| 378 | ||||
| 379 | static reassembly_table coap_block_reassembly_table; | |||
| 380 | ||||
| 381 | static const fragment_items coap_block_frag_items = { | |||
| 382 | /* Fragment subtrees */ | |||
| 383 | &ett_block, | |||
| 384 | &ett_blocks, | |||
| 385 | /* Fragment fields */ | |||
| 386 | &hf_blocks, | |||
| 387 | &hf_block, | |||
| 388 | &hf_block_overlap, | |||
| 389 | &hf_block_overlap_conflicts, | |||
| 390 | &hf_block_multiple_tails, | |||
| 391 | &hf_block_too_long, | |||
| 392 | &hf_block_error, | |||
| 393 | &hf_block_count, | |||
| 394 | /* Reassembled in field */ | |||
| 395 | &hf_block_reassembled_in, | |||
| 396 | /* Reassembled length field */ | |||
| 397 | &hf_block_reassembled_length, | |||
| 398 | /* Reassembled data field */ | |||
| 399 | NULL((void*)0), | |||
| 400 | /* Tag */ | |||
| 401 | "Block fragments" | |||
| 402 | }; | |||
| 403 | ||||
| 404 | void proto_reg_handoff_coap(void); | |||
| 405 | ||||
| 406 | static conversation_t * | |||
| 407 | find_or_create_conversation_noaddrb(packet_info *pinfo, bool_Bool request) | |||
| 408 | { | |||
| 409 | conversation_t *conv=NULL((void*)0); | |||
| 410 | address *addr_a; | |||
| 411 | address *addr_b; | |||
| 412 | uint32_t port_a; | |||
| 413 | uint32_t port_b; | |||
| 414 | ||||
| 415 | if (pinfo->ptype != PT_TCP) { | |||
| 416 | if (request) { | |||
| 417 | addr_a = &pinfo->src; | |||
| 418 | addr_b = &pinfo->dst; | |||
| 419 | port_a = pinfo->srcport; | |||
| 420 | port_b = pinfo->destport; | |||
| 421 | } else { | |||
| 422 | addr_a = &pinfo->dst; | |||
| 423 | addr_b = &pinfo->src; | |||
| 424 | port_a = pinfo->destport; | |||
| 425 | port_b = pinfo->srcport; | |||
| 426 | } | |||
| 427 | /* Have we seen this conversation before? */ | |||
| 428 | if((conv = find_conversation(pinfo->num, addr_a, addr_b, | |||
| 429 | conversation_pt_to_conversation_type(pinfo->ptype), port_a, | |||
| 430 | port_b, NO_ADDR_B0x00010000|NO_PORT_B0x00020000)) != NULL((void*)0)) { | |||
| 431 | if (pinfo->num > conv->last_frame) { | |||
| 432 | conv->last_frame = pinfo->num; | |||
| 433 | } | |||
| 434 | } else { | |||
| 435 | /* No, this is a new conversation. */ | |||
| 436 | conv = conversation_new(pinfo->num, &pinfo->src, | |||
| 437 | &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), | |||
| 438 | pinfo->srcport, pinfo->destport, NO_ADDR20x01|NO_PORT20x02); | |||
| 439 | } | |||
| 440 | } else { | |||
| 441 | /* fetch the conversation created by the TCP dissector */ | |||
| 442 | conv = find_conversation_pinfo(pinfo, 0); | |||
| 443 | DISSECTOR_ASSERT(conv)((void) ((conv) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/dissectors/packet-coap.c", 443, "conv")))); | |||
| 444 | } | |||
| 445 | return conv; | |||
| 446 | } | |||
| 447 | ||||
| 448 | static int | |||
| 449 | coap_get_opt_uint(tvbuff_t *tvb, int offset, int length) | |||
| 450 | { | |||
| 451 | switch (length) { | |||
| 452 | case 0: | |||
| 453 | return 0; | |||
| 454 | case 1: | |||
| 455 | return (unsigned)tvb_get_uint8(tvb, offset); | |||
| 456 | case 2: | |||
| 457 | return (unsigned)tvb_get_ntohs(tvb, offset); | |||
| 458 | case 3: | |||
| 459 | return (unsigned)tvb_get_ntoh24(tvb, offset); | |||
| 460 | case 4: | |||
| 461 | return (unsigned)tvb_get_ntohl(tvb, offset); | |||
| 462 | default: | |||
| 463 | return -1; | |||
| 464 | } | |||
| 465 | } | |||
| 466 | ||||
| 467 | static int | |||
| 468 | coap_opt_check(packet_info *pinfo, proto_tree *subtree, unsigned opt_num, int opt_length, coap_common_dissect_t *dissect_hf) | |||
| 469 | { | |||
| 470 | int i; | |||
| 471 | ||||
| 472 | for (i = 0; i < (int)(array_length(coi)(sizeof (coi) / sizeof (coi)[0])); i++) { | |||
| 473 | if (coi[i].type == opt_num) | |||
| 474 | break; | |||
| 475 | } | |||
| 476 | if (i == (int)(array_length(coi)(sizeof (coi) / sizeof (coi)[0]))) { | |||
| 477 | if (opt_num >= 2048 && opt_num <= 65535) { | |||
| 478 | /* private, vendor-specific or reserved for experiments */ | |||
| 479 | expert_add_info_format(pinfo, subtree, &dissect_hf->ei.opt_unknown_number, | |||
| 480 | "Unknown Option Number %u", opt_num); | |||
| 481 | } else { | |||
| 482 | expert_add_info_format(pinfo, subtree, &dissect_hf->ei.opt_invalid_number, | |||
| 483 | "Invalid Option Number %u", opt_num); | |||
| 484 | } | |||
| 485 | return -1; | |||
| 486 | } | |||
| 487 | if (opt_length < coi[i].min || opt_length > coi[i].max) { | |||
| 488 | expert_add_info_format(pinfo, subtree, &dissect_hf->ei.opt_invalid_range, | |||
| 489 | "Invalid Option Range: %d (%d < x < %d)", opt_length, coi[i].min, coi[i].max); | |||
| 490 | } | |||
| 491 | ||||
| 492 | return 0; | |||
| 493 | } | |||
| 494 | ||||
| 495 | static void | |||
| 496 | dissect_coap_opt_hex_string(tvbuff_t *tvb, packet_info *pinfo, proto_item *item, proto_tree *subtree, int offset, int opt_length, int hf) | |||
| 497 | { | |||
| 498 | const char *str; | |||
| 499 | ||||
| 500 | if (opt_length == 0) | |||
| 501 | str = nullstr; | |||
| 502 | else | |||
| 503 | str = tvb_bytes_to_str_punct(pinfo->pool, tvb, offset, opt_length, ' '); | |||
| 504 | ||||
| 505 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_NA0x00000000); | |||
| 506 | ||||
| 507 | /* add info to the head of the packet detail */ | |||
| 508 | proto_item_append_text(item, ": %s", str); | |||
| 509 | } | |||
| 510 | ||||
| 511 | static void | |||
| 512 | dissect_coap_opt_uint(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, int offset, int opt_length, int hf) | |||
| 513 | { | |||
| 514 | unsigned i = 0; | |||
| 515 | ||||
| 516 | if (opt_length != 0) { | |||
| 517 | i = coap_get_opt_uint(tvb, offset, opt_length); | |||
| 518 | } | |||
| 519 | ||||
| 520 | proto_tree_add_uint(subtree, hf, tvb, offset, opt_length, i); | |||
| 521 | ||||
| 522 | /* add info to the head of the packet detail */ | |||
| 523 | proto_item_append_text(head_item, ": %u", i); | |||
| 524 | } | |||
| 525 | ||||
| 526 | static void | |||
| 527 | 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 | { | |||
| 529 | const char *str; | |||
| 530 | ||||
| 531 | proto_tree_add_item_ret_string(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000, pinfo->pool, (const uint8_t**)&str); | |||
| 532 | ||||
| 533 | /* add info to the head of the packet detail */ | |||
| 534 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 535 | ||||
| 536 | /* forming a uri-string | |||
| 537 | * If the 'uri host' looks an IPv6 address, assuming that the address has | |||
| 538 | * to be enclosed by brackets. | |||
| 539 | */ | |||
| 540 | if (strchr(str, ':') == NULL((void*)0)) { | |||
| 541 | wmem_strbuf_append_printf(coinfo->uri_host_strbuf, "coap://%s", str); | |||
| 542 | } else { | |||
| 543 | wmem_strbuf_append_printf(coinfo->uri_host_strbuf, "coap://[%s]", str); | |||
| 544 | } | |||
| 545 | } | |||
| 546 | ||||
| 547 | static void | |||
| 548 | 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) | |||
| 549 | { | |||
| 550 | const char *str = NULL((void*)0); | |||
| 551 | ||||
| 552 | wmem_strbuf_append_c(coinfo->uri_path_strbuf, '/'); | |||
| 553 | ||||
| 554 | if (opt_length == 0) { | |||
| 555 | str = nullstr; | |||
| 556 | } else { | |||
| 557 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 558 | wmem_strbuf_append(coinfo->uri_path_strbuf, str); | |||
| 559 | } | |||
| 560 | ||||
| 561 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 562 | ||||
| 563 | /* add info to the head of the packet detail */ | |||
| 564 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 565 | } | |||
| 566 | ||||
| 567 | static void | |||
| 568 | 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) | |||
| 569 | { | |||
| 570 | const char *str = NULL((void*)0); | |||
| 571 | ||||
| 572 | wmem_strbuf_append_c(coinfo->uri_query_strbuf, | |||
| 573 | (wmem_strbuf_get_len(coinfo->uri_query_strbuf) == 0) ? '?' : '&'); | |||
| 574 | ||||
| 575 | if (opt_length == 0) { | |||
| 576 | str = nullstr; | |||
| 577 | } else { | |||
| 578 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 579 | wmem_strbuf_append(coinfo->uri_query_strbuf, str); | |||
| 580 | } | |||
| 581 | ||||
| 582 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 583 | ||||
| 584 | /* add info to the head of the packet detail */ | |||
| 585 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 586 | } | |||
| 587 | ||||
| 588 | static void | |||
| 589 | 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) | |||
| 590 | { | |||
| 591 | const char *str = NULL((void*)0); | |||
| 592 | ||||
| 593 | if (opt_length == 0) { | |||
| 594 | str = nullstr; | |||
| 595 | } else { | |||
| 596 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 597 | } | |||
| 598 | ||||
| 599 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 600 | ||||
| 601 | /* add info to the head of the packet detail */ | |||
| 602 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 603 | } | |||
| 604 | ||||
| 605 | static void | |||
| 606 | 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) | |||
| 607 | { | |||
| 608 | const char *str = NULL((void*)0); | |||
| 609 | ||||
| 610 | if (opt_length == 0) { | |||
| 611 | str = nullstr; | |||
| 612 | } else { | |||
| 613 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 614 | } | |||
| 615 | ||||
| 616 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 617 | ||||
| 618 | /* add info to the head of the packet detail */ | |||
| 619 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 620 | } | |||
| 621 | ||||
| 622 | /* rfc8613 */ | |||
| 623 | static void | |||
| 624 | 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) | |||
| 625 | { | |||
| 626 | uint8_t flag_byte = 0; | |||
| 627 | bool_Bool reserved = false0; | |||
| 628 | bool_Bool kid_context_present = false0; | |||
| 629 | bool_Bool kid_present = false0; | |||
| 630 | uint8_t piv_len = 0; | |||
| 631 | uint8_t kid_context_len = 0; | |||
| 632 | uint8_t kid_len = 0; | |||
| 633 | ||||
| 634 | coinfo->object_security = true1; | |||
| 635 | ||||
| 636 | coinfo->oscore_info->piv = NULL((void*)0); | |||
| 637 | coinfo->oscore_info->piv_len = 0; | |||
| 638 | coinfo->oscore_info->request_piv = NULL((void*)0); | |||
| 639 | coinfo->oscore_info->request_piv_len = 0; | |||
| 640 | coinfo->oscore_info->kid_context = NULL((void*)0); | |||
| 641 | coinfo->oscore_info->kid_context_len = 0; | |||
| 642 | coinfo->oscore_info->kid = NULL((void*)0); | |||
| 643 | coinfo->oscore_info->kid_len = 0; | |||
| 644 | coinfo->oscore_info->response = false0; | |||
| 645 | ||||
| 646 | if (opt_length == 0) { /* option length is zero, means flag byte is 0x00*/ | |||
| 647 | /* add info to the head of the packet detail */ | |||
| 648 | proto_item_append_text(head_item, ": 00 (no Flag Byte)"); | |||
| 649 | } else { | |||
| 650 | flag_byte = tvb_get_uint8(tvb, offset); | |||
| 651 | ||||
| 652 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_reserved, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 653 | reserved = flag_byte & COAP_OBJECT_SECURITY_RESERVED_MASK0xE0; | |||
| 654 | ||||
| 655 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_kid_context_present, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 656 | kid_context_present = flag_byte & COAP_OBJECT_SECURITY_KID_CONTEXT_MASK0x10; | |||
| 657 | ||||
| 658 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_kid_present, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 659 | kid_present = flag_byte & COAP_OBJECT_SECURITY_KID_MASK0x08; | |||
| 660 | ||||
| 661 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_piv_len, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 662 | piv_len = (flag_byte & COAP_OBJECT_SECURITY_PIVLEN_MASK0x07) >> 0; | |||
| 663 | ||||
| 664 | /* kid_len is what remains in the option after all other fields are parsed | |||
| 665 | we calculate kid_len by subtracting from option length as we parse individual fields */ | |||
| 666 | kid_len = opt_length; | |||
| 667 | ||||
| 668 | offset += 1; | |||
| 669 | kid_len -= 1; | |||
| 670 | ||||
| 671 | if (reserved) { | |||
| 672 | /* how these bits are handled is not yet specified */ | |||
| 673 | expert_add_info_format(pinfo, subtree, &dissect_hf->ei.opt_object_security_bad, "Unsupported format"); | |||
| 674 | } | |||
| 675 | ||||
| 676 | if (piv_len > 0) { | |||
| 677 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_piv, tvb, offset, piv_len, ENC_NA0x00000000); | |||
| 678 | coinfo->oscore_info->piv = (uint8_t *) tvb_memdup(pinfo->pool, tvb, offset, piv_len); | |||
| 679 | coinfo->oscore_info->piv_len = piv_len; | |||
| 680 | ||||
| 681 | if (code_class == 0) { | |||
| 682 | /* If this is a request, copy PIV to request_piv */ | |||
| 683 | coinfo->oscore_info->request_piv = (uint8_t *) tvb_memdup(pinfo->pool, tvb, offset, piv_len); | |||
| 684 | coinfo->oscore_info->request_piv_len = piv_len; | |||
| 685 | } | |||
| 686 | ||||
| 687 | offset += piv_len; | |||
| 688 | kid_len -= piv_len; | |||
| 689 | } | |||
| 690 | ||||
| 691 | if (kid_context_present) { | |||
| 692 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_kid_context_len, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 693 | kid_context_len = tvb_get_uint8(tvb, offset); | |||
| 694 | ||||
| 695 | offset += 1; | |||
| 696 | kid_len -= 1; | |||
| 697 | ||||
| 698 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_kid_context, tvb, offset, kid_context_len, ENC_NA0x00000000); | |||
| 699 | coinfo->oscore_info->kid_context = (uint8_t *) tvb_memdup(pinfo->pool, tvb, offset, kid_context_len); | |||
| 700 | coinfo->oscore_info->kid_context_len = kid_context_len; | |||
| 701 | ||||
| 702 | offset += kid_context_len; | |||
| 703 | kid_len -= kid_context_len; | |||
| 704 | } | |||
| 705 | ||||
| 706 | if (kid_present) { | |||
| 707 | proto_tree_add_item(subtree, dissect_hf->hf.opt_object_security_kid, tvb, offset, kid_len, ENC_NA0x00000000); | |||
| 708 | coinfo->oscore_info->kid = (uint8_t *) tvb_memdup(pinfo->pool, tvb, offset, kid_len); | |||
| 709 | coinfo->oscore_info->kid_len = kid_len; | |||
| 710 | ||||
| 711 | } | |||
| 712 | ||||
| 713 | proto_item_append_text(head_item, ": Key ID:%s, Key ID Context:%s, Partial IV:%s", | |||
| 714 | coinfo->oscore_info->kid == NULL((void*)0) ? nullstr : bytes_to_str(pinfo->pool, coinfo->oscore_info->kid, coinfo->oscore_info->kid_len)bytes_to_str_maxlen(pinfo->pool, coinfo->oscore_info-> kid, coinfo->oscore_info->kid_len, 36), | |||
| 715 | coinfo->oscore_info->kid_context == NULL((void*)0) ? nullstr : bytes_to_str(pinfo->pool, coinfo->oscore_info->kid_context, coinfo->oscore_info->kid_context_len)bytes_to_str_maxlen(pinfo->pool, coinfo->oscore_info-> kid_context, coinfo->oscore_info->kid_context_len, 36), | |||
| 716 | coinfo->oscore_info->piv == NULL((void*)0) ? nullstr : bytes_to_str(pinfo->pool, coinfo->oscore_info->piv, coinfo->oscore_info->piv_len)bytes_to_str_maxlen(pinfo->pool, coinfo->oscore_info-> piv, coinfo->oscore_info->piv_len, 36)); | |||
| 717 | } | |||
| 718 | } | |||
| 719 | ||||
| 720 | static void | |||
| 721 | 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) | |||
| 722 | { | |||
| 723 | const char *str = NULL((void*)0); | |||
| 724 | ||||
| 725 | if (opt_length == 0) { | |||
| 726 | str = nullstr; | |||
| 727 | } else { | |||
| 728 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 729 | } | |||
| 730 | ||||
| 731 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 732 | ||||
| 733 | /* add info to the head of the packet detail */ | |||
| 734 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 735 | } | |||
| 736 | ||||
| 737 | static void | |||
| 738 | 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) | |||
| 739 | { | |||
| 740 | const char *str = NULL((void*)0); | |||
| 741 | ||||
| 742 | if (opt_length == 0) { | |||
| 743 | str = nullstr; | |||
| 744 | } else { | |||
| 745 | str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 746 | } | |||
| 747 | ||||
| 748 | proto_tree_add_item(subtree, hf, tvb, offset, opt_length, ENC_ASCII0x00000000); | |||
| 749 | ||||
| 750 | /* add info to the head of the packet detail */ | |||
| 751 | proto_item_append_text(head_item, ": %s", format_text_string(pinfo->pool, str)); | |||
| 752 | } | |||
| 753 | ||||
| 754 | static void | |||
| 755 | dissect_coap_opt_ctype(tvbuff_t *tvb, packet_info* pinfo, proto_item *head_item, proto_tree *subtree, int offset, int opt_length, int hf, coap_info *coinfo) | |||
| 756 | { | |||
| 757 | if (opt_length == 0) { | |||
| 758 | coinfo->ctype_value = 0; | |||
| 759 | } else { | |||
| 760 | coinfo->ctype_value = coap_get_opt_uint(tvb, offset, opt_length); | |||
| 761 | } | |||
| 762 | ||||
| 763 | coinfo->ctype_str = val_to_str(pinfo->pool, coinfo->ctype_value, vals_ctype, "Unknown Type %u"); | |||
| 764 | ||||
| 765 | proto_tree_add_string(subtree, hf, tvb, offset, opt_length, coinfo->ctype_str); | |||
| 766 | ||||
| 767 | /* add info to the head of the packet detail */ | |||
| 768 | proto_item_append_text(head_item, ": %s", coinfo->ctype_str); | |||
| 769 | } | |||
| 770 | ||||
| 771 | static void | |||
| 772 | dissect_coap_opt_accept(tvbuff_t *tvb, packet_info* pinfo, proto_item *head_item, proto_tree *subtree, int offset, int opt_length, int hf) | |||
| 773 | { | |||
| 774 | const char *str = NULL((void*)0); | |||
| 775 | ||||
| 776 | if (opt_length == 0) { | |||
| 777 | str = nullstr; | |||
| 778 | } else { | |||
| 779 | unsigned value = coap_get_opt_uint(tvb, offset, opt_length); | |||
| 780 | str = val_to_str(pinfo->pool, value, vals_ctype, "Unknown Type %u"); | |||
| 781 | } | |||
| 782 | ||||
| 783 | proto_tree_add_string(subtree, hf, tvb, offset, opt_length, str); | |||
| 784 | ||||
| 785 | /* add info to the head of the packet detail */ | |||
| 786 | proto_item_append_text(head_item, ": %s", str); | |||
| 787 | } | |||
| 788 | ||||
| 789 | static void | |||
| 790 | 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) | |||
| 791 | { | |||
| 792 | uint8_t val = 0; | |||
| 793 | unsigned encoded_block_size; | |||
| 794 | unsigned block_esize; | |||
| 795 | ||||
| 796 | if (opt_length == 0) { | |||
| 797 | coinfo->block_number = 0; | |||
| 798 | val = 0; | |||
| 799 | } else { | |||
| 800 | coinfo->block_number = coap_get_opt_uint(tvb, offset, opt_length) >> 4; | |||
| 801 | val = tvb_get_uint8(tvb, offset + opt_length - 1) & 0x0f; | |||
| 802 | } | |||
| 803 | ||||
| 804 | proto_tree_add_uint(subtree, dissect_hf->hf.opt_block_number, | |||
| 805 | tvb, offset, opt_length, coinfo->block_number); | |||
| 806 | ||||
| 807 | /* More flag in the end of the option */ | |||
| 808 | coinfo->block_mflag = (val & COAP_BLOCK_MFLAG_MASK0x08) >> 3; | |||
| 809 | proto_tree_add_uint(subtree, dissect_hf->hf.opt_block_mflag, | |||
| 810 | tvb, offset + opt_length - 1, 1, val); | |||
| 811 | ||||
| 812 | /* block size */ | |||
| 813 | encoded_block_size = val & COAP_BLOCK_SIZE_MASK0x07; | |||
| 814 | block_esize = 1 << (encoded_block_size + 4); | |||
| 815 | proto_tree_add_uint_format(subtree, dissect_hf->hf.opt_block_size, | |||
| 816 | tvb, offset + opt_length - 1, 1, encoded_block_size, "Block Size: %u (%u encoded)", block_esize, encoded_block_size); | |||
| 817 | ||||
| 818 | /* add info to the head of the packet detail */ | |||
| 819 | proto_item_append_text(head_item, ": NUM:%u, M:%u, SZ:%u", | |||
| 820 | coinfo->block_number, coinfo->block_mflag, block_esize); | |||
| 821 | } | |||
| 822 | ||||
| 823 | static void | |||
| 824 | dissect_coap_opt_ocf_version(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, int offset, int opt_length, int hfindex) | |||
| 825 | { | |||
| 826 | unsigned option_value = coap_get_opt_uint(tvb, offset, opt_length); | |||
| 827 | ||||
| 828 | unsigned sub_version = option_value & COAP_OCF_VERSION_SUB_MASK0x3F; | |||
| 829 | unsigned minor_version = (option_value & COAP_OCF_VERSION_MINOR_MASK0x7C0) >> COAP_OCF_VERSION_MINOR_OFFSET6; | |||
| 830 | unsigned major_version = (option_value & COAP_OCF_VERSION_MAJOR_MASK0xF800) >> COAP_OCF_VERSION_MAJOR_OFFSET11; | |||
| 831 | ||||
| 832 | proto_tree_add_uint(subtree, hfindex, tvb, offset, opt_length, option_value); | |||
| 833 | ||||
| 834 | /* add info to the head of the packet detail */ | |||
| 835 | proto_item_append_text(head_item, ": %u.%u.%u", | |||
| 836 | major_version, minor_version, sub_version); | |||
| 837 | } | |||
| 838 | ||||
| 839 | static void | |||
| 840 | 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 | { | |||
| 842 | unsigned port = 0; | |||
| 843 | ||||
| 844 | if (opt_length != 0) { | |||
| 845 | port = coap_get_opt_uint(tvb, offset, opt_length); | |||
| 846 | } | |||
| 847 | ||||
| 848 | proto_tree_add_uint(subtree, hf, tvb, offset, opt_length, port); | |||
| 849 | ||||
| 850 | proto_item_append_text(head_item, ": %u", port); | |||
| 851 | ||||
| 852 | /* forming a uri-string */ | |||
| 853 | wmem_strbuf_append_printf(coinfo->uri_host_strbuf, ":%u", port); | |||
| 854 | } | |||
| 855 | ||||
| 856 | /* | |||
| 857 | * dissector for each option of CoAP. | |||
| 858 | * return the total length of the option including the header (e.g. delta and length). | |||
| 859 | */ | |||
| 860 | static unsigned | |||
| 861 | dissect_coap_options_main(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, unsigned offset, uint8_t opt_count, unsigned *opt_num, unsigned offset_end, uint8_t code_class, coap_info *coinfo, coap_common_dissect_t *dissect_hf, bool_Bool *ok) | |||
| 862 | { | |||
| 863 | uint8_t opt_jump; | |||
| 864 | int opt_length, opt_length_ext, opt_delta, opt_delta_ext; | |||
| 865 | int opt_length_ext_off = 0; | |||
| 866 | int8_t opt_length_ext_len = 0; | |||
| 867 | int opt_delta_ext_off = 0; | |||
| 868 | int8_t opt_delta_ext_len = 0; | |||
| 869 | int orig_offset = offset; | |||
| 870 | proto_tree *subtree; | |||
| 871 | proto_item *item; | |||
| 872 | char *strbuf2; | |||
| 873 | ||||
| 874 | opt_jump = tvb_get_uint8(tvb, offset); | |||
| 875 | if (0xff == opt_jump) | |||
| 876 | return offset; | |||
| 877 | offset += 1; | |||
| 878 | ||||
| 879 | /* | |||
| 880 | * section 3.1 in coap-17: | |||
| 881 | * Option Delta: 4-bit unsigned integer. A value between 0 and 12 | |||
| 882 | * indicates the Option Delta. Three values are reserved for special | |||
| 883 | * constructs: | |||
| 884 | * | |||
| 885 | * 13: An 8-bit unsigned integer follows the initial byte and | |||
| 886 | * indicates the Option Delta minus 13. | |||
| 887 | * | |||
| 888 | * 14: A 16-bit unsigned integer in network byte order follows the | |||
| 889 | * initial byte and indicates the Option Delta minus 269. | |||
| 890 | * | |||
| 891 | * 15: Reserved for the Payload Marker. If the field is set to this | |||
| 892 | * value but the entire byte is not the payload marker, this MUST | |||
| 893 | * be processed as a message format error. | |||
| 894 | */ | |||
| 895 | switch (opt_jump & 0xf0) { | |||
| 896 | case 0xd0: | |||
| 897 | opt_delta_ext = tvb_get_uint8(tvb, offset); | |||
| 898 | opt_delta_ext_off = offset; | |||
| 899 | opt_delta_ext_len = 1; | |||
| 900 | offset += 1; | |||
| 901 | ||||
| 902 | opt_delta = 13; | |||
| 903 | opt_delta += opt_delta_ext; | |||
| 904 | break; | |||
| 905 | case 0xe0: | |||
| 906 | opt_delta_ext = coap_get_opt_uint(tvb, offset, 2); | |||
| 907 | opt_delta_ext_off = offset; | |||
| 908 | opt_delta_ext_len = 2; | |||
| 909 | offset += 2; | |||
| 910 | ||||
| 911 | opt_delta = 269; | |||
| 912 | opt_delta += opt_delta_ext; | |||
| 913 | break; | |||
| 914 | case 0xf0: | |||
| 915 | expert_add_info_format(pinfo, coap_tree, &dissect_hf->ei.opt_length_bad, | |||
| 916 | "end-of-options marker found, but option length isn't 15"); | |||
| 917 | *ok = false0; return offset; | |||
| 918 | default: | |||
| 919 | opt_delta = ((opt_jump & 0xf0) >> 4); | |||
| 920 | break; | |||
| 921 | } | |||
| 922 | *opt_num += opt_delta; | |||
| 923 | ||||
| 924 | /* | |||
| 925 | * section 3.1 in coap-17: | |||
| 926 | * Option Length: 4-bit unsigned integer. A value between 0 and 12 | |||
| 927 | * indicates the length of the Option Value, in bytes. Three values | |||
| 928 | * are reserved for special constructs: | |||
| 929 | * | |||
| 930 | * 13: An 8-bit unsigned integer precedes the Option Value and | |||
| 931 | * indicates the Option Length minus 13. | |||
| 932 | * | |||
| 933 | * 14: A 16-bit unsigned integer in network byte order precedes the | |||
| 934 | * Option Value and indicates the Option Length minus 269. | |||
| 935 | * | |||
| 936 | * 15: Reserved for future use. If the field is set to this value, | |||
| 937 | * it MUST be processed as a message format error. | |||
| 938 | */ | |||
| 939 | switch (opt_jump & 0x0f) { | |||
| 940 | case 0x0d: | |||
| 941 | opt_length_ext = tvb_get_uint8(tvb, offset); | |||
| 942 | opt_length_ext_off = offset; | |||
| 943 | opt_length_ext_len = 1; | |||
| 944 | offset += 1; | |||
| 945 | ||||
| 946 | opt_length = 13; | |||
| 947 | opt_length += opt_length_ext; | |||
| 948 | break; | |||
| 949 | case 0x0e: | |||
| 950 | opt_length_ext = coap_get_opt_uint(tvb, offset, 2); | |||
| 951 | opt_length_ext_off = offset; | |||
| 952 | opt_length_ext_len = 2; | |||
| 953 | offset += 2; | |||
| 954 | ||||
| 955 | opt_length = 269; | |||
| 956 | opt_length += opt_length_ext; | |||
| 957 | break; | |||
| 958 | case 0x0f: | |||
| 959 | expert_add_info_format(pinfo, coap_tree, &dissect_hf->ei.opt_length_bad, | |||
| 960 | "end-of-options marker found, but option delta isn't 15"); | |||
| 961 | *ok = false0; return offset; | |||
| 962 | default: | |||
| 963 | opt_length = (opt_jump & 0x0f); | |||
| 964 | break; | |||
| 965 | } | |||
| 966 | if ((unsigned)opt_length > offset_end - offset) { | |||
| 967 | expert_add_info_format(pinfo, coap_tree, &dissect_hf->ei.opt_length_bad, | |||
| 968 | "option longer than the package"); | |||
| 969 | *ok = false0; return offset; | |||
| 970 | } | |||
| 971 | ||||
| 972 | strbuf2 = wmem_strdup_printf(pinfo->pool, "#%u: %s", opt_count, val_to_str(pinfo->pool, *opt_num, vals_opt_type, | |||
| 973 | *opt_num % 14 == 0 ? "No-Op" : "Unknown Option (%d)")); | |||
| 974 | item = proto_tree_add_string(coap_tree, dissect_hf->hf.opt_name, | |||
| 975 | tvb, orig_offset, offset - orig_offset + opt_length, strbuf2); | |||
| 976 | subtree = proto_item_add_subtree(item, dissect_hf->ett.option); | |||
| 977 | ||||
| 978 | coap_opt_check(pinfo, subtree, *opt_num, opt_length, dissect_hf); | |||
| 979 | ||||
| 980 | strbuf2 = wmem_strdup_printf(pinfo->pool, "Type %u, %s, %s%s", *opt_num, | |||
| 981 | (*opt_num & 1) ? "Critical" : "Elective", | |||
| 982 | (*opt_num & 2) ? "Unsafe" : "Safe", | |||
| 983 | ((*opt_num & 0x1e) == 0x1c) ? ", NoCacheKey" : ""); | |||
| 984 | proto_tree_add_string(subtree, dissect_hf->hf.opt_desc, | |||
| 985 | tvb, orig_offset, offset - orig_offset + opt_length, strbuf2); | |||
| 986 | ||||
| 987 | proto_tree_add_item(subtree, dissect_hf->hf.opt_delta, tvb, orig_offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 988 | proto_tree_add_item(subtree, dissect_hf->hf.opt_length, tvb, orig_offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 989 | ||||
| 990 | if (opt_delta_ext_off && opt_delta_ext_len) | |||
| 991 | proto_tree_add_item(subtree, dissect_hf->hf.opt_delta_ext, tvb, opt_delta_ext_off, opt_delta_ext_len, ENC_BIG_ENDIAN0x00000000); | |||
| 992 | ||||
| 993 | if (opt_length_ext_off && opt_length_ext_len) | |||
| 994 | proto_tree_add_item(subtree, dissect_hf->hf.opt_length_ext, tvb, opt_length_ext_off, opt_length_ext_len, ENC_BIG_ENDIAN0x00000000); | |||
| 995 | ||||
| 996 | /* offset points the next to its option header */ | |||
| 997 | switch (*opt_num) { | |||
| 998 | case COAP_OPT_CONTENT_TYPE12: | |||
| 999 | dissect_coap_opt_ctype(tvb, pinfo, item, subtree, offset, | |||
| 1000 | opt_length, dissect_hf->hf.opt_ctype, coinfo); | |||
| 1001 | break; | |||
| 1002 | case COAP_OPT_MAX_AGE14: | |||
| 1003 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1004 | opt_length, dissect_hf->hf.opt_max_age); | |||
| 1005 | break; | |||
| 1006 | case COAP_OPT_PROXY_URI35: | |||
| 1007 | dissect_coap_opt_proxy_uri(tvb, pinfo, item, subtree, offset, | |||
| 1008 | opt_length, dissect_hf->hf.opt_proxy_uri); | |||
| 1009 | break; | |||
| 1010 | case COAP_OPT_PROXY_SCHEME39: | |||
| 1011 | dissect_coap_opt_proxy_scheme(tvb, pinfo, item, subtree, offset, | |||
| 1012 | opt_length, dissect_hf->hf.opt_proxy_scheme); | |||
| 1013 | break; | |||
| 1014 | case COAP_OPT_SIZE160: | |||
| 1015 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1016 | opt_length, dissect_hf->hf.opt_size1); | |||
| 1017 | break; | |||
| 1018 | case COAP_OPT_ETAG4: | |||
| 1019 | dissect_coap_opt_hex_string(tvb, pinfo, item, subtree, offset, | |||
| 1020 | opt_length, dissect_hf->hf.opt_etag); | |||
| 1021 | break; | |||
| 1022 | case COAP_OPT_URI_HOST3: | |||
| 1023 | dissect_coap_opt_uri_host(tvb, pinfo, item, subtree, offset, | |||
| 1024 | opt_length, coinfo, dissect_hf->hf.opt_uri_host); | |||
| 1025 | break; | |||
| 1026 | case COAP_OPT_LOCATION_PATH8: | |||
| 1027 | dissect_coap_opt_location_path(tvb, pinfo, item, subtree, offset, | |||
| 1028 | opt_length, dissect_hf->hf.opt_location_path); | |||
| 1029 | break; | |||
| 1030 | case COAP_OPT_URI_PORT7: | |||
| 1031 | dissect_coap_opt_uri_port(tvb, item, subtree, offset, | |||
| 1032 | opt_length, coinfo, dissect_hf->hf.opt_uri_port); | |||
| 1033 | break; | |||
| 1034 | case COAP_OPT_LOCATION_QUERY20: | |||
| 1035 | dissect_coap_opt_location_query(tvb, pinfo, item, subtree, offset, | |||
| 1036 | opt_length, dissect_hf->hf.opt_location_query); | |||
| 1037 | break; | |||
| 1038 | case COAP_OPT_OBJECT_SECURITY9: | |||
| 1039 | dissect_coap_opt_object_security(tvb, item, subtree, offset, | |||
| 1040 | opt_length, pinfo, coinfo, dissect_hf, code_class); | |||
| 1041 | break; | |||
| 1042 | case COAP_OPT_URI_PATH11: | |||
| 1043 | dissect_coap_opt_uri_path(tvb, pinfo, item, subtree, offset, | |||
| 1044 | opt_length, coinfo, dissect_hf->hf.opt_uri_path); | |||
| 1045 | break; | |||
| 1046 | case COAP_OPT_OBSERVE6: | |||
| 1047 | if (code_class == 0) { | |||
| 1048 | /* Request */ | |||
| 1049 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1050 | opt_length, dissect_hf->hf.opt_observe_req); | |||
| 1051 | } else { | |||
| 1052 | /* Response */ | |||
| 1053 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1054 | opt_length, dissect_hf->hf.opt_observe_rsp); | |||
| 1055 | } | |||
| 1056 | break; | |||
| 1057 | case COAP_OPT_HOP_LIMIT16: | |||
| 1058 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1059 | opt_length, dissect_hf->hf.opt_hop_limit); | |||
| 1060 | break; | |||
| 1061 | case COAP_OPT_ACCEPT17: | |||
| 1062 | dissect_coap_opt_accept(tvb, pinfo, item, subtree, offset, | |||
| 1063 | opt_length, dissect_hf->hf.opt_accept); | |||
| 1064 | break; | |||
| 1065 | case COAP_OPT_IF_MATCH1: | |||
| 1066 | dissect_coap_opt_hex_string(tvb, pinfo, item, subtree, offset, | |||
| 1067 | opt_length, dissect_hf->hf.opt_if_match); | |||
| 1068 | break; | |||
| 1069 | case COAP_OPT_URI_QUERY15: | |||
| 1070 | dissect_coap_opt_uri_query(tvb, pinfo, item, subtree, offset, | |||
| 1071 | opt_length, coinfo, dissect_hf->hf.opt_uri_query); | |||
| 1072 | break; | |||
| 1073 | case COAP_OPT_ECHO252: | |||
| 1074 | dissect_coap_opt_hex_string(tvb, pinfo, item, subtree, offset, | |||
| 1075 | opt_length, dissect_hf->hf.opt_echo); | |||
| 1076 | break; | |||
| 1077 | case COAP_OPT_REQUEST_TAG292: | |||
| 1078 | dissect_coap_opt_hex_string(tvb, pinfo, item, subtree, offset, | |||
| 1079 | opt_length, dissect_hf->hf.opt_request_tag); | |||
| 1080 | break; | |||
| 1081 | case COAP_OPT_NO_RESPONSE258: | |||
| 1082 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1083 | opt_length, dissect_hf->hf.opt_no_response); | |||
| 1084 | break; | |||
| 1085 | case COAP_OPT_BLOCK223: | |||
| 1086 | coinfo->block_option = 2; | |||
| 1087 | dissect_coap_opt_block(tvb, item, subtree, offset, | |||
| 1088 | opt_length, coinfo, dissect_hf); | |||
| 1089 | break; | |||
| 1090 | case COAP_OPT_BLOCK127: | |||
| 1091 | coinfo->block_option = 1; | |||
| 1092 | dissect_coap_opt_block(tvb, item, subtree, offset, | |||
| 1093 | opt_length, coinfo, dissect_hf); | |||
| 1094 | break; | |||
| 1095 | case COAP_OPT_QBLOCK231: | |||
| 1096 | coinfo->block_option = 2; | |||
| 1097 | dissect_coap_opt_block(tvb, item, subtree, offset, | |||
| 1098 | opt_length, coinfo, dissect_hf); | |||
| 1099 | break; | |||
| 1100 | case COAP_OPT_QBLOCK119: | |||
| 1101 | coinfo->block_option = 1; | |||
| 1102 | dissect_coap_opt_block(tvb, item, subtree, offset, | |||
| 1103 | opt_length, coinfo, dissect_hf); | |||
| 1104 | break; | |||
| 1105 | case COAP_OPT_IF_NONE_MATCH5: | |||
| 1106 | break; | |||
| 1107 | case COAP_OPT_EDHOC21: | |||
| 1108 | break; | |||
| 1109 | case COAP_OPT_SIZE228: | |||
| 1110 | dissect_coap_opt_uint(tvb, item, subtree, offset, | |||
| 1111 | opt_length, dissect_hf->hf.opt_block_size); | |||
| 1112 | break; | |||
| 1113 | case COAP_OPT_OCF_CONTENT2053: | |||
| 1114 | dissect_coap_opt_ocf_version(tvb, item, subtree, offset, | |||
| 1115 | opt_length, dissect_hf->hf.opt_ocf_version); | |||
| 1116 | break; | |||
| 1117 | case COAP_OPT_OCF_ACCEPT2049: | |||
| 1118 | dissect_coap_opt_ocf_version(tvb, item, subtree, offset, | |||
| 1119 | opt_length, dissect_hf->hf.opt_ocf_accept_version); | |||
| 1120 | break; | |||
| 1121 | default: | |||
| 1122 | dissect_coap_opt_hex_string(tvb, pinfo, item, subtree, offset, | |||
| 1123 | opt_length, dissect_hf->hf.opt_unknown); | |||
| 1124 | break; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | return offset + opt_length; | |||
| 1128 | } | |||
| 1129 | ||||
| 1130 | /* | |||
| 1131 | * options dissector. | |||
| 1132 | * return offset pointing the next of options. (i.e. the top of the payload | |||
| 1133 | * or the end of the data. | |||
| 1134 | */ | |||
| 1135 | unsigned | |||
| 1136 | dissect_coap_options(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, unsigned offset, unsigned offset_end, uint8_t code_class, coap_info *coinfo, coap_common_dissect_t *dissect_hf, bool_Bool *ok) | |||
| 1137 | { | |||
| 1138 | unsigned opt_num = 0; | |||
| 1139 | int i; | |||
| 1140 | uint8_t endmarker; | |||
| 1141 | bool_Bool sub_ok; | |||
| 1142 | ||||
| 1143 | if (ok
| |||
| 1144 | ||||
| 1145 | /* loop for dissecting options */ | |||
| 1146 | for (i = 1; offset < offset_end; i++) { | |||
| 1147 | offset = dissect_coap_options_main(tvb, pinfo, coap_tree, | |||
| 1148 | offset, i, &opt_num, offset_end, code_class, coinfo, dissect_hf, &sub_ok); | |||
| 1149 | if (!sub_ok) { | |||
| ||||
| 1150 | if (ok) *ok = false0; | |||
| 1151 | return offset; | |||
| 1152 | } | |||
| 1153 | if (offset >= offset_end) | |||
| 1154 | break; | |||
| 1155 | endmarker = tvb_get_uint8(tvb, offset); | |||
| 1156 | if (endmarker == 0xff) { | |||
| 1157 | proto_tree_add_item(coap_tree, dissect_hf->hf.opt_end_marker, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1158 | offset += 1; | |||
| 1159 | break; | |||
| 1160 | } | |||
| 1161 | } | |||
| 1162 | ||||
| 1163 | return offset; | |||
| 1164 | } | |||
| 1165 | ||||
| 1166 | /* | |||
| 1167 | * CoAP code dissector. | |||
| 1168 | * return code value and updates the offset | |||
| 1169 | * */ | |||
| 1170 | uint8_t | |||
| 1171 | dissect_coap_code(tvbuff_t *tvb, proto_tree *tree, unsigned *offset, coap_common_dissect_t *dissect_hf, uint8_t *code_class) | |||
| 1172 | { | |||
| 1173 | uint8_t code; | |||
| 1174 | ||||
| 1175 | proto_tree_add_item(tree, dissect_hf->hf.code, tvb, *offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1176 | code = tvb_get_uint8(tvb, *offset); | |||
| 1177 | *code_class = code >> 5; | |||
| 1178 | *offset += 1; | |||
| 1179 | ||||
| 1180 | return code; | |||
| 1181 | } | |||
| 1182 | ||||
| 1183 | void | |||
| 1184 | 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_Bool oscore) | |||
| 1185 | { | |||
| 1186 | proto_tree *payload_tree; | |||
| 1187 | proto_item *payload_item, *length_item; | |||
| 1188 | tvbuff_t *payload_tvb; | |||
| 1189 | unsigned payload_length = offset_end - offset; | |||
| 1190 | const char *coap_ctype_str_dis; | |||
| 1191 | media_content_info_t content_info = {0}; | |||
| 1192 | char str_payload[80]; | |||
| 1193 | int result = 0; | |||
| 1194 | ||||
| 1195 | /* coinfo->ctype_value == DEFAULT_COAP_CTYPE_VALUE: No Content-Format option present */ | |||
| 1196 | if (coinfo->ctype_value == DEFAULT_COAP_CTYPE_VALUE~0U) { | |||
| 1197 | /* | |||
| 1198 | * 5.5.2. Diagnostic Payload | |||
| 1199 | * | |||
| 1200 | * If no Content-Format option is given, the payload of responses | |||
| 1201 | * indicating a client or server error is a brief human-readable | |||
| 1202 | * diagnostic message, explaining the error situation. This diagnostic | |||
| 1203 | * message MUST be encoded using UTF-8 [RFC3629], more specifically | |||
| 1204 | * using Net-Unicode form [RFC5198]. | |||
| 1205 | */ | |||
| 1206 | if ((code_class >= 4) && (code_class <= 5)) { | |||
| 1207 | coinfo->ctype_str = "text/plain; charset=utf-8"; | |||
| 1208 | coap_ctype_str_dis = "text/plain"; | |||
| 1209 | } else { | |||
| 1210 | /* Assume no Content-Format is opaque octet stream */ | |||
| 1211 | coinfo->ctype_str = "application/octet-stream"; | |||
| 1212 | coap_ctype_str_dis = coinfo->ctype_str; | |||
| 1213 | } | |||
| 1214 | } | |||
| 1215 | /* coinfo->ctype_value == 0: Content-Format option present with length 0 */ | |||
| 1216 | else if (coinfo->ctype_value == 0) { | |||
| 1217 | /* coinfo->ctype_str is already set by option parsing routine */ | |||
| 1218 | coap_ctype_str_dis = "text/plain"; | |||
| 1219 | } else { | |||
| 1220 | coap_ctype_str_dis = coinfo->ctype_str; | |||
| 1221 | } | |||
| 1222 | ||||
| 1223 | snprintf(str_payload, sizeof(str_payload), | |||
| 1224 | "Payload Content-Format: %s%s, Length: %u", | |||
| 1225 | coinfo->ctype_str, coinfo->ctype_value == DEFAULT_COAP_CTYPE_VALUE~0U ? | |||
| 1226 | " (no Content-Format)" : "", payload_length); | |||
| 1227 | ||||
| 1228 | payload_item = proto_tree_add_string(coap_tree, dissect_hf->hf.payload, | |||
| 1229 | tvb, offset, payload_length, | |||
| 1230 | str_payload); | |||
| 1231 | payload_tree = proto_item_add_subtree(payload_item, dissect_hf->ett.payload); | |||
| 1232 | ||||
| 1233 | proto_tree_add_string(payload_tree, dissect_hf->hf.payload_desc, tvb, offset, 0, coinfo->ctype_str); | |||
| 1234 | length_item = proto_tree_add_uint(payload_tree, dissect_hf->hf.payload_length, tvb, offset, 0, payload_length); | |||
| 1235 | proto_item_set_generated(length_item); | |||
| 1236 | payload_tvb = tvb_new_subset_length(tvb, offset, payload_length); | |||
| 1237 | ||||
| 1238 | content_info.type = (code_class == 0) ? MEDIA_CONTAINER_HTTP_REQUEST : MEDIA_CONTAINER_HTTP_RESPONSE; | |||
| 1239 | content_info.media_str = wmem_strdup_printf(pinfo->pool, "%s%s", wmem_strbuf_get_str(coinfo->uri_host_strbuf), wmem_strbuf_get_str(coinfo->uri_path_strbuf)); | |||
| 1240 | ||||
| 1241 | /* | |||
| 1242 | * The Thread protocol uses application/octet-stream for its | |||
| 1243 | * messages, rather than having its own media type for those | |||
| 1244 | * messages, as, for example, the Internet Printing Protocol | |||
| 1245 | * does. | |||
| 1246 | * | |||
| 1247 | * Handle "application/octet-stream" specially if this is | |||
| 1248 | * being dissected by the "CoAP for Thread Management Framework" | |||
| 1249 | * dissector. | |||
| 1250 | */ | |||
| 1251 | if (coinfo->is_coap_for_tmf) { | |||
| 1252 | /* | |||
| 1253 | * Try the media type dissector table for CoAP-TMF first. | |||
| 1254 | */ | |||
| 1255 | result = dissector_try_string_with_data(coap_tmf_media_type_dissector_table, | |||
| 1256 | coap_ctype_str_dis, payload_tvb, pinfo, parent_tree, true1, | |||
| 1257 | &content_info); | |||
| 1258 | } | |||
| 1259 | if (result == 0) { | |||
| 1260 | /* | |||
| 1261 | * Try the CoAP URI-Path table. | |||
| 1262 | */ | |||
| 1263 | result = dissector_try_string_with_data(coap_uri_path_dissector_table, | |||
| 1264 | wmem_strbuf_get_str(coinfo->uri_path_strbuf), payload_tvb, pinfo, parent_tree, true1, | |||
| 1265 | &content_info); | |||
| 1266 | } | |||
| 1267 | if (result == 0) { | |||
| 1268 | /* | |||
| 1269 | * That either failed or we didn't try it. | |||
| 1270 | * Now try the regular media type table. | |||
| 1271 | */ | |||
| 1272 | dissector_try_string_with_data(media_type_dissector_table, | |||
| 1273 | coap_ctype_str_dis, payload_tvb, pinfo, parent_tree, true1, | |||
| 1274 | &content_info); | |||
| 1275 | } | |||
| 1276 | if (coinfo->object_security && !oscore) { | |||
| 1277 | proto_item_set_text(payload_item, "Encrypted OSCORE Data"); | |||
| 1278 | call_dissector_with_data(oscore_handle, payload_tvb, pinfo, parent_tree, coinfo->oscore_info); | |||
| 1279 | } | |||
| 1280 | } | |||
| 1281 | ||||
| 1282 | static uint32_t | |||
| 1283 | coap_frame_length(tvbuff_t *tvb, unsigned offset, int *size) | |||
| 1284 | { | |||
| 1285 | /* | |||
| 1286 | * Decode Len and Extended Length according to | |||
| 1287 | * https://tools.ietf.org/html/rfc8323#page-10 | |||
| 1288 | */ | |||
| 1289 | uint8_t len = tvb_get_uint8(tvb, offset) >> 4; | |||
| 1290 | switch (len) { | |||
| 1291 | default: | |||
| 1292 | *size = 1; | |||
| 1293 | return len; | |||
| 1294 | case 13: | |||
| 1295 | if (tvb_reported_length_remaining(tvb, offset) < 2) { | |||
| 1296 | *size = -1; | |||
| 1297 | return 0; | |||
| 1298 | } | |||
| 1299 | *size = 2; | |||
| 1300 | return tvb_get_uint8(tvb, offset + 1) + 13; | |||
| 1301 | case 14: | |||
| 1302 | if (tvb_reported_length_remaining(tvb, offset) < 3) { | |||
| 1303 | *size = -1; | |||
| 1304 | return 0; | |||
| 1305 | } | |||
| 1306 | *size = 3; | |||
| 1307 | return tvb_get_ntohs(tvb, offset + 1) + 269; | |||
| 1308 | case 15: | |||
| 1309 | if (tvb_reported_length_remaining(tvb, offset) < 5) { | |||
| 1310 | *size = -1; | |||
| 1311 | return 0; | |||
| 1312 | } | |||
| 1313 | *size = 5; | |||
| 1314 | return tvb_get_ntohl(tvb, offset + 1) + 65805; | |||
| 1315 | } | |||
| 1316 | } | |||
| 1317 | ||||
| 1318 | static int | |||
| 1319 | dissect_coap_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, coap_parent_protocol parent_protocol, bool_Bool is_coap_for_tmf) | |||
| 1320 | { | |||
| 1321 | unsigned offset = 0; | |||
| 1322 | proto_item *coap_root; | |||
| 1323 | proto_item *pi; | |||
| 1324 | proto_tree *coap_tree; | |||
| 1325 | int length_size = 0; | |||
| 1326 | uint8_t ttype = UINT8_MAX(255); | |||
| 1327 | uint32_t token_len; | |||
| 1328 | uint8_t code; | |||
| 1329 | uint8_t code_class; | |||
| 1330 | uint32_t mid = 0; | |||
| 1331 | unsigned coap_length; | |||
| 1332 | char *coap_token_str; | |||
| 1333 | coap_info *coinfo; | |||
| 1334 | conversation_t *conversation; | |||
| 1335 | coap_conv_info *ccinfo; | |||
| 1336 | coap_transaction *coap_trans = NULL((void*)0); | |||
| 1337 | char *coap_trans_key; | |||
| 1338 | coap_request_response *coap_req_rsp = NULL((void*)0); | |||
| 1339 | ||||
| 1340 | // TODO support TCP/WebSocket/TCP with more than one PDU per packet. | |||
| 1341 | // These probably require a unique coinfo for each. | |||
| 1342 | ||||
| 1343 | /* Allocate information for upper layers */ | |||
| 1344 | coinfo = (coap_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_coap, 0); | |||
| 1345 | ||||
| 1346 | if (coinfo == NULL((void*)0)) | |||
| ||||
| 1347 | { | |||
| 1348 | coinfo = wmem_new0(wmem_file_scope(), coap_info)((coap_info*)wmem_alloc0((wmem_file_scope()), sizeof(coap_info ))); | |||
| 1349 | p_add_proto_data(wmem_file_scope(), pinfo, proto_coap, 0, coinfo); | |||
| 1350 | } | |||
| 1351 | ||||
| 1352 | // coinfo->parent_protocol = parent_protocol; | |||
| 1353 | coinfo->is_coap_for_tmf = is_coap_for_tmf; | |||
| 1354 | /* check if trel is previously dissected */ | |||
| 1355 | if (coinfo->is_coap_for_tmf == 0) | |||
| 1356 | { | |||
| 1357 | unsigned id2 = proto_get_id_by_short_name("TREL"); | |||
| 1358 | wmem_list_frame_t* ptr2 = wmem_list_find(pinfo->layers, GUINT_TO_POINTER(id2)((gpointer) (gulong) (id2))); | |||
| 1359 | ||||
| 1360 | if ( ptr2 != NULL((void*)0)) | |||
| 1361 | coinfo->is_coap_for_tmf = 1; | |||
| 1362 | } | |||
| 1363 | ||||
| 1364 | /* initialize the CoAP length and the content-Format */ | |||
| 1365 | /* | |||
| 1366 | * The length of CoAP message is not specified in the CoAP header using | |||
| 1367 | * UDP or WebSockets. The lower layers provide it. For TCP/TLS, an | |||
| 1368 | * explicit length is present. | |||
| 1369 | */ | |||
| 1370 | coap_length = tvb_reported_length(tvb); | |||
| 1371 | if (parent_protocol == PARENT_TCP_TLS) { | |||
| 1372 | token_len = tvb_get_uint8(tvb, offset) & 0xf; | |||
| 1373 | coap_length = coap_frame_length(tvb, offset, &length_size); | |||
| 1374 | if (length_size < 0) { | |||
| 1375 | pinfo->desegment_offset = offset; | |||
| 1376 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 1377 | return tvb_reported_length(tvb); | |||
| 1378 | } | |||
| 1379 | /* | |||
| 1380 | * Length of the whole CoAP frame includes the (Extended) Length fields | |||
| 1381 | * (1 to 4 bytes), the Code (1 byte) and token length (normally 0 to 8 | |||
| 1382 | * bytes), plus everything afterwards. | |||
| 1383 | */ | |||
| 1384 | coap_length += 1 + token_len + length_size; | |||
| 1385 | if (coap_length > tvb_reported_length_remaining(tvb, offset)) { | |||
| 1386 | pinfo->desegment_offset = offset; | |||
| 1387 | pinfo->desegment_len = coap_length - tvb_reported_length_remaining(tvb, offset); | |||
| 1388 | return tvb_reported_length(tvb); | |||
| 1389 | } | |||
| 1390 | } | |||
| 1391 | coinfo->ctype_str = ""; | |||
| 1392 | coinfo->ctype_value = DEFAULT_COAP_CTYPE_VALUE~0U; | |||
| 1393 | ||||
| 1394 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "CoAP"); | |||
| 1395 | col_clear(pinfo->cinfo, COL_INFO); | |||
| 1396 | ||||
| 1397 | coap_root = proto_tree_add_item(parent_tree, proto_coap, tvb, offset, -1, ENC_NA0x00000000); | |||
| 1398 | coap_tree = proto_item_add_subtree(coap_root, ett_coap); | |||
| 1399 | ||||
| 1400 | if (parent_protocol == PARENT_OTHER) { | |||
| 1401 | proto_tree_add_item(coap_tree, hf_coap_version, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1402 | ||||
| 1403 | proto_tree_add_item_ret_uint8(coap_tree, hf_coap_ttype, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &ttype); | |||
| 1404 | ||||
| 1405 | proto_tree_add_item_ret_uint(coap_tree, hf_coap_token_len, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &token_len); | |||
| 1406 | offset += 1; | |||
| 1407 | ||||
| 1408 | code = dissect_coap_code(tvb, coap_tree, &offset, &dissect_coap_hf, &code_class); | |||
| 1409 | ||||
| 1410 | proto_tree_add_item_ret_uint(coap_tree, hf_coap_mid, tvb, offset, 2, ENC_BIG_ENDIAN0x00000000, &mid); | |||
| 1411 | offset += 2; | |||
| 1412 | ||||
| 1413 | col_add_fstr(pinfo->cinfo, COL_INFO, | |||
| 1414 | "%s, MID:%u, %s", | |||
| 1415 | val_to_str(pinfo->pool, ttype, vals_ttype_short, "Unknown %u"), | |||
| 1416 | mid, | |||
| 1417 | val_to_str_ext(pinfo->pool, code, &coap_vals_code_ext, "Unknown %u")); | |||
| 1418 | ||||
| 1419 | /* append the header information */ | |||
| 1420 | proto_item_append_text(coap_root, | |||
| 1421 | ", %s, %s, MID:%u", | |||
| 1422 | val_to_str(pinfo->pool, ttype, vals_ttype, "Unknown %u"), | |||
| 1423 | val_to_str_ext(pinfo->pool, code, &coap_vals_code_ext, "Unknown %u"), | |||
| 1424 | mid); | |||
| 1425 | } else { | |||
| 1426 | unsigned len = coap_length; | |||
| 1427 | if (parent_protocol == PARENT_WEBSOCKETS) { | |||
| 1428 | len = tvb_get_uint8(tvb, offset) >> 4; | |||
| 1429 | length_size = 1; | |||
| 1430 | } | |||
| 1431 | proto_tree_add_uint(coap_tree, hf_coap_length, tvb, offset, length_size, len); | |||
| 1432 | ||||
| 1433 | proto_tree_add_item_ret_uint(coap_tree, hf_coap_token_len, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &token_len); | |||
| 1434 | offset += length_size; | |||
| 1435 | ||||
| 1436 | code = dissect_coap_code(tvb, coap_tree, &offset, &dissect_coap_hf, &code_class); | |||
| 1437 | ||||
| 1438 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1439 | val_to_str_ext(pinfo->pool, code, &coap_vals_code_ext, "Unknown %u")); | |||
| 1440 | ||||
| 1441 | /* append the header information */ | |||
| 1442 | proto_item_append_text(coap_root, | |||
| 1443 | ", %s", | |||
| 1444 | val_to_str_ext(pinfo->pool, code, &coap_vals_code_ext, "Unknown %u")); | |||
| 1445 | } | |||
| 1446 | ||||
| 1447 | /* initialize the external value */ | |||
| 1448 | coinfo->block_option = 0; | |||
| 1449 | coinfo->block_number = DEFAULT_COAP_BLOCK_NUMBER~0U; | |||
| 1450 | coinfo->block_mflag = 0; | |||
| 1451 | coinfo->uri_host_strbuf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, ""); | |||
| 1452 | coinfo->uri_path_strbuf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, ""); | |||
| 1453 | coinfo->uri_query_strbuf = wmem_strbuf_create(pinfo->pool)wmem_strbuf_new(pinfo->pool, ""); | |||
| 1454 | /* Allocate pointers and static elements of oscore_info_t, arrays are allocated only if object security option is found during option parsing */ | |||
| 1455 | coinfo->oscore_info = wmem_new0(pinfo->pool, oscore_info_t)((oscore_info_t*)wmem_alloc0((pinfo->pool), sizeof(oscore_info_t ))); | |||
| 1456 | coinfo->object_security = false0; | |||
| 1457 | coap_token_str = NULL((void*)0); | |||
| 1458 | ||||
| 1459 | if (token_len > 0) { | |||
| 1460 | /* This has to be file scope as the token string is stored in the map | |||
| 1461 | * for conversation lookup */ | |||
| 1462 | coap_token_str = tvb_bytes_to_str_punct(wmem_file_scope(), tvb, offset, token_len, ' '); | |||
| 1463 | proto_tree_add_item(coap_tree, hf_coap_token, | |||
| 1464 | tvb, offset, token_len, ENC_NA0x00000000); | |||
| 1465 | offset += token_len; | |||
| 1466 | ||||
| 1467 | /* Use the token for transaction key */ | |||
| 1468 | coap_trans_key = coap_token_str; | |||
| 1469 | } else { | |||
| 1470 | /* Use the message id for transaction key */ | |||
| 1471 | coap_trans_key = wmem_strdup_printf(wmem_file_scope(), "%u", mid); | |||
| 1472 | } | |||
| 1473 | ||||
| 1474 | /* process options */ | |||
| 1475 | { bool_Bool opts_ok; | |||
| 1476 | offset = dissect_coap_options(tvb, pinfo, coap_tree, offset, coap_length, code_class, coinfo, &dissect_coap_hf, &opts_ok); | |||
| 1477 | if (!opts_ok) | |||
| 1478 | return tvb_captured_length(tvb); | |||
| 1479 | } | |||
| 1480 | ||||
| 1481 | /* Use conversations to track state for request/response */ | |||
| 1482 | conversation = find_or_create_conversation_noaddrb(pinfo, (code_class == 0)); | |||
| 1483 | ||||
| 1484 | /* Retrieve or create state structure for this conversation */ | |||
| 1485 | ccinfo = (coap_conv_info *)conversation_get_proto_data(conversation, proto_coap); | |||
| 1486 | if (!ccinfo) { | |||
| 1487 | /* No state structure - create it */ | |||
| 1488 | ccinfo = wmem_new(wmem_file_scope(), coap_conv_info)((coap_conv_info*)wmem_alloc((wmem_file_scope()), sizeof(coap_conv_info ))); | |||
| 1489 | ccinfo->messages = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); | |||
| 1490 | conversation_add_proto_data(conversation, proto_coap, ccinfo); | |||
| 1491 | } | |||
| 1492 | ||||
| 1493 | /* Process request/response in conversation */ | |||
| 1494 | if (code != 0) { /* Ignore empty messages */ | |||
| 1495 | /* Try and look up a matching token. If it's the first | |||
| 1496 | * sight of a request, there shouldn't be one */ | |||
| 1497 | coap_trans = (coap_transaction *)wmem_map_lookup(ccinfo->messages, coap_trans_key); | |||
| 1498 | if (!coap_trans) { | |||
| 1499 | if ((!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) && (code_class == 0)) { | |||
| 1500 | /* New request - log it */ | |||
| 1501 | coap_trans = wmem_new0(wmem_file_scope(), coap_transaction)((coap_transaction*)wmem_alloc0((wmem_file_scope()), sizeof(coap_transaction ))); | |||
| 1502 | coap_trans->req_rsp = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); | |||
| 1503 | if (coinfo->uri_host_strbuf) { | |||
| 1504 | /* Store the URI-Host into CoAP transaction info */ | |||
| 1505 | coap_trans->uri_host_strbuf = wmem_strbuf_new(wmem_file_scope(), wmem_strbuf_get_str(coinfo->uri_host_strbuf)); | |||
| 1506 | } | |||
| 1507 | if (coinfo->uri_path_strbuf) { | |||
| 1508 | /* Store the URI-Path into CoAP transaction info */ | |||
| 1509 | coap_trans->uri_path_strbuf = wmem_strbuf_new(wmem_file_scope(), wmem_strbuf_get_str(coinfo->uri_path_strbuf)); | |||
| 1510 | } | |||
| 1511 | if (coinfo->oscore_info) { | |||
| 1512 | coap_trans->oscore_info = (oscore_info_t *) wmem_memdup(wmem_file_scope(), coinfo->oscore_info, sizeof(oscore_info_t)); | |||
| 1513 | if (coinfo->oscore_info->kid) { | |||
| 1514 | coap_trans->oscore_info->kid = (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo->oscore_info->kid, coinfo->oscore_info->kid_len); | |||
| 1515 | } | |||
| 1516 | if (coinfo->oscore_info->kid_context) { | |||
| 1517 | coap_trans->oscore_info->kid_context = (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo->oscore_info->kid_context, coinfo->oscore_info->kid_context_len); | |||
| 1518 | } | |||
| 1519 | if (coinfo->oscore_info->piv) { | |||
| 1520 | coap_trans->oscore_info->request_piv = (uint8_t *) wmem_memdup(wmem_file_scope(), coinfo->oscore_info->request_piv, coinfo->oscore_info->request_piv_len); | |||
| 1521 | } | |||
| 1522 | } | |||
| 1523 | wmem_map_insert(ccinfo->messages, coap_trans_key, (void *)coap_trans); | |||
| 1524 | } | |||
| 1525 | } else { | |||
| 1526 | if ((code_class >= 2) && (code_class <= 5)) { | |||
| 1527 | if (coap_trans->uri_host_strbuf) { | |||
| 1528 | /* Copy the URI-Host stored in matching transaction info into CoAP packet info */ | |||
| 1529 | coinfo->uri_host_strbuf = wmem_strbuf_new(pinfo->pool, wmem_strbuf_get_str(coap_trans->uri_host_strbuf)); | |||
| 1530 | } | |||
| 1531 | if (coap_trans->uri_path_strbuf) { | |||
| 1532 | /* Copy the URI-Path stored in matching transaction info into CoAP packet info */ | |||
| 1533 | coinfo->uri_path_strbuf = wmem_strbuf_new(pinfo->pool, wmem_strbuf_get_str(coap_trans->uri_path_strbuf)); | |||
| 1534 | } | |||
| 1535 | if (coap_trans->oscore_info) { | |||
| 1536 | /* Copy OSCORE info in matching transaction info into CoAP packet info */ | |||
| 1537 | if (coap_trans->oscore_info->kid) { | |||
| 1538 | coinfo->oscore_info->kid = (uint8_t *) wmem_memdup(pinfo->pool, coap_trans->oscore_info->kid, coap_trans->oscore_info->kid_len); | |||
| 1539 | } | |||
| 1540 | coinfo->oscore_info->kid_len = coap_trans->oscore_info->kid_len; | |||
| 1541 | if (coap_trans->oscore_info->kid_context) { | |||
| 1542 | coinfo->oscore_info->kid_context = (uint8_t *) wmem_memdup(pinfo->pool, coap_trans->oscore_info->kid_context, coap_trans->oscore_info->kid_context_len); | |||
| 1543 | } | |||
| 1544 | coinfo->oscore_info->kid_context_len = coap_trans->oscore_info->kid_context_len; | |||
| 1545 | if (coap_trans->oscore_info->request_piv) { | |||
| 1546 | coinfo->oscore_info->request_piv = (uint8_t *) wmem_memdup(pinfo->pool, coap_trans->oscore_info->request_piv, coap_trans->oscore_info->request_piv_len); | |||
| 1547 | } | |||
| 1548 | coinfo->oscore_info->request_piv_len = coap_trans->oscore_info->request_piv_len; | |||
| 1549 | coinfo->oscore_info->response = true1; | |||
| 1550 | } | |||
| 1551 | } | |||
| 1552 | } | |||
| 1553 | if (coap_trans) { | |||
| 1554 | coap_req_rsp = (coap_request_response *)wmem_map_lookup(coap_trans->req_rsp, GINT_TO_POINTER(mid)((gpointer) (glong) (mid))); | |||
| 1555 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1556 | if (!coap_req_rsp) { | |||
| 1557 | coap_req_rsp = wmem_new0(wmem_file_scope(), coap_request_response)((coap_request_response*)wmem_alloc0((wmem_file_scope()), sizeof (coap_request_response))); | |||
| 1558 | wmem_map_insert(coap_trans->req_rsp, GINT_TO_POINTER(mid)((gpointer) (glong) (mid)), (void *)coap_req_rsp); | |||
| 1559 | } | |||
| 1560 | if (code_class == 0) { | |||
| 1561 | /* This is a request */ | |||
| 1562 | if (coap_req_rsp->req_frame == 0) { | |||
| 1563 | /* Log the first request frame */ | |||
| 1564 | coap_req_rsp->req_frame = pinfo->num; | |||
| 1565 | coap_req_rsp->req_time = pinfo->abs_ts; | |||
| 1566 | } | |||
| 1567 | } else if ((code_class >= 2) && (code_class <= 5)) { | |||
| 1568 | /* This is a reply */ | |||
| 1569 | if (coap_req_rsp->rsp_frame == 0) { | |||
| 1570 | /* Log the first matching response frame */ | |||
| 1571 | coap_req_rsp->rsp_frame = pinfo->num; | |||
| 1572 | } | |||
| 1573 | } | |||
| 1574 | } | |||
| 1575 | } | |||
| 1576 | } | |||
| 1577 | ||||
| 1578 | /* dissect the payload after info column updates below */ | |||
| 1579 | tvbuff_t *payload_tvb = NULL((void*)0); | |||
| 1580 | if (coap_length > offset) { | |||
| 1581 | if (coinfo->block_number == DEFAULT_COAP_BLOCK_NUMBER~0U) { | |||
| 1582 | payload_tvb = tvb_new_subset_remaining(tvb, offset); | |||
| 1583 | } else { | |||
| 1584 | proto_tree_add_bytes_format(coap_tree, hf_block_payload, tvb, offset, | |||
| 1585 | coap_length - offset, NULL((void*)0), "Block Payload"); | |||
| 1586 | pi = proto_tree_add_uint(coap_tree, hf_block_length, tvb, offset, 0, coap_length - offset); | |||
| 1587 | proto_item_set_generated(pi); | |||
| 1588 | ||||
| 1589 | fragment_head *frag_msg = fragment_add_seq_check(&coap_block_reassembly_table, tvb, offset, | |||
| 1590 | pinfo, 0, NULL((void*)0), coinfo->block_number, | |||
| 1591 | coap_length - offset, coinfo->block_mflag); | |||
| 1592 | payload_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CoAP blocks", | |||
| 1593 | frag_msg, &coap_block_frag_items, NULL((void*)0), coap_tree); | |||
| 1594 | } | |||
| 1595 | } | |||
| 1596 | ||||
| 1597 | /* add informations to the packet list */ | |||
| 1598 | if (coap_token_str != NULL((void*)0)) | |||
| 1599 | col_append_fstr(pinfo->cinfo, COL_INFO, ", TKN:%s", coap_token_str); | |||
| 1600 | if (coinfo->block_number != DEFAULT_COAP_BLOCK_NUMBER~0U) { | |||
| 1601 | /* The M bit is used in Block1 Option in a request and in Block2 Option in a response */ | |||
| 1602 | bool_Bool mflag_is_used = (((coinfo->block_option == 1) && (code_class == 0)) || | |||
| 1603 | ((coinfo->block_option == 2) && (code_class >= 2) && (code_class <= 5))); | |||
| 1604 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %sBlock #%u", | |||
| 1605 | (coinfo->block_mflag || !mflag_is_used) ? "" : "End of ", coinfo->block_number); | |||
| 1606 | } | |||
| 1607 | if (wmem_strbuf_get_len(coinfo->uri_host_strbuf) > 0 || wmem_strbuf_get_len(coinfo->uri_path_strbuf) > 0) { | |||
| 1608 | char *uri_host_path = wmem_strdup_printf(pinfo->pool, "%s%s", wmem_strbuf_get_str(coinfo->uri_host_strbuf), wmem_strbuf_get_str(coinfo->uri_path_strbuf)); | |||
| 1609 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", format_text(pinfo->pool, uri_host_path, strlen(uri_host_path))); | |||
| 1610 | /* Add a generated protocol item as well */ | |||
| 1611 | pi = proto_tree_add_string(coap_tree, dissect_coap_hf.hf.opt_uri_path_recon, tvb, 0, 0, uri_host_path); | |||
| 1612 | proto_item_set_generated(pi); | |||
| 1613 | } | |||
| 1614 | if (wmem_strbuf_get_len(coinfo->uri_query_strbuf) > 0) | |||
| 1615 | 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))); | |||
| 1616 | ||||
| 1617 | if (coap_req_rsp != NULL((void*)0)) { | |||
| 1618 | /* Print state tracking in the tree */ | |||
| 1619 | if (code_class == 0) { | |||
| 1620 | /* This is a request */ | |||
| 1621 | if (coap_req_rsp->rsp_frame) { | |||
| 1622 | pi = proto_tree_add_uint(coap_tree, hf_coap_response_in, | |||
| 1623 | tvb, 0, 0, coap_req_rsp->rsp_frame); | |||
| 1624 | proto_item_set_generated(pi); | |||
| 1625 | } | |||
| 1626 | if ((ttype == TT_CON0 || ttype == TT_NON1) && (coap_req_rsp->req_frame != pinfo->num)) { | |||
| 1627 | col_append_str(pinfo->cinfo, COL_INFO, " [Retransmission]"); | |||
| 1628 | pi = proto_tree_add_uint(coap_tree, hf_coap_request_resend_in, | |||
| 1629 | tvb, 0, 0, coap_req_rsp->req_frame); | |||
| 1630 | proto_item_set_generated(pi); | |||
| 1631 | expert_add_info(pinfo, pi, &ei_retransmitted); | |||
| 1632 | } | |||
| 1633 | } else if ((code_class >= 2) && (code_class <= 5)) { | |||
| 1634 | /* This is a reply */ | |||
| 1635 | if (coap_req_rsp->req_frame) { | |||
| 1636 | nstime_t ns; | |||
| 1637 | ||||
| 1638 | pi = proto_tree_add_uint(coap_tree, hf_coap_response_to, | |||
| 1639 | tvb, 0, 0, coap_req_rsp->req_frame); | |||
| 1640 | proto_item_set_generated(pi); | |||
| 1641 | ||||
| 1642 | nstime_delta(&ns, &pinfo->abs_ts, &coap_req_rsp->req_time); | |||
| 1643 | pi = proto_tree_add_time(coap_tree, hf_coap_response_time, tvb, 0, 0, &ns); | |||
| 1644 | proto_item_set_generated(pi); | |||
| 1645 | } | |||
| 1646 | if ((ttype == TT_CON0 || ttype == TT_NON1) && (coap_req_rsp->rsp_frame != pinfo->num)) { | |||
| 1647 | col_append_str(pinfo->cinfo, COL_INFO, " [Retransmission]"); | |||
| 1648 | pi = proto_tree_add_uint(coap_tree, hf_coap_response_resend_in, | |||
| 1649 | tvb, 0, 0, coap_req_rsp->rsp_frame); | |||
| 1650 | proto_item_set_generated(pi); | |||
| 1651 | expert_add_info(pinfo, pi, &ei_retransmitted); | |||
| 1652 | } | |||
| 1653 | } | |||
| 1654 | } | |||
| 1655 | ||||
| 1656 | if (coap_trans != NULL((void*)0)) { | |||
| 1657 | if ((code_class >= 2) && (code_class <= 5)) { | |||
| 1658 | /* This is a reply */ | |||
| 1659 | if (coinfo->object_security && coap_trans->oscore_info) { | |||
| 1660 | pi = proto_tree_add_bytes(coap_tree, hf_coap_oscore_kid, tvb, 0, coap_trans->oscore_info->kid_len, coap_trans->oscore_info->kid); | |||
| 1661 | proto_item_set_generated(pi); | |||
| 1662 | ||||
| 1663 | 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); | |||
| 1664 | proto_item_set_generated(pi); | |||
| 1665 | ||||
| 1666 | if (coinfo->oscore_info->piv_len) { | |||
| 1667 | pi = proto_tree_add_bytes(coap_tree, hf_coap_oscore_piv, tvb, 0, coinfo->oscore_info->piv_len, coinfo->oscore_info->piv); | |||
| 1668 | } else { | |||
| 1669 | pi = proto_tree_add_bytes(coap_tree, hf_coap_oscore_piv, tvb, 0, coinfo->oscore_info->request_piv_len, coinfo->oscore_info->request_piv); | |||
| 1670 | } | |||
| 1671 | proto_item_set_generated(pi); | |||
| 1672 | } | |||
| 1673 | } | |||
| 1674 | } | |||
| 1675 | ||||
| 1676 | if (payload_tvb) { | |||
| 1677 | dissect_coap_payload(payload_tvb, pinfo, coap_tree, parent_tree, 0, tvb_reported_length(payload_tvb), | |||
| 1678 | code_class, coinfo, &dissect_coap_hf, false0); | |||
| 1679 | } | |||
| 1680 | ||||
| 1681 | return coap_length; | |||
| 1682 | } | |||
| 1683 | ||||
| 1684 | static int | |||
| 1685 | dissect_coap_tcp_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) | |||
| 1686 | { | |||
| 1687 | return dissect_coap_message(tvb, pinfo, tree, PARENT_TCP_TLS, false0); | |||
| 1688 | } | |||
| 1689 | ||||
| 1690 | static int | |||
| 1691 | dissect_coap_websockets(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) | |||
| 1692 | { | |||
| 1693 | return dissect_coap_message(tvb, pinfo, tree, PARENT_WEBSOCKETS, false0); | |||
| 1694 | } | |||
| 1695 | ||||
| 1696 | static int | |||
| 1697 | dissect_coap_other(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) | |||
| 1698 | { | |||
| 1699 | return dissect_coap_message(tvb, pinfo, tree, PARENT_OTHER, false0); | |||
| 1700 | } | |||
| 1701 | ||||
| 1702 | static int | |||
| 1703 | dissect_coap_for_tmf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) | |||
| 1704 | { | |||
| 1705 | return dissect_coap_message(tvb, pinfo, tree, PARENT_OTHER, true1); | |||
| 1706 | } | |||
| 1707 | ||||
| 1708 | /* | |||
| 1709 | * Protocol initialization | |||
| 1710 | */ | |||
| 1711 | void | |||
| 1712 | proto_register_coap(void) | |||
| 1713 | { | |||
| 1714 | static hf_register_info hf[] = { | |||
| 1715 | { &hf_coap_length, | |||
| 1716 | { "Length", "coap.length", | |||
| 1717 | FT_UINT32, BASE_DEC, NULL((void*)0), 0, | |||
| 1718 | "Length of the CoAP frame, combining Len and Extended Length (if any) fields", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1719 | }, | |||
| 1720 | { &hf_coap_version, | |||
| 1721 | { "Version", "coap.version", | |||
| 1722 | FT_UINT8, BASE_DEC, NULL((void*)0), COAP_VERSION_MASK0xC0, | |||
| 1723 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1724 | }, | |||
| 1725 | { &hf_coap_ttype, | |||
| 1726 | { "Type", "coap.type", | |||
| 1727 | FT_UINT8, BASE_DEC, VALS(vals_ttype)((0 ? (const struct _value_string*)0 : ((vals_ttype)))), COAP_TYPE_MASK0x30, | |||
| 1728 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1729 | }, | |||
| 1730 | { &hf_coap_token_len, | |||
| 1731 | { "Token Length", "coap.token_len", | |||
| 1732 | FT_UINT8, BASE_DEC, NULL((void*)0), COAP_TOKEN_LEN_MASK0x0F, | |||
| 1733 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1734 | }, | |||
| 1735 | { &hf_coap_token, | |||
| 1736 | { "Token", "coap.token", | |||
| 1737 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1738 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1739 | }, | |||
| 1740 | { &hf_coap_mid, | |||
| 1741 | { "Message ID", "coap.mid", | |||
| 1742 | FT_UINT16, BASE_DEC, NULL((void*)0), 0x0, | |||
| 1743 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1744 | }, | |||
| 1745 | { &hf_coap_response_in, | |||
| 1746 | { "Response In", "coap.response_in", | |||
| 1747 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE)((gpointer) (glong) (FT_FRAMENUM_RESPONSE)), 0x0, | |||
| 1748 | "The response to this CoAP request is in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1749 | }, | |||
| 1750 | { &hf_coap_response_to, | |||
| 1751 | { "Request In", "coap.response_to", | |||
| 1752 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST)((gpointer) (glong) (FT_FRAMENUM_REQUEST)), 0x0, | |||
| 1753 | "This is a response to the CoAP request in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1754 | }, | |||
| 1755 | { &hf_coap_response_time, | |||
| 1756 | { "Response Time", "coap.response_time", | |||
| 1757 | FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1758 | "The time between the Call and the Reply", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1759 | }, | |||
| 1760 | { &hf_coap_request_resend_in, | |||
| 1761 | { "Retransmission of request in", "coap.request_first_in", | |||
| 1762 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1763 | "This request was first sent in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1764 | }, | |||
| 1765 | { &hf_coap_response_resend_in, | |||
| 1766 | { "Retransmission of response in", "coap.response_first_in", | |||
| 1767 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1768 | "This response was first sent in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1769 | }, | |||
| 1770 | { &hf_coap_oscore_kid, | |||
| 1771 | { "OSCORE Key ID", "coap.oscore_kid", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1772 | "Matched OSCORE Key ID", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1773 | }, | |||
| 1774 | { &hf_coap_oscore_kid_context, | |||
| 1775 | { "OSCORE Key ID Context", "coap.oscore_kid_context", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1776 | "Matched OSCORE Key ID Context", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1777 | }, | |||
| 1778 | { &hf_coap_oscore_piv, | |||
| 1779 | { "OSCORE Partial IV", "coap.oscore_piv", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1780 | "Matched OSCORE Partial IV", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1781 | }, | |||
| 1782 | { &hf_block_payload, | |||
| 1783 | { "Block Payload", "coap.block_payload", | |||
| 1784 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, | |||
| 1785 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1786 | }, | |||
| 1787 | { &hf_block_length, | |||
| 1788 | { "Block Length", "coap.block_length", | |||
| 1789 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, | |||
| 1790 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1791 | }, | |||
| 1792 | { &hf_blocks, | |||
| 1793 | { "Blocks", "coap.blocks", | |||
| 1794 | FT_NONE, BASE_NONE, NULL((void*)0), 0x00, | |||
| 1795 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1796 | }, | |||
| 1797 | { &hf_block, | |||
| 1798 | { "Block", "coap.block", | |||
| 1799 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, | |||
| 1800 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1801 | }, | |||
| 1802 | { &hf_block_overlap, | |||
| 1803 | { "Block overlap", "coap.block.overlap", | |||
| 1804 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1805 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1806 | }, | |||
| 1807 | { &hf_block_overlap_conflicts, | |||
| 1808 | { "Block overlapping with conflicting data", "coap.block.overlap.conflicts", | |||
| 1809 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1810 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1811 | }, | |||
| 1812 | { &hf_block_multiple_tails, | |||
| 1813 | { "Block has multiple tails", "coap.block.multiple_tails", | |||
| 1814 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1815 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1816 | }, | |||
| 1817 | { &hf_block_too_long, | |||
| 1818 | { "Block too long", "coap.block.too_long", | |||
| 1819 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 1820 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1821 | }, | |||
| 1822 | { &hf_block_error, | |||
| 1823 | { "Block defragmentation error", "coap.block.error", | |||
| 1824 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, | |||
| 1825 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1826 | }, | |||
| 1827 | { &hf_block_count, | |||
| 1828 | { "Block count", "coap.block.count", | |||
| 1829 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, | |||
| 1830 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1831 | }, | |||
| 1832 | { &hf_block_reassembled_in, | |||
| 1833 | { "Reassembled in", "coap.block.reassembled.in", | |||
| 1834 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x00, | |||
| 1835 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1836 | }, | |||
| 1837 | { &hf_block_reassembled_length, | |||
| 1838 | { "Reassembled block length", "coap.block.reassembled.length", | |||
| 1839 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x00, | |||
| 1840 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 1841 | }, | |||
| 1842 | COAP_COMMON_HF_LIST(dissect_coap_hf, "coap"){ & dissect_coap_hf .hf.code, { "Code", "coap" ".code", FT_UINT8 , BASE_DEC | 0x00000200, &coap_vals_code_ext, 0x0, ((void *)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.payload, { "Payload", "coap" ".payload", FT_STRING, BASE_NONE , ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ( (void*)0) } }, { & dissect_coap_hf .hf.payload_desc, { "Payload Desc" , "coap" ".payload_desc", FT_STRING, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.payload_length, { "Payload Length", "coap" ".payload_length", FT_UINT32, BASE_DEC, ((void*)0), 0x0, ((void *)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_name, { "Opt Name", "coap" ".opt.name", FT_STRING, BASE_NONE , ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ( (void*)0) } }, { & dissect_coap_hf .hf.opt_desc, { "Opt Desc" , "coap" ".opt.desc", FT_STRING, BASE_NONE, ((void*)0), 0x0, ( (void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_delta, { "Opt Delta", "coap" ".opt.delta" , FT_UINT8, BASE_DEC, ((void*)0), 0xf0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_delta_ext , { "Opt Delta extended", "coap" ".opt.delta_ext", FT_UINT16, BASE_DEC, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_length, { "Opt Length", "coap" ".opt.length", FT_UINT8, BASE_DEC, (( void*)0), 0x0f, "Option Length", -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_length_ext, { "Opt Length extended", "coap" ".opt.length_ext", FT_UINT16, BASE_DEC , ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ( (void*)0) } }, { & dissect_coap_hf .hf.opt_end_marker, { "End of options marker" , "coap" ".opt.end_marker", FT_UINT8, BASE_DEC, ((void*)0), 0x00 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_ctype, { "Content-type", "coap" ".opt.ctype" , FT_STRING, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_max_age , { "Max-age", "coap" ".opt.max_age", FT_UINT32, BASE_DEC, (( void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0) } }, { & dissect_coap_hf .hf.opt_proxy_uri, { "Proxy-Uri" , "coap" ".opt.proxy_uri", FT_STRING, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_proxy_scheme, { "Proxy-Scheme", "coap" ".opt.proxy_scheme", FT_STRING, BASE_NONE, ((void*)0), 0x0, ( (void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_size1, { "Size1", "coap" ".opt.size1" , FT_UINT32, BASE_DEC, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_etag, { "Etag", "coap" ".opt.etag", FT_BYTES, BASE_NONE, ((void*)0), 0x0, "Option Etag", -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_uri_host, { "Uri-Host", "coap" ".opt.uri_host", FT_STRING, BASE_NONE, ((void*)0), 0x0, ((void *)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_location_path, { "Location-Path", "coap" ".opt.location_path" , FT_STRING, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_uri_port , { "Uri-Port", "coap" ".opt.uri_port", FT_UINT16, BASE_DEC, ( (void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0) } }, { & dissect_coap_hf .hf.opt_location_query, { "Location-Query" , "coap" ".opt.location_query", FT_STRING, BASE_NONE, ((void* )0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_reserved , { "Reserved", "coap" ".opt.object_security_reserved", FT_BOOLEAN , 8, ((void*)0), 0xE0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, - 1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_kid_context_present , { "Key ID Context Present", "coap" ".opt.object_security_kid_context_present" , FT_BOOLEAN, 8, ((void*)0), 0x10, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_kid_present , { "Key ID Present", "coap" ".opt.object_security_kid_present" , FT_BOOLEAN, 8, ((void*)0), 0x08, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_piv_len , { "Partial IV Length", "coap" ".opt.object_security_piv_len" , FT_UINT8, BASE_DEC, ((void*)0), 0x07, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_piv , { "Partial IV", "coap" ".opt.object_security_piv", FT_BYTES , BASE_NONE, ((void*)0), 0x00, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_kid_context_len , { "Key ID Context Length", "coap" ".opt.object_security_kid_context_len" , FT_UINT8, BASE_DEC, ((void*)0), 0x00, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_kid_context , { "Key ID Context", "coap" ".opt.object_security_kid_context" , FT_BYTES, BASE_NONE, ((void*)0), 0x00, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_object_security_kid , { "Key ID", "coap" ".opt.object_security_kid", FT_BYTES, BASE_NONE , ((void*)0), 0x00, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ( (void*)0) } }, { & dissect_coap_hf .hf.opt_uri_path, { "Uri-Path" , "coap" ".opt.uri_path", FT_STRING, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_uri_path_recon, { "Uri-Path", "coap" ".opt.uri_path_recon", FT_STRING, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_observe_req, { "Observe", "coap" ".opt.observe" , FT_UINT32, BASE_DEC, ((0 ? (const struct _value_string*)0 : ((coap_vals_observe_options)))), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_observe_rsp , { "Observe sequence number", "coap" ".opt.observe", FT_UINT32 , BASE_DEC, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_hop_limit , { "Hop Limit", "coap" ".opt.hop_limit", FT_UINT8, BASE_DEC, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, (( void*)0) } }, { & dissect_coap_hf .hf.opt_accept, { "Accept" , "coap" ".opt.accept", FT_STRING, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_if_match, { "If-Match", "coap" ".opt.if_match" , FT_BYTES, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_block_number , { "Block Number", "coap" ".opt.block_number", FT_UINT32, BASE_DEC , ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ( (void*)0) } }, { & dissect_coap_hf .hf.opt_block_mflag, { "More Flag", "coap" ".opt.block_mflag", FT_UINT8, BASE_DEC, ( (void*)0), 0x08, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0) } }, { & dissect_coap_hf .hf.opt_block_size, { "Encoded Block Size" , "coap" ".opt.block_size", FT_UINT8, BASE_DEC, ((void*)0), 0x07 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_uri_query, { "Uri-Query", "coap" ".opt.uri_query" , FT_STRING, BASE_NONE, ((void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_echo, { "Echo", "coap" ".opt.opt_echo", FT_BYTES, BASE_NONE, ((void* )0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_no_response, { "No-Response" , "coap" ".opt.opt_no_response", FT_UINT8, BASE_DEC, ((void*) 0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_request_tag, { "Request-Tag" , "coap" ".opt.opt_request_tag", FT_BYTES, BASE_NONE, ((void* )0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_ocf_version, { "OCF-Content-Format-Version" , "coap" ".opt.opt_ocf_version", FT_UINT8, BASE_DEC, ((void*) 0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, { & dissect_coap_hf .hf.opt_ocf_accept_version, { "OCF-Accept-Content-Format-Version" , "coap" ".opt.opt_ocf_accept_version", FT_UINT8, BASE_DEC, ( (void*)0), 0x0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0) } }, { & dissect_coap_hf .hf.opt_unknown, { "Unknown" , "coap" ".opt.unknown", FT_BYTES, BASE_NONE, ((void*)0), 0x0 , ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 1843 | }; | |||
| 1844 | ||||
| 1845 | static int *ett[] = { | |||
| 1846 | &ett_coap, | |||
| 1847 | &ett_block, | |||
| 1848 | &ett_blocks, | |||
| 1849 | COAP_COMMON_ETT_LIST(dissect_coap_hf)& dissect_coap_hf .ett.payload, & dissect_coap_hf .ett .option, | |||
| 1850 | }; | |||
| 1851 | ||||
| 1852 | static ei_register_info ei[] = { | |||
| 1853 | { &ei_retransmitted, | |||
| 1854 | { "coap.retransmitted", PI_SEQUENCE0x02000000, PI_NOTE0x00400000, | |||
| 1855 | "Retransmitted", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} } | |||
| 1856 | }, | |||
| 1857 | COAP_COMMON_EI_LIST(dissect_coap_hf, "coap"){ & dissect_coap_hf .ei.opt_unknown_number, { "coap" ".unknown_option_number" , 0x05000000, 0x00600000, "Unknown Option Number", 0, ((void* )0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} } }, { & dissect_coap_hf .ei.opt_invalid_number, { "coap" ".invalid_option_number", 0x07000000, 0x00600000, "Invalid Option Number" , 0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} } }, { & dissect_coap_hf .ei.opt_invalid_range , { "coap" ".invalid_option_range", 0x07000000, 0x00600000, "Invalid Option Range" , 0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} } }, { & dissect_coap_hf .ei.opt_length_bad , { "coap" ".option_length_bad", 0x07000000, 0x00600000, "Option length bad" , 0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} } }, { & dissect_coap_hf .ei.opt_object_security_bad , { "coap" ".option_oscore_bad", 0x07000000, 0x00600000, "Invalid OSCORE Option Format" , 0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} } }, | |||
| 1858 | }; | |||
| 1859 | ||||
| 1860 | expert_module_t *expert_coap; | |||
| 1861 | ||||
| 1862 | proto_coap = proto_register_protocol("Constrained Application Protocol", "CoAP", "coap"); | |||
| 1863 | proto_register_field_array(proto_coap, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0])); | |||
| 1864 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0])); | |||
| 1865 | expert_coap = expert_register_protocol(proto_coap); | |||
| 1866 | expert_register_field_array(expert_coap, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0])); | |||
| 1867 | ||||
| 1868 | reassembly_table_register (&coap_block_reassembly_table, &addresses_reassembly_table_functions); | |||
| 1869 | ||||
| 1870 | coap_other_handle = register_dissector("coap", dissect_coap_other, proto_coap); | |||
| 1871 | coap_tcp_tls_handle = register_dissector("coap_tcp_tls", dissect_coap_tcp_tls, proto_coap); | |||
| 1872 | coap_for_tmf_handle = register_dissector_with_description("coap_for_tmf", "CoAP-TMF", dissect_coap_for_tmf, proto_coap_for_tmf); | |||
| 1873 | ||||
| 1874 | /* | |||
| 1875 | * Set up a subdissector table for media types for CoAP-TMF. | |||
| 1876 | */ | |||
| 1877 | coap_tmf_media_type_dissector_table = | |||
| 1878 | register_dissector_table("coap_tmf_media_type", | |||
| 1879 | "Internet media type for CoAP-TMF", proto_coap, FT_STRING, STRING_CASE_INSENSITIVE1); | |||
| 1880 | ||||
| 1881 | /* | |||
| 1882 | * Set up a subdissector table for CoAP URI-Path. | |||
| 1883 | */ | |||
| 1884 | coap_uri_path_dissector_table = | |||
| 1885 | register_dissector_table("coap_uri_path", | |||
| 1886 | "URI-Path for CoAP", proto_coap, FT_STRING, STRING_CASE_INSENSITIVE1); | |||
| 1887 | } | |||
| 1888 | ||||
| 1889 | void | |||
| 1890 | proto_reg_handoff_coap(void) | |||
| 1891 | { | |||
| 1892 | dissector_handle_t coap_websockets_handle; | |||
| 1893 | ||||
| 1894 | media_type_dissector_table = find_dissector_table("media_type"); | |||
| 1895 | ||||
| 1896 | /* UDP and DTLS */ | |||
| 1897 | dissector_add_uint_with_preference("udp.port", DEFAULT_COAP_PORT5683, coap_other_handle); | |||
| 1898 | dtls_dissector_add(DEFAULT_COAPS_PORT5684, coap_other_handle); | |||
| 1899 | ||||
| 1900 | /* TCP, TLS */ | |||
| 1901 | dissector_add_uint_with_preference("tcp.port", DEFAULT_COAP_PORT5683, coap_tcp_tls_handle); | |||
| 1902 | ssl_dissector_add(DEFAULT_COAPS_PORT5684, coap_tcp_tls_handle); | |||
| 1903 | dissector_add_string("tls.alpn", "coap", coap_tcp_tls_handle); | |||
| 1904 | ||||
| 1905 | /* WebSockets (RFC 8323) */ | |||
| 1906 | coap_websockets_handle = create_dissector_handle(dissect_coap_websockets, proto_coap); | |||
| 1907 | dissector_add_string("ws.protocol", "coap", coap_websockets_handle); | |||
| 1908 | ||||
| 1909 | /* CoAP for Thread Management Framework */ | |||
| 1910 | dissector_add_for_decode_as("udp.port", coap_for_tmf_handle); | |||
| 1911 | ||||
| 1912 | oscore_handle = find_dissector("oscore"); | |||
| 1913 | } | |||
| 1914 | ||||
| 1915 | /* | |||
| 1916 | * Editor modelines - https://www.wireshark.org/tools/modelines.html | |||
| 1917 | * | |||
| 1918 | * Local variables: | |||
| 1919 | * c-basic-offset: 8 | |||
| 1920 | * tab-width: 8 | |||
| 1921 | * indent-tabs-mode: t | |||
| 1922 | * End: | |||
| 1923 | * | |||
| 1924 | * vi: set shiftwidth=8 tabstop=8 noexpandtab: | |||
| 1925 | * :indentSize=8:tabSize=8:noTabs=false: | |||
| 1926 | */ |