From Shoichi Sakane via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5270 :
authormorriss <morriss@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 20 Oct 2010 20:40:53 +0000 (20:40 +0000)
committermorriss <morriss@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 20 Oct 2010 20:40:53 +0000 (20:40 +0000)
I made a patch to support more COAP options.
some options includes variable length field.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@34592 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-coap.c

index f58b8dafc644906fdf961b0a3b0d72293ebabc2f..daf5449f62fc513358a77853a98c3d47339dfd6b 100644 (file)
@@ -3,7 +3,11 @@
  * Shoichi Sakane <sakane@tanu.org>
  *
  * $Id$
+ *
  * draft-core-coap-02.txt
+ * draft-ietf-core-coap-02.txt
+ * draft-ietf-core-block-00.txt
+ * draft-ietf-core-observe-00.txt
  *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
@@ -44,11 +48,11 @@ static int hf_coap_code                     = -1;
 static int hf_coap_tid                 = -1;
 static int hf_coap_opt_type            = -1;
 static int hf_coap_opt_ctype           = -1;
-static int hf_coap_opt_max_age         = -1;
 static int hf_coap_opt_etag            = -1;
 static int hf_coap_opt_uri_authority   = -1;
 static int hf_coap_opt_location                = -1;
 static int hf_coap_opt_uri_path                = -1;
+static int hf_coap_opt_opaque_bytes    = -1;
 
 static gint ett_coap                   = -1;
 static gint ett_coap_noop              = -1;
@@ -59,6 +63,9 @@ static gint ett_coap_etag             = -1;
 static gint ett_coap_uri_authority     = -1;
 static gint ett_coap_location          = -1;
 static gint ett_coap_uri_path          = -1;
+static gint ett_coap_subscr_lifetime   = -1;
+static gint ett_coap_opaque_bytes      = -1;
+static gint ett_coap_block             = -1;
 static gint ett_coap_payload           = -1;
 
 /* TODO: COAP port number will be assigned by IANA after the draft become a RFC */
@@ -116,22 +123,28 @@ static const value_string vals_code[] = {
 #define COAP_OPT_URI_AUTHORITY 5
 #define COAP_OPT_LOCATION      6
 #define COAP_OPT_URI_PATH      9
+#define COAP_OPT_SUBSCR_LIFETIME       10
+#define COAP_OPT_OPAQUE_BYTES  11
+#define COAP_OPT_BLOCK         13
 
 static const value_string vals_opt_type[] = {
        { COAP_OPT_CONTENT_TYPE, "Content-Type" },
-       { COAP_OPT_MAX_AGE, "Max-age"},
-       { COAP_OPT_ETAG, "Etag"},
-       { COAP_OPT_URI_AUTHORITY, "Uri-Authority"},
-       { COAP_OPT_LOCATION, "Location"},
-       { COAP_OPT_URI_PATH, "Uri-Path"},
+       { COAP_OPT_MAX_AGE, "Max-age" },
+       { COAP_OPT_ETAG, "Etag" },
+       { COAP_OPT_URI_AUTHORITY, "Uri-Authority" },
+       { COAP_OPT_LOCATION, "Location" },
+       { COAP_OPT_URI_PATH, "Uri-Path" },
+       { COAP_OPT_SUBSCR_LIFETIME, "Subscription Lifetime" },
+       { COAP_OPT_OPAQUE_BYTES, "Opaque Bytes" },
+       { COAP_OPT_BLOCK, "Block" },
        { 0, NULL },
 };
 
 static const value_string vals_ctype[] = {
-       { 0, "text/plain (UTF-8)" },
-       { 1, "text/xml (UTF-8)" },
-       { 2, "text/csv (UTF-8)" },
-       { 3, "text/html (UTF-8)" },
+       { 0, "text/plain" },
+       { 1, "text/xml" },
+       { 2, "text/csv" },
+       { 3, "text/html" },
        { 21, "image/gif" },
        { 22, "image/jpeg" },
        { 23, "image/png" },
@@ -155,16 +168,77 @@ static const value_string vals_ctype[] = {
 
 void proto_reg_handoff_coap(void);
 
+/* the value of opt_length should be checked out of this function */
+static void
+dissect_coap_opt_time(tvbuff_t *tvb, proto_tree *subtree, int offset, gint opt_length, char *str)
+{
+       guint time = 0;
+
+       switch (opt_length) {
+       case 0:
+               time = 0;
+               break;
+       case 1:
+               time = (guint)tvb_get_guint8(tvb, offset);
+               break;
+       case 2:
+               time = (guint)tvb_get_ntohs(tvb, offset);
+               break;
+       case 3:
+               time = (guint)tvb_get_ntoh24(tvb, offset);
+               break;
+       case 4:
+               time = (guint)tvb_get_ntohl(tvb, offset);
+               break;
+       default:
+               proto_tree_add_text(subtree, tvb, 0, 0, "Invalid length: %d", opt_length);
+               break;
+       }
+       proto_tree_add_text(subtree, tvb, offset, opt_length, "%s: %d (s)", str, time);
+
+       return;
+}
+
+static void
+dissect_coap_opt_block(tvbuff_t *tvb, proto_tree *subtree, int offset, gint opt_length)
+{
+       guint block_number = 0;
+       guint more_flag = 0;
+       guint block_size = 0;
+       guint8 val = 0;
+
+       switch (opt_length) {
+       case 1:
+               block_number = (guint)(tvb_get_guint8(tvb, offset) >> 4);
+               break;
+       case 2:
+               block_number = (guint)(tvb_get_ntohs(tvb, offset) >> 4);
+               break;
+       case 3:
+               block_number = (guint)(tvb_get_ntoh24(tvb, offset) >> 4);
+               break;
+       default:
+               proto_tree_add_text(subtree, tvb, 0, 0, "Invalid length: %d", opt_length);
+               return;
+       }
+
+       val = tvb_get_guint8(tvb, offset + opt_length - 1) & 0x0f;
+       more_flag = (val & 0x08) >> 3;
+       block_size = val & 0x07;
+       block_size = 2^(block_size + 4);
+
+       proto_tree_add_text(subtree, tvb, offset, opt_length, "Block Number:%d, More Flag:%d, Block Size:%d", block_number, more_flag, block_size);
+}
+
 /*
  * dissector for each option of COAP.
  * return the total length of the option including the header (e.g. delta and length).
  */
 static int
-dissect_coap_options(tvbuff_t *tvb, proto_tree *coap_tree, proto_tree *parent_tree _U_, int offset, guint8 *opt_code)
+dissect_coap_options(tvbuff_t *tvb, proto_tree *coap_tree, proto_tree *parent_tree _U_, int offset, guint8 opt_count, guint8 *opt_code)
 {
        guint8 opt_delta;
        guint32 opt_ctype = 0;
-       guint opt_max_age = 0;
        gint opt_length;
        proto_tree *subtree = NULL;
        proto_item *item = NULL;
@@ -178,9 +252,10 @@ dissect_coap_options(tvbuff_t *tvb, proto_tree *coap_tree, proto_tree *parent_tr
                opt_length += tvb_get_guint8(tvb, offset + 1);
                opt_hlen = 2;
        }
-       item = proto_tree_add_uint_format(coap_tree, hf_coap_opt_type, tvb, offset, 1, *opt_code,
-           "Option (Length: %u) %s",
-           opt_length, val_to_str(*opt_code, vals_opt_type, "Unknown Option Type"));
+
+       item = proto_tree_add_text(coap_tree, tvb, offset, opt_hlen + opt_length,
+                                  "Option #%u (Length: %u) %s", opt_count, opt_length,
+                                  val_to_str(*opt_code, vals_opt_type, "Unknown Option Type %u"));
        offset += opt_hlen;
 
        /* if opt_code is a multiple of 14, that means the option is a noop option */
@@ -192,31 +267,16 @@ dissect_coap_options(tvbuff_t *tvb, proto_tree *coap_tree, proto_tree *parent_tr
                case COAP_OPT_CONTENT_TYPE:
                        subtree = proto_item_add_subtree(item, ett_coap_ctype);
                        opt_ctype = tvb_get_guint8(tvb, offset);
-                       coap_content_type = val_to_str(opt_ctype, vals_code, "Unknown %d");
+                       coap_content_type = val_to_str(opt_ctype, vals_ctype, "Unknown %d");
                        proto_tree_add_item(subtree, hf_coap_opt_ctype, tvb, offset, 1, FALSE);
                        break;
                case COAP_OPT_MAX_AGE:
                        subtree = proto_item_add_subtree(item, ett_coap_max_age);
-                       switch (opt_length) {
-                       case 1:
-                               opt_max_age = (guint)tvb_get_guint8(tvb, offset);
-                               break;
-                       case 2:
-                               opt_max_age = (guint)tvb_get_ntohs(tvb, offset);
-                               break;
-                       case 3:
-                               opt_max_age = (guint)tvb_get_ntoh24(tvb, offset);
-                               break;
-                       case 4:
-                               opt_max_age = (guint)tvb_get_ntohl(tvb, offset);
-                               break;
-                       default:
-                               proto_tree_add_text(subtree, tvb, 0, 0, "Invalid length: %d", opt_length);
-                               break;
-                       }
-                       if (opt_length >= 1 && opt_length <= 4) {
-                         proto_tree_add_item(subtree, hf_coap_opt_max_age, tvb, offset, opt_length, FALSE);
-                       }
+                       dissect_coap_opt_time(tvb, subtree, offset, opt_length, "Max-age");
+                       break;
+               case COAP_OPT_SUBSCR_LIFETIME:
+                       subtree = proto_item_add_subtree(item, ett_coap_subscr_lifetime);
+                       dissect_coap_opt_time(tvb, subtree, offset, opt_length, "Subscription Lifetime");
                        break;
                case COAP_OPT_ETAG:
                        subtree = proto_item_add_subtree(item, ett_coap_etag);
@@ -234,6 +294,13 @@ dissect_coap_options(tvbuff_t *tvb, proto_tree *coap_tree, proto_tree *parent_tr
                        subtree = proto_item_add_subtree(item, ett_coap_uri_path);
                        proto_tree_add_item(subtree, hf_coap_opt_uri_path, tvb, offset, opt_length, FALSE);
                        break;
+               case COAP_OPT_OPAQUE_BYTES:
+                       /* TODO: implement it after a draft will be published */
+                       break;
+               case COAP_OPT_BLOCK:
+                       subtree = proto_item_add_subtree(item, ett_coap_block);
+                       dissect_coap_opt_block(tvb, subtree, offset, opt_length);
+                       break;
                default:
                        proto_tree_add_text(subtree, tvb, 0, 0, "Unkown Option Type");
                }
@@ -251,8 +318,9 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        guint8 opt_count = 0;
        guint8 code = 0;
        guint16 tid = 0;
-       guint coap_length = pinfo->iplen - pinfo->iphdrlen - 8;
+       guint coap_length = 0;
        guint8 opt_code = 0;
+       int i;
 
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "COAP");
        col_clear(pinfo->cinfo, COL_INFO);
@@ -260,6 +328,15 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        if (!parent_tree)
                return;
 
+       /* initialize the COAP length and the content-type */
+       /*
+        * the length of COAP message is not specified in the COAP header.
+        * It has to be from the lower layer.  the iplen of packet_info is not accurate.
+        * Currently, the length is just copied from the reported length of the tvbuffer.
+        */
+       coap_length = tvb_reported_length(tvb);
+       coap_content_type = NULL;
+
        coap_root = proto_tree_add_item(parent_tree, proto_coap, tvb, offset, -1, FALSE);
        coap_tree = proto_item_add_subtree(coap_root, ett_coap);
 
@@ -286,8 +363,8 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        proto_item_append_text(coap_tree, ", TID: %u, Length: %u", tid, coap_length);
 
        /* dissect the options */
-       while (opt_count--) {
-               offset = dissect_coap_options(tvb, coap_tree, parent_tree, offset, &opt_code);
+       for (i = 1; i <= opt_count; i++) {
+               offset = dissect_coap_options(tvb, coap_tree, parent_tree, offset, i, &opt_code);
                if (coap_length < offset) {
                        /* error */
                        proto_tree_add_text(coap_tree, tvb, 0, 0, "Invalid length: coap_length(%d) < offset(%d)", coap_length, offset);
@@ -302,7 +379,6 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                tvbuff_t *payload_tvb;
                guint payload_length = coap_length - offset;
                char *ctype_str_default = "";
-               gboolean result = TRUE;
 
                /*
                 * TODO:
@@ -314,7 +390,7 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        /* default: coap-02 section 3.2.1 */
                        /* when it's NULL, "text/plain" is set anyway */
                        coap_content_type = "text/plain";
-                       ctype_str_default = "(as default)";
+                       ctype_str_default = " (default)";
                }
                /*
                 * TODO: should the content type be canonicalized,
@@ -322,15 +398,11 @@ dissect_coap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                 */
 
                payload_item = proto_tree_add_text(coap_tree, tvb, offset, -1, "Payload Content-Type: %s%s, Length: %u, offset: %u",
-                   coap_content_type, ctype_str_default, payload_length, offset);
+                                                  coap_content_type, ctype_str_default, payload_length, offset);
                payload_tree = proto_item_add_subtree(payload_item, ett_coap_payload);
                payload_tvb = tvb_new_subset(tvb, offset, payload_length, payload_length);
 
-               result = dissector_try_string(media_type_dissector_table, coap_content_type, payload_tvb, pinfo, payload_tree);
-               if (!result) {
-                       /* TODO: call heuristic dissector */
-                       ;
-               }
+               dissector_try_string(media_type_dissector_table, coap_content_type, payload_tvb, pinfo, payload_tree);
        }
 }
 
@@ -348,11 +420,11 @@ proto_register_coap(void)
            { &hf_coap_tid, { "Transaction ID", "coap.tid", FT_UINT16, BASE_DEC, NULL, 0x0, "COAP Transaction ID", HFILL }},
            { &hf_coap_opt_type, { "Option Type", "coap.opt.opt_type", FT_UINT8, BASE_DEC, VALS(&vals_opt_type), 0x0, "COAP Option Type", HFILL }},
            { &hf_coap_opt_ctype, { "Content-type", "coap.opt.ctype", FT_UINT8, BASE_DEC, VALS(&vals_ctype), 0x0, "COAP Media Type", HFILL }},
-           { &hf_coap_opt_max_age, { "Max-age", "coap.opt.maxage", FT_UINT32, BASE_DEC, NULL, 0x0, "COAP Max-age", HFILL }},
            { &hf_coap_opt_etag, { "Etag", "coap.opt.etag", FT_BYTES, BASE_NONE, NULL, 0x0, "COAP Etag", HFILL }},
            { &hf_coap_opt_uri_authority, { "Uri-Authority", "coap.opt.uri_auth", FT_STRING, BASE_NONE, NULL, 0x0, "COAP Uri-Authority", HFILL }},
            { &hf_coap_opt_location, { "Location", "coap.opt.location", FT_STRING, BASE_NONE, NULL, 0x0, "COAP Location", HFILL }},
            { &hf_coap_opt_uri_path, { "Uri-Path", "coap.opt.uri_path", FT_STRING, BASE_NONE, NULL, 0x0, "COAP Uri-Path", HFILL }},
+           { &hf_coap_opt_opaque_bytes, { "Opaque Bytes", "coap.opt.opaquebytes", FT_BYTES, BASE_NONE, NULL, 0x0, "COAP Opaque Bytes", HFILL }},
        };
 
        static gint *ett[] = {
@@ -365,6 +437,9 @@ proto_register_coap(void)
                &ett_coap_uri_authority,
                &ett_coap_location,
                &ett_coap_uri_path,
+               &ett_coap_subscr_lifetime,
+               &ett_coap_opaque_bytes,
+               &ett_coap_block,
                &ett_coap_payload,
        };