From Hauke Mehrtens:
[metze/wireshark/wip.git] / epan / dissectors / packet-coap.c
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-07.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  * $Id$
13  *
14  * Wireshark - Network traffic analyzer
15  * By Gerald Combs <gerald@wireshark.org>
16  * Copyright 1998 Gerald Combs
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31  */
32
33 #include "config.h"
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include <epan/prefs.h>
39 #include <expert.h>
40
41 void proto_register_coap(void);
42
43 static dissector_table_t media_type_dissector_table;
44
45 static int proto_coap = -1;
46
47 static int hf_coap_version              = -1;
48 static int hf_coap_ttype                = -1;
49 static int hf_coap_token_len            = -1;
50 static int hf_coap_token                = -1;
51 static int hf_coap_code                 = -1;
52 static int hf_coap_mid                  = -1;
53 static int hf_coap_payload_desc         = -1;
54 static int hf_coap_opt_name             = -1;
55 static int hf_coap_opt_desc             = -1;
56 static int hf_coap_opt_delta            = -1;
57 static int hf_coap_opt_delta_ext        = -1;
58 static int hf_coap_opt_length           = -1;
59 static int hf_coap_opt_length_ext       = -1;
60 static int hf_coap_opt_end_marker       = -1;
61 static int hf_coap_opt_ctype            = -1;
62 static int hf_coap_opt_max_age          = -1;
63 static int hf_coap_opt_proxy_uri        = -1;
64 static int hf_coap_opt_etag             = -1;
65 static int hf_coap_opt_uri_host         = -1;
66 static int hf_coap_opt_location_path    = -1;
67 static int hf_coap_opt_uri_port         = -1;
68 static int hf_coap_opt_location_query   = -1;
69 static int hf_coap_opt_uri_path         = -1;
70 static int hf_coap_opt_observe          = -1;
71 static int hf_coap_opt_accept           = -1;
72 static int hf_coap_opt_if_match         = -1;
73 static int hf_coap_opt_block_number     = -1;
74 static int hf_coap_opt_block_mflag      = -1;
75 static int hf_coap_opt_block_size       = -1;
76 static int hf_coap_opt_uri_query        = -1;
77 static int hf_coap_opt_unknown          = -1;
78
79 static gint ett_coap                    = -1;
80 static gint ett_coap_option             = -1;
81 static gint ett_coap_payload            = -1;
82
83 /* CoAP's IANA-assigned port number */
84 #define DEFAULT_COAP_PORT       5683
85
86 /* indicators whether those are to be showed or not */
87 #define DEFAULT_COAP_CTYPE_VALUE        ~0
88 #define DEFAULT_COAP_BLOCK_NUMBER       ~0
89
90 static const gchar *coap_ctype_str   = NULL;
91 static gint coap_ctype_value = DEFAULT_COAP_CTYPE_VALUE;
92 static guint global_coap_port_number = DEFAULT_COAP_PORT;
93 static gint coap_block_number = DEFAULT_COAP_BLOCK_NUMBER;
94 static guint coap_block_mflag = 0;
95 static gchar coap_uri_str[1024];        /* the maximum is 1024 > 510 = Uri-Host:255 + Uri-Path:255 x 2 */
96 static gchar coap_uri_query[1024];      /* the maximum is 1024 > 765 = Uri-Query:255 x 3 */
97 static gchar coap_token_str[128];
98
99 /*
100  * Transaction Type
101  */
102 static const value_string vals_ttype[] = {
103         { 0, "Confirmable" },
104         { 1, "Non-Confirmable" },
105         { 2, "Acknowledgement" },
106         { 3, "Reset" },
107         { 0, NULL },
108 };
109 static const value_string vals_ttype_short[] = {
110         { 0, "CON" },
111         { 1, "NON" },
112         { 2, "ACK" },
113         { 3, "RST" },
114         { 0, NULL },
115 };
116
117 /*
118  * Method Code
119  * Response Code
120  */
121 static const value_string vals_code[] = {
122         { 0, "Empty Message" },
123
124         /* method code */
125         { 1, "GET" },
126         { 2, "POST" },
127         { 3, "PUT" },
128         { 4, "DELETE" },
129
130         /* response code */
131         {  65, "2.01 Created" },
132         {  66, "2.02 Deleted" },
133         {  67, "2.03 Valid" },
134         {  68, "2.04 Changed" },
135         {  69, "2.05 Content" },
136         { 128, "4.00 Bad Request" },
137         { 129, "4.01 Unauthorized" },
138         { 130, "4.02 Bad Option" },
139         { 131, "4.03 Forbidden" },
140         { 132, "4.04 Not Found" },
141         { 133, "4.05 Method Not Allowed" },
142         { 134, "4.06 Not Acceptable" },
143         { 136, "4.08 Request Entity Incomplete" },      /* core-block-10 */
144         { 140, "4.12 Precondition Failed" },
145         { 141, "4.13 Request Entity Too Large" },
146         { 143, "4.15 Unsupported Content-Format" },
147         { 160, "5.00 Internal Server Error" },
148         { 161, "5.01 Not Implemented" },
149         { 162, "5.02 Bad Gateway" },
150         { 163, "5.03 Service Unavailable" },
151         { 164, "5.04 Gateway Timeout" },
152         { 165, "5.05 Proxying Not Supported" },
153
154         { 0, NULL },
155 };
156
157 /*
158  * Option Headers
159  * No-Option must not be included in this structure, is handled in the function
160  * of the dissector, especially.
161  */
162 #define COAP_OPT_IF_MATCH        1
163 #define COAP_OPT_URI_HOST        3
164 #define COAP_OPT_ETAG            4
165 #define COAP_OPT_IF_NONE_MATCH   5
166 #define COAP_OPT_OBSERVE         6      /* core-observe-07 */
167 #define COAP_OPT_URI_PORT        7
168 #define COAP_OPT_LOCATION_PATH   8
169 #define COAP_OPT_URI_PATH       11
170 #define COAP_OPT_CONTENT_TYPE   12
171 #define COAP_OPT_MAX_AGE        14
172 #define COAP_OPT_URI_QUERY      15
173 #define COAP_OPT_ACCEPT         16
174 #define COAP_OPT_LOCATION_QUERY 20
175 #define COAP_OPT_BLOCK2         23      /* core-block-10 */
176 #define COAP_OPT_BLOCK_SIZE     28      /* core-block-10 */
177 #define COAP_OPT_BLOCK1         27      /* core-block-10 */
178 #define COAP_OPT_PROXY_URI      35
179
180 static const value_string vals_opt_type[] = {
181         { COAP_OPT_IF_MATCH,       "If-Match" },
182         { COAP_OPT_URI_HOST,       "Uri-Host" },
183         { COAP_OPT_ETAG,           "Etag" },
184         { COAP_OPT_IF_NONE_MATCH,  "If-None-Match" },
185         { COAP_OPT_URI_PORT,       "Uri-Port" },
186         { COAP_OPT_LOCATION_PATH,  "Location-Path" },
187         { COAP_OPT_URI_PATH,       "Uri-Path" },
188         { COAP_OPT_CONTENT_TYPE,   "Content-Format" },
189         { COAP_OPT_MAX_AGE,        "Max-age" },
190         { COAP_OPT_URI_QUERY,      "Uri-Query" },
191         { COAP_OPT_ACCEPT,         "Accept" },
192         { COAP_OPT_LOCATION_QUERY, "Location-Query" },
193         { COAP_OPT_PROXY_URI,      "Proxy-Uri" },
194         { COAP_OPT_OBSERVE,        "Observe" },
195         { COAP_OPT_BLOCK2,         "Block2" },
196         { COAP_OPT_BLOCK1,         "Block1" },
197         { COAP_OPT_BLOCK_SIZE,     "Block Size" },
198         { 0, NULL },
199 };
200
201 struct coap_option_range_t {
202         guint type;
203         gint min;
204         gint max;
205 } coi[] = {
206     { COAP_OPT_IF_MATCH,       0,   8 },
207     { COAP_OPT_URI_HOST,       1, 255 },
208     { COAP_OPT_ETAG,           1,   8 },
209     { COAP_OPT_IF_NONE_MATCH,  0,   0 },
210     { COAP_OPT_URI_PORT,       0,   2 },
211     { COAP_OPT_LOCATION_PATH,  0, 255 },
212     { COAP_OPT_URI_PATH,       0, 255 },
213     { COAP_OPT_CONTENT_TYPE,   0,   2 },
214     { COAP_OPT_MAX_AGE,        0,   4 },
215     { COAP_OPT_URI_QUERY,      1, 255 },
216     { COAP_OPT_ACCEPT,         0,   2 },
217     { COAP_OPT_LOCATION_QUERY, 0, 255 },
218     { COAP_OPT_PROXY_URI,      1,1034 },
219     { COAP_OPT_OBSERVE,        0,   2 },
220     { COAP_OPT_BLOCK2,         0,   3 },
221     { COAP_OPT_BLOCK1,         0,   3 },
222     { COAP_OPT_BLOCK_SIZE,     0,   4 },
223     { 0, 0, 0 },
224 };
225
226 static const value_string vals_ctype[] = {
227         { 0, "text/plain; charset=utf-8" },
228         { 40, "application/link-format" },
229         { 41, "application/xml" },
230         { 42, "application/octet-stream" },
231         { 47, "application/exi" },
232         { 50, "application/json" },
233         { 0, NULL },
234 };
235
236 static const char *nullstr = "(null)";
237
238 void proto_reg_handoff_coap(void);
239
240 static int
241 coap_is_str_ipv6addr(guint8 *str)
242 {
243         size_t len   = strlen(str);
244         int    colon = 0;
245
246         while (len--) {
247                 if (*str++ == ':')
248                         colon++;
249         }
250
251         return colon > 1 ? 1 : 0;
252 }
253
254 static gint
255 coap_get_opt_uint(tvbuff_t *tvb, gint offset, gint length)
256 {
257         switch (length) {
258         case 0:
259                 return 0;
260         case 1:
261                 return (guint)tvb_get_guint8(tvb, offset);
262         case 2:
263                 return (guint)tvb_get_ntohs(tvb, offset);
264         case 3:
265                 return (guint)tvb_get_ntoh24(tvb, offset);
266         case 4:
267                 return (guint)tvb_get_ntohl(tvb, offset);
268         default:
269                 return -1;
270         }
271 }
272
273 static gint
274 coap_opt_check(packet_info *pinfo, proto_tree *subtree, guint opt_num, gint opt_length)
275 {
276         int i;
277
278         for (i = 0; i < (int)(array_length(coi)); i++) {
279                 if (coi[i].type == opt_num)
280                         break;
281         }
282         if (i == (int)(array_length(coi))) {
283                 expert_add_info_format(pinfo, subtree, PI_MALFORMED, PI_WARN,
284                     "Invalid Option Number %d", opt_num);
285                 return -1;
286         }
287         if (opt_length < coi[i].min || opt_length > coi[i].max) {
288                 expert_add_info_format(pinfo, subtree, PI_MALFORMED,
289                     PI_WARN, "Invalid Option Range: %d (%d < x < %d)",
290                     opt_length, coi[i].min, coi[i].max);
291         }
292
293         return 0;
294 }
295
296 static void
297 dissect_coap_opt_hex_string(tvbuff_t *tvb, proto_item *item, proto_tree *subtree, gint offset, gint opt_length, int hf)
298 {
299         const guint8 *str;
300
301         if (opt_length == 0)
302                 str = nullstr;
303         else
304                 str = tvb_bytes_to_str_punct(tvb, offset, opt_length, ' ');
305
306         proto_tree_add_string(subtree, hf, tvb, offset, opt_length, str);
307
308         /* add info to the head of the packet detail */
309         proto_item_append_text(item, ": %s", str);
310 }
311
312 static void
313 dissect_coap_opt_uint(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length, int hf)
314 {
315         guint i = 0;
316
317         if (opt_length != 0) {
318                 i = coap_get_opt_uint(tvb, offset, opt_length);
319         }
320
321         proto_tree_add_uint(subtree, hf, tvb, offset, opt_length, i);
322
323         /* add info to the head of the packet detail */
324         proto_item_append_text(head_item, ": %d", i);
325 }
326
327 static void
328 dissect_coap_opt_uri_host(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
329 {
330         guint8 *str = NULL;
331
332         str = tvb_get_ephemeral_string(tvb, offset, opt_length);
333
334         proto_tree_add_string(subtree, hf_coap_opt_uri_host, tvb, offset, opt_length, str);
335
336         /* add info to the head of the packet detail */
337         proto_item_append_text(head_item, ": %s", str);
338
339         /* forming a uri-string */
340         g_strlcat(coap_uri_str, "coap://", sizeof(coap_uri_str));
341         /*
342          * if the string looks an IPv6 address, assuming that it has
343          * to be enclosed by brackets.
344          */
345         if (coap_is_str_ipv6addr(str)) {
346                 g_strlcat(coap_uri_str, "[", sizeof(coap_uri_str));
347                 g_strlcat(coap_uri_str, str, sizeof(coap_uri_str));
348                 g_strlcat(coap_uri_str, "]", sizeof(coap_uri_str));
349         } else
350                 g_strlcat(coap_uri_str, str, sizeof(coap_uri_str));
351 }
352
353 static void
354 dissect_coap_opt_uri_path(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
355 {
356         const guint8 *str = NULL;
357
358         g_strlcat(coap_uri_str, "/", sizeof(coap_uri_str));
359
360         if (opt_length == 0) {
361                 str = nullstr;
362         } else {
363                 str = tvb_get_ephemeral_string(tvb, offset, opt_length);
364                 g_strlcat(coap_uri_str, str, sizeof(coap_uri_str));
365         }
366
367         proto_tree_add_string(subtree, hf_coap_opt_uri_path, tvb, offset, opt_length, str);
368
369         /* add info to the head of the packet detail */
370         proto_item_append_text(head_item, ": %s", str);
371 }
372
373 static void
374 dissect_coap_opt_uri_query(tvbuff_t *tvb, proto_item *head_item,proto_tree *subtree, gint offset, gint opt_length)
375 {
376         const guint8 *str = NULL;
377
378         if (coap_uri_query[0] == '\0')
379                 g_strlcat(coap_uri_query, "?", sizeof(coap_uri_str));
380         else
381                 g_strlcat(coap_uri_query, "&", sizeof(coap_uri_str));
382
383         if (opt_length == 0) {
384                 str = nullstr;
385         } else {
386                 str = tvb_get_ephemeral_string(tvb, offset, opt_length);
387                 g_strlcat(coap_uri_str, str, sizeof(coap_uri_str));
388         }
389
390         proto_tree_add_string(subtree, hf_coap_opt_uri_query, tvb, offset, opt_length, str);
391
392         /* add info to the head of the packet detail */
393         proto_item_append_text(head_item, ": %s", str);
394 }
395
396 static void
397 dissect_coap_opt_location_path(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
398 {
399         const guint8 *str = NULL;
400
401         if (opt_length == 0) {
402                 str = nullstr;
403         } else {
404                 str = tvb_get_ephemeral_string(tvb, offset, opt_length);
405         }
406
407         proto_tree_add_string(subtree, hf_coap_opt_location_path, tvb, offset, opt_length, str);
408
409         /* add info to the head of the packet detail */
410         proto_item_append_text(head_item, ": %s", str);
411 }
412
413 static void
414 dissect_coap_opt_location_query(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
415 {
416         const guint8 *str = NULL;
417
418         if (opt_length == 0) {
419                 str = nullstr;
420         } else {
421                 str = tvb_get_ephemeral_string(tvb, offset, opt_length);
422         }
423
424         proto_tree_add_string(subtree, hf_coap_opt_location_query, tvb, offset, opt_length, str);
425
426         /* add info to the head of the packet detail */
427         proto_item_append_text(head_item, ": %s", str);
428 }
429
430 static void
431 dissect_coap_opt_proxy_uri(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
432 {
433         const guint8 *str = NULL;
434
435         if (opt_length == 0) {
436                 str = nullstr;
437         } else {
438                 str = tvb_get_ephemeral_string(tvb, offset, opt_length);
439         }
440
441         proto_tree_add_string(subtree, hf_coap_opt_proxy_uri, tvb, offset, opt_length, str);
442
443         /* add info to the head of the packet detail */
444         proto_item_append_text(head_item, ": %s", str);
445 }
446
447 static void
448 dissect_coap_opt_ctype(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length, int hf)
449 {
450         if (opt_length == 0) {
451                 coap_ctype_value = 0;
452         } else {
453                 coap_ctype_value = coap_get_opt_uint(tvb, offset, opt_length);
454         }
455
456         coap_ctype_str = val_to_str(coap_ctype_value, vals_ctype, "Unknown Type %d");
457
458         proto_tree_add_string(subtree, hf, tvb, offset, opt_length, coap_ctype_str);
459
460         /* add info to the head of the packet detail */
461         proto_item_append_text(head_item, ": %s", coap_ctype_str);
462 }
463
464 static void
465 dissect_coap_opt_block(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
466 {
467         guint8      val                = 0;
468         guint       encoded_block_size = 0;
469         guint       block_esize;
470
471         if (opt_length == 0) {
472                 coap_block_number = 0;
473                 val = 0;
474         } else {
475                 coap_block_number = coap_get_opt_uint(tvb, offset, opt_length) >> 4;
476                 val = tvb_get_guint8(tvb, offset + opt_length - 1) & 0x0f;
477         }
478
479         proto_tree_add_uint(subtree, hf_coap_opt_block_number,
480             tvb, offset, opt_length, coap_block_number);
481
482         /* More flag in the end of the option */
483         coap_block_mflag = val & 0x08;
484         proto_tree_add_uint(subtree, hf_coap_opt_block_mflag,
485             tvb, offset + opt_length - 1, 1, coap_block_mflag);
486
487         /* block size */
488         encoded_block_size = val & 0x07;
489         block_esize = 1 << (encoded_block_size + 4);
490         proto_tree_add_uint_format(subtree, hf_coap_opt_block_size,
491             tvb, offset + opt_length - 1, 1, encoded_block_size, "Block Size: %d (%d encoded)", block_esize, encoded_block_size);
492
493         /* add info to the head of the packet detail */
494         proto_item_append_text(head_item, ": NUM:%d, M:%d, SZX:%d",
495             coap_block_number, coap_block_mflag, block_esize);
496 }
497
498 static void
499 dissect_coap_opt_uri_port(tvbuff_t *tvb, proto_item *head_item, proto_tree *subtree, gint offset, gint opt_length)
500 {
501         guint port = 0;
502         char portstr[6];
503
504         memset(portstr, '\0', sizeof(portstr));
505
506         if (opt_length != 0) {
507                 port = coap_get_opt_uint(tvb, offset, opt_length);
508         }
509
510         proto_tree_add_uint(subtree, hf_coap_opt_uri_port, tvb, offset, opt_length, port);
511
512         proto_item_append_text(head_item, ": %d", port);
513
514         /* forming a uri-string */
515         g_snprintf(portstr, sizeof(portstr), "%u", port);
516         g_strlcat(coap_uri_str, ":", sizeof(coap_uri_str));
517         g_strlcat(coap_uri_str, portstr, sizeof(coap_uri_str));
518 }
519
520 /*
521  * dissector for each option of CoAP.
522  * return the total length of the option including the header (e.g. delta and length).
523  */
524 static int
525 dissect_coap_options_main(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, gint offset, guint8 opt_count, guint *opt_num, gint coap_length)
526 {
527         guint8      opt_jump;
528         gint        opt_length, opt_length_ext, opt_delta, opt_delta_ext;
529         gint        opt_length_ext_off = 0;
530         gint8       opt_length_ext_len = 0;
531         gint        opt_delta_ext_off = 0;
532         gint8       opt_delta_ext_len = 0;
533         gint        orig_offset = offset;
534         proto_tree *subtree    = NULL;
535         proto_item *item       = NULL;
536         char strbuf[56];
537
538         opt_jump = tvb_get_guint8(tvb, offset);
539         offset++;
540
541         /*
542          * seciton 3.1 in coap-17:
543          * Option Delta:  4-bit unsigned integer.  A value between 0 and 12
544          * indicates the Option Delta.  Three values are reserved for special
545          * constructs:
546          *
547          * 13:  An 8-bit unsigned integer follows the initial byte and
548          *      indicates the Option Delta minus 13.
549          *
550          * 14:  A 16-bit unsigned integer in network byte order follows the
551          *      initial byte and indicates the Option Delta minus 269.
552          *
553          * 15:  Reserved for the Payload Marker.  If the field is set to this
554          *      value but the entire byte is not the payload marker, this MUST
555          *      be processed as a message format error.
556          */
557         switch (opt_jump & 0xf0) {
558         case 0xd0:
559                 opt_delta_ext = tvb_get_guint8(tvb, offset);
560                 opt_delta_ext_off = offset;
561                 opt_delta_ext_len = 1;
562                 offset++;
563
564                 opt_delta = 13;
565                 opt_delta += opt_delta_ext;
566                 break;
567         case 0xe0:
568                 opt_delta_ext = coap_get_opt_uint(tvb, offset, 2);
569                 opt_delta_ext_off = offset;
570                 opt_delta_ext_len = 2;
571                 offset += 2;
572
573                 opt_delta = 269;
574                 opt_delta += opt_delta_ext;
575                 break;
576         case 0xf0:
577                 expert_add_info_format(pinfo, coap_tree,
578                     PI_MALFORMED, PI_WARN,
579                     "end-of-options marker found, but option length isn't 15");
580                 return -1;
581         default:
582                 opt_delta = ((opt_jump & 0xf0) >> 4);
583                 break;
584         }
585         *opt_num += opt_delta;
586
587         /*
588          * seciton 3.1 in coap-17:
589          * Option Length:  4-bit unsigned integer.  A value between 0 and 12
590          * indicates the length of the Option Value, in bytes.  Three values
591          * are reserved for special constructs:
592          *
593          * 13:  An 8-bit unsigned integer precedes the Option Value and
594          *      indicates the Option Length minus 13.
595          *
596          * 14:  A 16-bit unsigned integer in network byte order precedes the
597          *      Option Value and indicates the Option Length minus 269.
598          * 
599          * 15:  Reserved for future use.  If the field is set to this value,
600          *      it MUST be processed as a message format error.
601          */
602         switch (opt_jump & 0x0f) {
603         case 0x0d:
604                 opt_length_ext = tvb_get_guint8(tvb, offset);
605                 opt_length_ext_off = offset;
606                 opt_length_ext_len = 1;
607                 offset++;
608
609                 opt_length = 13;
610                 opt_length += opt_length_ext;
611                 break;
612         case 0x0e:
613                 opt_length_ext = coap_get_opt_uint(tvb, offset, 2);
614                 opt_length_ext_off = offset;
615                 opt_length_ext_len = 2;
616                 offset += 2;
617
618                 opt_length = 269;
619                 opt_length += opt_length_ext;
620                 break;
621         case 0x0f:
622                 expert_add_info_format(pinfo, coap_tree,
623                     PI_MALFORMED, PI_WARN,
624                     "end-of-options marker found, but option delta isn't 15");
625                 return -1;
626         default:
627                 opt_length = (opt_jump & 0x0f);
628                 break;
629         }
630         if (offset + opt_length > coap_length) {
631                 expert_add_info_format(pinfo, coap_tree,
632                     PI_MALFORMED, PI_WARN,
633                     "option longer than the package");
634                 return -1;
635         }
636
637         coap_opt_check(pinfo, coap_tree, *opt_num, opt_length);
638
639         g_snprintf(strbuf, sizeof(strbuf), 
640             "#%u: %s", opt_count, val_to_str_const(*opt_num, vals_opt_type,
641             *opt_num % 14 == 0 ? "No-Op" : "Unknown Option"));
642         item = proto_tree_add_string(coap_tree, hf_coap_opt_name,
643             tvb, orig_offset, offset - orig_offset + opt_length, strbuf);
644         subtree = proto_item_add_subtree(item, ett_coap_option);
645
646         g_snprintf(strbuf, sizeof(strbuf), 
647             "Type %u, %s, %s%s", *opt_num,
648             (*opt_num & 1) ? "Critical" : "Elective",
649             (*opt_num & 2) ? "Unsafe" : "Safe",
650             ((*opt_num & 0x1e) == 0x1c) ? ", NoCacheKey" : "");
651         proto_tree_add_string(subtree, hf_coap_opt_desc,
652             tvb, orig_offset, offset - orig_offset + opt_length, strbuf);
653
654         proto_tree_add_item(subtree, hf_coap_opt_delta, tvb, orig_offset, 1, ENC_BIG_ENDIAN);
655         proto_tree_add_item(subtree, hf_coap_opt_length, tvb, orig_offset, 1, ENC_BIG_ENDIAN);
656
657         if (opt_delta_ext_off && opt_delta_ext_len)
658                 proto_tree_add_item(subtree, hf_coap_opt_delta_ext, tvb, opt_delta_ext_off, opt_delta_ext_len, ENC_BIG_ENDIAN);
659
660         if (opt_length_ext_off && opt_length_ext_len)
661                 proto_tree_add_item(subtree, hf_coap_opt_length_ext, tvb, opt_length_ext_off, opt_length_ext_len, ENC_BIG_ENDIAN);
662
663         /* offset points the next to its option header */
664         switch (*opt_num) {
665         case COAP_OPT_CONTENT_TYPE:
666                 dissect_coap_opt_ctype(tvb, item, subtree, offset,
667                     opt_length, hf_coap_opt_ctype);
668                 break;
669         case COAP_OPT_MAX_AGE:
670                 dissect_coap_opt_uint(tvb, item, subtree, offset,
671                     opt_length, hf_coap_opt_max_age);
672                 break;
673         case COAP_OPT_PROXY_URI:
674                 dissect_coap_opt_proxy_uri(tvb, item, subtree, offset,
675                     opt_length);
676                 break;
677         case COAP_OPT_ETAG:
678                 dissect_coap_opt_hex_string(tvb, item, subtree, offset,
679                     opt_length, hf_coap_opt_etag);
680                 break;
681         case COAP_OPT_URI_HOST:
682                 dissect_coap_opt_uri_host(tvb, item, subtree, offset,
683                     opt_length);
684                 break;
685         case COAP_OPT_LOCATION_PATH:
686                 dissect_coap_opt_location_path(tvb, item, subtree, offset,
687                     opt_length);
688                 break;
689         case COAP_OPT_URI_PORT:
690                 dissect_coap_opt_uri_port(tvb, item, subtree, offset,
691                     opt_length);
692                 break;
693         case COAP_OPT_LOCATION_QUERY:
694                 dissect_coap_opt_location_query(tvb, item, subtree, offset,
695                     opt_length);
696                 break;
697         case COAP_OPT_URI_PATH:
698                 dissect_coap_opt_uri_path(tvb, item, subtree, offset,
699                     opt_length);
700                 break;
701         case COAP_OPT_OBSERVE:
702                 dissect_coap_opt_uint(tvb, item, subtree, offset,
703                     opt_length, hf_coap_opt_observe);
704                 break;
705         case COAP_OPT_ACCEPT:
706                 dissect_coap_opt_ctype(tvb, item, subtree, offset,
707                     opt_length, hf_coap_opt_accept);
708                 break;
709         case COAP_OPT_IF_MATCH:
710                 dissect_coap_opt_hex_string(tvb, item, subtree, offset,
711                     opt_length, hf_coap_opt_if_match);
712                 break;
713         case COAP_OPT_URI_QUERY:
714                 dissect_coap_opt_uri_query(tvb, item, subtree, offset,
715                     opt_length);
716                 break;
717         case COAP_OPT_BLOCK2:
718                 dissect_coap_opt_block(tvb, item, subtree, offset,
719                     opt_length);
720                 break;
721         case COAP_OPT_BLOCK1:
722                 dissect_coap_opt_block(tvb, item, subtree, offset,
723                     opt_length);
724                 break;
725         case COAP_OPT_IF_NONE_MATCH:
726                 break;
727         case COAP_OPT_BLOCK_SIZE:
728                 dissect_coap_opt_uint(tvb, item, subtree, offset,
729                     opt_length, hf_coap_opt_block_size);
730                 break;
731         default:
732                 dissect_coap_opt_hex_string(tvb, item, subtree, offset,
733                     opt_length, hf_coap_opt_unknown);
734                 break;
735         }
736
737         return offset + opt_length;
738 }
739
740 /*
741  * options dissector.
742  * return offset pointing the next of options. (i.e. the top of the paylaod
743  * or the end of the data.
744  */
745 static int
746 dissect_coap_options(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, gint offset, gint coap_length)
747 {
748         guint      opt_num = 0;
749         int         i;
750         guint8     endmarker;
751
752         /* loop for dissecting options */
753         for (i = 1; offset < coap_length; i++) {
754                 offset = dissect_coap_options_main(tvb, pinfo, coap_tree,
755                     offset, i, &opt_num, coap_length);
756                 if (offset == -1)
757                         return -1;
758                 if (offset >= coap_length)
759                         break;
760                 endmarker = tvb_get_guint8(tvb, offset);
761                 if (endmarker == 0xff) {
762                         proto_tree_add_item(coap_tree, hf_coap_opt_end_marker, tvb, offset, 1, ENC_BIG_ENDIAN);
763                         offset++;
764                         break;
765                 }
766         }
767
768         return offset;
769 }
770
771 static void
772 dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
773 {
774         gint        offset      = 0;
775         proto_item *coap_root   = NULL;
776         proto_tree *coap_tree   = NULL;
777         guint8      ttype       = 0;
778         guint8      token_len   = 0;
779         guint8      code        = 0;
780         guint16     mid         = 0;
781         gint        coap_length = 0;
782
783         /* initialize the CoAP length and the content-Format */
784         /*
785          * the length of CoAP message is not specified in the CoAP header.
786          * It has to be from the lower layer.  the iplen of packet_info is not accurate.
787          * Currently, the length is just copied from the reported length of the tvbuffer.
788          */
789         coap_length = tvb_reported_length(tvb);
790         coap_ctype_str = "";
791         coap_ctype_value = DEFAULT_COAP_CTYPE_VALUE;
792
793         coap_root = proto_tree_add_item(parent_tree, proto_coap, tvb, offset, -1, ENC_NA);
794         coap_tree = proto_item_add_subtree(coap_root, ett_coap);
795
796         proto_tree_add_item(coap_tree, hf_coap_version, tvb, offset, 1, ENC_BIG_ENDIAN);
797
798         proto_tree_add_item(coap_tree, hf_coap_ttype, tvb, offset, 1, ENC_BIG_ENDIAN);
799         ttype = (tvb_get_guint8(tvb, offset) & 0x30) >> 4;
800
801         proto_tree_add_item(coap_tree, hf_coap_token_len, tvb, offset, 1, ENC_BIG_ENDIAN);
802         token_len = tvb_get_guint8(tvb, offset) & 0x0f;
803         offset += 1;
804
805         proto_tree_add_item(coap_tree, hf_coap_code, tvb, offset, 1, ENC_BIG_ENDIAN);
806         code = tvb_get_guint8(tvb, offset);
807         offset += 1;
808
809         proto_tree_add_item(coap_tree, hf_coap_mid, tvb, offset, 2, ENC_BIG_ENDIAN);
810         mid = tvb_get_ntohs(tvb, offset);
811         offset += 2;
812
813         /* append the header information */
814         proto_item_append_text(coap_tree, ", %s, %s, MID:%u", val_to_str(ttype, vals_ttype, "Unkown %d"), val_to_str(code, vals_code, "Unknown %d"), mid);
815
816         /* initialize the external value */
817         coap_block_number = DEFAULT_COAP_BLOCK_NUMBER;
818         coap_block_mflag = 0;
819         coap_uri_str[0] = '\0';
820         coap_uri_query[0] = '\0';
821         coap_token_str[0] = '\0';
822
823         if (token_len > 0)
824         {
825                 g_strlcat(coap_token_str, tvb_bytes_to_str_punct(tvb, offset, token_len, ' '), sizeof(coap_token_str));
826                 proto_tree_add_item(coap_tree, hf_coap_token,
827                                     tvb, offset, token_len, ENC_NA);
828                 offset += token_len;
829         }
830
831         /* process options */
832         offset = dissect_coap_options(tvb, pinfo, coap_tree, offset, coap_length);
833         if (offset == -1)
834                 return;
835
836         /* add informations to the packet list */
837         col_set_str(pinfo->cinfo, COL_PROTOCOL, "CoAP");
838         col_clear(pinfo->cinfo, COL_INFO);
839         col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(ttype, vals_ttype_short, "Unknown %d"));
840         col_append_fstr(pinfo->cinfo, COL_INFO, ", MID:%u", mid);
841         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(code, vals_code, "Unknown %d"));
842         if (coap_token_str[0] != '\0')
843                 col_append_fstr(pinfo->cinfo, COL_INFO, ", TKN:%s", coap_token_str);
844         if (coap_block_number != DEFAULT_COAP_BLOCK_NUMBER)
845                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %sBlock #%d", coap_block_mflag ? "" : "End of ", coap_block_number);
846         if (coap_uri_str[0] != '\0')
847                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", coap_uri_str);
848         if (coap_uri_query[0] != '\0')
849                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", coap_uri_query);
850
851         /* dissect the payload */
852         if (coap_length > offset) {
853                 proto_tree *payload_tree = NULL;
854                 proto_item *payload_item = NULL;
855                 tvbuff_t *payload_tvb;
856                 guint payload_length = coap_length - offset;
857                 char str_payload[80];
858
859                 /*
860                  * 5.5.2.  Diagnostic Payload
861                  *
862                  * If no Content-Format option is given, the payload of responses
863                  * indicating a client or server error is a brief human-readable
864                  * diagnostic message, explaining the error situation. This diagnostic
865                  * message MUST be encoded using UTF-8 [RFC3629], more specifically
866                  * using Net-Unicode form [RFC5198].
867                  */
868                 if (coap_ctype_value == DEFAULT_COAP_CTYPE_VALUE)
869                         coap_ctype_str = "text/plain; charset=utf-8";
870
871                 g_snprintf(str_payload, sizeof(str_payload), 
872                     "Payload Content-Format: %s%s, Length: %u, offset: %u",
873                     coap_ctype_str, coap_ctype_value == DEFAULT_COAP_CTYPE_VALUE ?
874                     " (no Content-Format)" : "", payload_length, offset);
875                 proto_tree_add_string(coap_tree, hf_coap_payload_desc,
876                     tvb, offset, -1, coap_ctype_str);
877                 payload_tree = proto_item_add_subtree(payload_item, ett_coap_payload);
878                 payload_tvb = tvb_new_subset(tvb, offset, payload_length, payload_length);
879
880                 dissector_try_string(media_type_dissector_table, coap_ctype_str, payload_tvb, pinfo, payload_tree);
881         }
882 }
883
884 /*
885  * Protocol initialization
886  */
887 void
888 proto_register_coap(void)
889 {
890         static hf_register_info hf[] = {
891                 { &hf_coap_version,
892                   { "Version", "coap.version",
893                     FT_UINT8, BASE_DEC, NULL, 0xc0,
894                     "CoAP Version", HFILL }
895                 },
896                 { &hf_coap_ttype,
897                   { "Type", "coap.type",
898                     FT_UINT8, BASE_DEC, VALS(vals_ttype), 0x30,
899                     "CoAP Transaction Type", HFILL }
900                 },
901                 { &hf_coap_token_len,
902                   { "Token Length", "coap.token_len",
903                     FT_UINT8, BASE_DEC, NULL, 0x0f,
904                     "CoAP Token Length", HFILL }
905                 },
906                 { &hf_coap_token,
907                   { "Token", "coap.token",
908                     FT_BYTES, BASE_NONE, NULL, 0x0,
909                     "CoAP Token", HFILL }
910                 },
911                 { &hf_coap_code,
912                   { "Code", "coap.code",
913                     FT_UINT8, BASE_DEC, VALS(vals_code), 0x0,
914                     "CoAP Method or Response Code", HFILL }
915                 },
916                 { &hf_coap_mid,
917                   { "Message ID", "coap.mid",
918                     FT_UINT16, BASE_DEC, NULL, 0x0,
919                     "CoAP Message ID", HFILL }
920                 },
921                 { &hf_coap_payload_desc,
922                   { "Payload Desc", "coap.opt.payload_desc",
923                     FT_STRING, BASE_NONE, NULL, 0x0,
924                     "CoAP Payload Description", HFILL }
925                 },
926                 { &hf_coap_opt_name,
927                   { "Opt Name", "coap.opt.name",
928                     FT_STRING, BASE_NONE, NULL, 0x0,
929                     "CoAP Option Name", HFILL }
930                 },
931                 { &hf_coap_opt_desc,
932                   { "Opt Desc", "coap.opt.desc",
933                     FT_STRING, BASE_NONE, NULL, 0x0,
934                     "CoAP Option Description", HFILL }
935                 },
936                 { &hf_coap_opt_delta,
937                   { "Opt Delta", "coap.opt.delta",
938                     FT_UINT8, BASE_DEC, NULL, 0xf0,
939                     "CoAP Option Delta", HFILL }
940                 },
941                 { &hf_coap_opt_delta_ext,
942                   { "Opt Delta extended", "coap.opt.delta_ext",
943                     FT_UINT16, BASE_DEC, NULL, 0x0,
944                     "CoAP Option Delta extended", HFILL }
945                 },
946                 { &hf_coap_opt_length,
947                   { "Opt Length", "coap.opt.length",
948                     FT_UINT8, BASE_DEC, NULL, 0x0f,
949                     "CoAP Option Length", HFILL }
950                 },
951                 { &hf_coap_opt_length_ext,
952                   { "Opt Length extended", "coap.opt.length_ext",
953                     FT_UINT16, BASE_DEC, NULL, 0x0,
954                     "CoAP Option Length extended", HFILL }
955                 },
956                 { &hf_coap_opt_end_marker,
957                   { "End of options marker", "coap.opt.end_marker",
958                     FT_UINT8, BASE_DEC, NULL, 0x00,
959                     "CoAP End of options marker", HFILL }
960                 },
961                 { &hf_coap_opt_ctype,
962                   { "Content-type", "coap.opt.ctype",
963                     FT_STRING, BASE_NONE, NULL, 0x0,
964                     "CoAP Option Content Type", HFILL }
965                 },
966                 { &hf_coap_opt_max_age,
967                   { "Max-age", "coap.opt.max_age",
968                     FT_UINT32, BASE_DEC, NULL, 0x0,
969                     "CoAP Option Max-age", HFILL }
970                 },
971                 { &hf_coap_opt_proxy_uri,
972                   { "Proxy-Uri", "coap.opt.proxy_uri",
973                     FT_STRING, BASE_NONE, NULL, 0x0,
974                     "CoAP Option Proxy-Uri", HFILL }
975                 },
976                 { &hf_coap_opt_etag,
977                   { "Etag", "coap.opt.etag",
978                     FT_BYTES, BASE_NONE, NULL, 0x0,
979                     "CoAP Option Etag", HFILL }
980                 },
981                 { &hf_coap_opt_uri_host,
982                   { "Uri-Host", "coap.opt.uri_host",
983                     FT_STRING, BASE_NONE, NULL, 0x0,
984                     "CoAP Option Uri-Host", HFILL }
985                 },
986                 { &hf_coap_opt_location_path,
987                   { "Location-Path", "coap.opt.location_path",
988                     FT_STRING, BASE_NONE, NULL, 0x0,
989                     "CoAP Option Uri-Path", HFILL }
990                 },
991                 { &hf_coap_opt_uri_port,
992                   { "Uri-Port", "coap.opt.uri_port",
993                     FT_UINT16, BASE_DEC, NULL, 0x0,
994                     "CoAP Option Uri-Port", HFILL }
995                 },
996                 { &hf_coap_opt_location_query,
997                   { "Location-Query", "coap.opt.location_query",
998                     FT_STRING, BASE_NONE, NULL, 0x0,
999                     "CoAP Option Uri-Query", HFILL }
1000                 },
1001                 { &hf_coap_opt_uri_path,
1002                   { "Uri-Path", "coap.opt.uri_path",
1003                     FT_STRING, BASE_NONE, NULL, 0x0,
1004                     "CoAP Option Uri-Path", HFILL }
1005                 },
1006                 { &hf_coap_opt_observe,
1007                   { "Lifetime", "coap.opt.subscr_lifetime",
1008                     FT_UINT32, BASE_DEC, NULL, 0x0,
1009                     "CoAP Option Observe", HFILL }
1010                 },
1011                 { &hf_coap_opt_accept,
1012                   { "Accept", "coap.opt.accept",
1013                     FT_STRING, BASE_NONE, NULL, 0x0,
1014                     "CoAP Option Acceptable Content Type", HFILL }
1015                 },
1016                 { &hf_coap_opt_if_match,
1017                   { "If-Match", "coap.opt.if_match",
1018                     FT_BYTES, BASE_NONE, NULL, 0x0,
1019                     "CoAP Option If-Match", HFILL }
1020                 },
1021                 { &hf_coap_opt_block_number,
1022                   { "Block Number", "coap.opt.block_number",
1023                     FT_UINT32, BASE_DEC, NULL, 0x0,
1024                     "CoAP Option Block Number", HFILL }
1025                 },
1026                 { &hf_coap_opt_block_mflag,
1027                   { "More Flag", "coap.opt.block_mflag",
1028                     FT_UINT8, BASE_DEC, NULL, 0x08,
1029                     "CoAP Option Block More Size", HFILL }
1030                 },
1031                 { &hf_coap_opt_block_size,
1032                   { "Encoded Block Size", "coap.opt.block_size",
1033                     FT_UINT8, BASE_DEC, NULL, 0x07,
1034                     "CoAP Option Encoded Block Size", HFILL }
1035                 },
1036                 { &hf_coap_opt_uri_query,
1037                   { "Uri-Query", "coap.opt.uri_query",
1038                     FT_STRING, BASE_NONE, NULL, 0x0,
1039                     "CoAP Option Uri-Query", HFILL }
1040                 },
1041                 { &hf_coap_opt_unknown,
1042                   { "Unknown", "coap.opt.unknown",
1043                     FT_STRING, BASE_NONE, NULL, 0x0,
1044                     "Coap Unknown Option", HFILL }
1045                 },
1046         };
1047
1048         static gint *ett[] = {
1049                 &ett_coap,
1050                 &ett_coap_option,
1051                 &ett_coap_payload,
1052         };
1053
1054         module_t *coap_module;
1055
1056         proto_coap = proto_register_protocol("Constrained Application Protocol", "CoAP", "coap");
1057         proto_register_field_array(proto_coap, hf, array_length(hf));
1058         proto_register_subtree_array(ett, array_length(ett));
1059
1060         register_dissector("coap", dissect_coap, proto_coap);
1061
1062         /* Register our configuration options */
1063         coap_module = prefs_register_protocol (proto_coap, proto_reg_handoff_coap);
1064
1065         prefs_register_uint_preference (coap_module, "udp_port",
1066                                         "CoAP port number",
1067                                         "Port number used for CoAP traffic",
1068                                         10, &global_coap_port_number);
1069 }
1070
1071 void
1072 proto_reg_handoff_coap(void)
1073 {
1074         static gboolean coap_prefs_initialized = FALSE;
1075         static dissector_handle_t coap_handle;
1076         static guint coap_port_number;
1077
1078         if (!coap_prefs_initialized) {
1079                 coap_handle = find_dissector("coap");
1080                 media_type_dissector_table = find_dissector_table("media_type");
1081                 coap_prefs_initialized = TRUE;
1082         } else {
1083                 dissector_delete_uint("udp.port", coap_port_number, coap_handle);
1084                 dissector_delete_uint("tcp.port", coap_port_number, coap_handle);
1085         }
1086
1087         coap_port_number = global_coap_port_number;
1088         dissector_add_uint("udp.port", coap_port_number, coap_handle);
1089         dissector_add_uint("tcp.port", coap_port_number, coap_handle);
1090 }