Call subdissectors even if we're not building a protocol tree.
[obnox/wireshark/wip.git] / packet-ipp.c
index 431e2f30afdfc6e9693cd71ff8db2dea4342ada7..5449fa99082e5dac3bb4a102356322bad67b52a3 100644 (file)
@@ -3,43 +3,38 @@
  *
  * Guy Harris <guy@alum.mit.edu>
  *
- * $Id: packet-ipp.c,v 1.6 2000/03/06 19:53:44 guy Exp $
+ * $Id: packet-ipp.c,v 1.34 2003/01/28 22:02:26 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
- * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #include <string.h>
 #include <ctype.h>
 
 #include <glib.h>
-#include "packet.h"
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include "packet-http.h"
 
 static int proto_ipp = -1;
 
@@ -47,6 +42,8 @@ static gint ett_ipp = -1;
 static gint ett_ipp_as = -1;
 static gint ett_ipp_attr = -1;
 
+static dissector_handle_t data_handle;
+
 #define        PRINT_JOB               0x0002
 #define        PRINT_URI               0x0003
 #define        VALIDATE_JOB            0x0004
@@ -141,54 +138,57 @@ static const value_string status_vals[] = {
     { 0,                                 NULL }
 };
 
-static int parse_attributes(const u_char *pd, int offset, frame_data *fd,
-    proto_tree *tree);
-static proto_tree *add_integer_tree(proto_tree *tree, const u_char *pd,
-    int offset, int name_length, guint value_length);
-static void add_integer_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, guint name_length, guint value_length);
-static proto_tree *add_octetstring_tree(proto_tree *tree, const u_char *pd,
-    int offset, int name_length, guint value_length);
-static void add_octetstring_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, guint name_length, guint value_length);
-static proto_tree *add_charstring_tree(proto_tree *tree, const u_char *pd,
-    int offset, int name_length, guint value_length);
-static void add_charstring_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, int name_length, guint value_length);
-static int add_value_head(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, int name_length, guint value_length);
-
-void dissect_ipp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+static int parse_attributes(tvbuff_t *tvb, int offset, proto_tree *tree);
+static proto_tree *add_integer_tree(proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length, guint8 tag);
+static void add_integer_value(gchar *tag_desc, proto_tree *tree,
+    tvbuff_t *tvb, int offset, int name_length, int value_length, guint8 tag);
+static proto_tree *add_octetstring_tree(proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length);
+static void add_octetstring_value(gchar *tag_desc, proto_tree *tree,
+    tvbuff_t *tvb, int offset, int name_length, int value_length);
+static proto_tree *add_charstring_tree(proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length);
+static void add_charstring_value(gchar *tag_desc, proto_tree *tree,
+    tvbuff_t *tvb, int offset, int name_length, int value_length);
+static int add_value_head(gchar *tag_desc, proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length);
+
+static void
+dissect_ipp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        proto_tree *ipp_tree;
        proto_item *ti;
-       gboolean is_request = (pi.destport == 631);
+       int offset = 0;
+       gboolean is_request = (pinfo->destport == 631);
        guint16 status_code;
        gchar *status_fmt;
 
-       if (check_col(fd, COL_PROTOCOL))
-               col_add_str(fd, COL_PROTOCOL, "IPP");
-       if (check_col(fd, COL_INFO)) {
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPP");
+       if (check_col(pinfo->cinfo, COL_INFO)) {
                if (is_request)
-                       col_add_str(fd, COL_INFO, "IPP request");
+                       col_set_str(pinfo->cinfo, COL_INFO, "IPP request");
                else
-                       col_add_str(fd, COL_INFO, "IPP response");
+                       col_set_str(pinfo->cinfo, COL_INFO, "IPP response");
        }
 
        if (tree) {
-               ti = proto_tree_add_item(tree, proto_ipp, offset, END_OF_FRAME, NULL);
+               ti = proto_tree_add_item(tree, proto_ipp, tvb, offset, -1,
+                   FALSE);
                ipp_tree = proto_item_add_subtree(ti, ett_ipp);
 
-               proto_tree_add_text(ipp_tree, offset, 2, "Version: %u.%u",
-                   pd[offset], pd[offset + 1]);
+               proto_tree_add_text(ipp_tree, tvb, offset, 2, "Version: %u.%u",
+                   tvb_get_guint8(tvb, offset),
+                   tvb_get_guint8(tvb, offset + 1));
                offset += 2;
 
                if (is_request) {
-                       proto_tree_add_text(ipp_tree, offset, 2, "Operation-id: %s",
-                           val_to_str(pntohs(&pd[offset]), operation_vals,
+                       proto_tree_add_text(ipp_tree, tvb, offset, 2, "Operation-id: %s",
+                           val_to_str(tvb_get_ntohs(tvb, offset), operation_vals,
                                "Unknown (0x%04x)"));
                } else {
-                       status_code = pntohs(&pd[offset]);
+                       status_code = tvb_get_ntohs(tvb, offset);
                        switch (status_code & STATUS_TYPE_MASK) {
 
                        case STATUS_SUCCESSFUL:
@@ -215,19 +215,22 @@ void dissect_ipp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                                status_fmt = "Unknown (0x%04x)";
                                break;
                        }
-                       proto_tree_add_text(ipp_tree, offset, 2, "Status-code: %s",
+                       proto_tree_add_text(ipp_tree, tvb, offset, 2, "Status-code: %s",
                            val_to_str(status_code, status_vals, status_fmt));
                }
                offset += 2;
 
-               proto_tree_add_text(ipp_tree, offset, 4, "Request ID: %u",
-                   pntohl(&pd[offset]));
+               proto_tree_add_text(ipp_tree, tvb, offset, 4, "Request ID: %u",
+                   tvb_get_ntohl(tvb, offset));
                offset += 4;
 
-               offset = parse_attributes(pd, offset, fd, ipp_tree);
+               offset = parse_attributes(tvb, offset, ipp_tree);
 
-               if (IS_DATA_IN_FRAME(offset))
-                       dissect_data(pd, offset, fd, ipp_tree);
+               if (tvb_offset_exists(tvb, offset)) {
+                       call_dissector(data_handle,
+                           tvb_new_subset(tvb, offset, -1, -1), pinfo,
+                           ipp_tree);
+               }
        }
 }
 
@@ -292,18 +295,18 @@ static const value_string tag_vals[] = {
 };
 
 static int
-parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+parse_attributes(tvbuff_t *tvb, int offset, proto_tree *tree)
 {
        guint8 tag;
        gchar *tag_desc;
-       guint16 name_length, value_length;
+       int name_length, value_length;
        proto_tree *as_tree = tree;
        proto_item *tas = NULL;
        int start_offset = offset;
        proto_tree *attr_tree = tree;
 
-       while (IS_DATA_IN_FRAME(offset)) {
-               tag = pd[offset];
+       while (tvb_offset_exists(tvb, offset)) {
+               tag = tvb_get_guint8(tvb, offset);
                tag_desc = val_to_str(tag, tag_vals, "Reserved (0x%02x)");
                if (TAG_TYPE(tag) == TAG_TYPE_DELIMITER) {
                        /*
@@ -334,7 +337,7 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                        /*
                         * Now create a new item for this tag.
                         */
-                       tas = proto_tree_add_text(tree, offset, 1,
+                       tas = proto_tree_add_text(tree, tvb, offset, 1,
                            "%s", tag_desc);
                        offset++;
                        if (tag == TAG_END_OF_ATTRIBUTES) {
@@ -347,42 +350,17 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                        /*
                         * Value tag - get the name length.
                         */
-                       if (!BYTES_ARE_IN_FRAME(offset + 1, 2)) {
-                               /*
-                                * We ran past the end of the frame.
-                                * Quit (we need to be able to handle
-                                * stuff that crosses frames to do more)
-                                */
-                               break;
-                       }
-                       name_length = pntohs(&pd[offset + 1]);
+                       name_length = tvb_get_ntohs(tvb, offset + 1);
 
                        /*
                         * OK, get the value length.
                         */
-                       if (!BYTES_ARE_IN_FRAME(offset + 1 + 2, name_length)) {
-                               /*
-                                * We ran past the end of the frame.
-                                * Quit (we need to be able to handle
-                                * stuff that crosses frames to do more)
-                                */
-                               break;
-                       }
-                       value_length = pntohs(&pd[offset + 1 + 2 + name_length]);
+                       value_length = tvb_get_ntohs(tvb, offset + 1 + 2 + name_length);
 
                        /*
                         * OK, does the value run past the end of the
                         * frame?
                         */
-                       if (!BYTES_ARE_IN_FRAME(offset + 1 + 2 + name_length + 2,
-                           value_length)) {
-                               /*
-                                * We ran past the end of the frame.
-                                * Quit (we need to be able to handle
-                                * stuff that crosses frames to do more)
-                                */
-                               break;
-                       }
                        if (as_tree == NULL) {
                                /*
                                 * OK, there's an attribute to hang
@@ -405,11 +383,11 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                                         * start a tree for it.
                                         */
                                        attr_tree = add_integer_tree(as_tree,
-                                           pd, offset, name_length,
-                                           value_length);
+                                           tvb, offset, name_length,
+                                           value_length, tag);
                                }
-                               add_integer_value(tag, tag_desc, attr_tree, pd,
-                                   offset, name_length, value_length);
+                               add_integer_value(tag_desc, attr_tree, tvb,
+                                   offset, name_length, value_length, tag);
                                break;
 
                        case TAG_TYPE_OCTETSTRING:
@@ -420,12 +398,11 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                                         * start a tree for it.
                                         */
                                        attr_tree = add_octetstring_tree(as_tree,
-                                           pd, offset, name_length,
+                                           tvb, offset, name_length,
                                            value_length);
                                }
-                               add_octetstring_value(tag, tag_desc,
-                                   attr_tree, pd, offset, name_length,
-                                   value_length);
+                               add_octetstring_value(tag_desc, attr_tree, tvb,
+                                   offset, name_length, value_length);
                                break;
 
                        case TAG_TYPE_CHARSTRING:
@@ -436,12 +413,11 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
                                         * start a tree for it.
                                         */
                                        attr_tree = add_charstring_tree(as_tree,
-                                           pd, offset, name_length,
+                                           tvb, offset, name_length,
                                            value_length);
                                }
-                               add_charstring_value(tag, tag_desc,
-                                   attr_tree, pd, offset, name_length,
-                                   value_length);
+                               add_charstring_value(tag_desc, attr_tree, tvb,
+                                   offset, name_length, value_length);
                                break;
                        }
                        offset += 1 + 2 + name_length + 2 + value_length;
@@ -451,104 +427,169 @@ parse_attributes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
        return offset;
 }
 
+static const value_string bool_vals[] = {
+       { 0x00, "false" },
+       { 0x01, "true" },
+       { 0,    NULL }
+};
+
 static proto_tree *
-add_integer_tree(proto_tree *tree, const u_char *pd, int offset,
-    int name_length, guint value_length)
+add_integer_tree(proto_tree *tree, tvbuff_t *tvb, int offset,
+    int name_length, int value_length, guint8 tag)
 {
        proto_item *ti;
+       guint8 bool_val;
+
+       switch (tag) {
+
+       case TAG_BOOLEAN:
+               if (value_length != 1) {
+                       ti = proto_tree_add_text(tree, tvb, offset,
+                           1 + 2 + name_length + 2 + value_length,
+                           "%.*s: Invalid boolean (length is %u, should be 1)",
+                           name_length,
+                           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+                           value_length);
+               } else {
+                       bool_val = tvb_get_guint8(tvb,
+                           offset + 1 + 2 + name_length + 2);
+                       ti = proto_tree_add_text(tree, tvb, offset,
+                           1 + 2 + name_length + 2 + value_length,
+                           "%.*s: %s",
+                           name_length,
+                           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+                           val_to_str(bool_val, bool_vals, "Unknown (0x%02x)"));
+               }
+               break;
+
+       case TAG_INTEGER:
+       case TAG_ENUM:
+               if (value_length != 4) {
+                       ti = proto_tree_add_text(tree, tvb, offset,
+                           1 + 2 + name_length + 2 + value_length,
+                           "%.*s: Invalid integer (length is %u, should be 4)",
+                           name_length,
+                           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+                           value_length);
+               } else {
+                       ti = proto_tree_add_text(tree, tvb, offset,
+                           1 + 2 + name_length + 2 + value_length,
+                           "%.*s: %u",
+                           name_length,
+                           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+                           tvb_get_ntohl(tvb, offset + 1 + 2 + name_length + 2));
+               }
+               break;
 
-       if (value_length != 4) {
-               ti = proto_tree_add_text(tree, offset,
-                   1 + 2 + name_length + 2 + value_length,
-                   "%.*s: Invalid integer (length is %u, should be 4)",
-                   name_length, &pd[offset + 1 + 2],
-                   value_length);
-       } else {
-               ti = proto_tree_add_text(tree, offset,
+       default:
+               ti = proto_tree_add_text(tree, tvb, offset,
                    1 + 2 + name_length + 2 + value_length,
-                   "%.*s: %u",
-                   name_length, &pd[offset + 1 + 2],
-                   pntohl(&pd[offset + 1 + 2 + name_length + 2]));
+                   "%.*s: Unknown integer type 0x%02x",
+                   name_length,
+                   tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+                   tag);
+               break;
        }
        return proto_item_add_subtree(ti, ett_ipp_attr);
 }
 
 static void
-add_integer_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, guint name_length, guint value_length)
+add_integer_value(gchar *tag_desc, proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length, guint8 tag)
 {
-       offset = add_value_head(tag, tag_desc, tree, pd, offset,
-           name_length, value_length);
-       if (value_length == 4) {
-               proto_tree_add_text(tree, offset, value_length,
-                   "Value: %u", pntohl(&pd[offset]));
+       guint8 bool_val;
+
+       offset = add_value_head(tag_desc, tree, tvb, offset, name_length,
+           value_length);
+
+       switch (tag) {
+
+       case TAG_BOOLEAN:
+               if (value_length == 1) {
+                       bool_val = tvb_get_guint8(tvb, offset);
+                       proto_tree_add_text(tree, tvb, offset, value_length,
+                           "Value: %s",
+                           val_to_str(bool_val, bool_vals, "Unknown (0x%02x)"));
+               }
+               break;
+
+       case TAG_INTEGER:
+       case TAG_ENUM:
+               if (value_length == 4) {
+                       proto_tree_add_text(tree, tvb, offset, value_length,
+                           "Value: %u", tvb_get_ntohl(tvb, offset));
+               }
+               break;
        }
 }
 
 static proto_tree *
-add_octetstring_tree(proto_tree *tree, const u_char *pd, int offset,
-    int name_length, guint value_length)
+add_octetstring_tree(proto_tree *tree, tvbuff_t *tvb, int offset,
+    int name_length, int value_length)
 {
        proto_item *ti;
 
-       ti = proto_tree_add_text(tree, offset,
+       ti = proto_tree_add_text(tree, tvb, offset,
            1 + 2 + name_length + 2 + value_length,
            "%.*s: %s",
            name_length,
-           &pd[offset + 1 + 2],
-           bytes_to_str(&pd[offset + 1 + 2 + name_length + 2], value_length));
+           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+           tvb_bytes_to_str(tvb, offset + 1 + 2 + name_length + 2, value_length));
        return proto_item_add_subtree(ti, ett_ipp_attr);
 }
 
 static void
-add_octetstring_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, guint name_length, guint value_length)
+add_octetstring_value(gchar *tag_desc, proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length)
 {
-       offset = add_value_head(tag, tag_desc, tree, pd, offset,
-           name_length, value_length);
-       proto_tree_add_text(tree, offset, value_length,
-           "Value: %s", bytes_to_str(&pd[offset], value_length));
+       offset = add_value_head(tag_desc, tree, tvb, offset, name_length,
+           value_length);
+       proto_tree_add_text(tree, tvb, offset, value_length,
+           "Value: %s", tvb_bytes_to_str(tvb, offset, value_length));
 }
 
 static proto_tree *
-add_charstring_tree(proto_tree *tree, const u_char *pd, int offset,
-    int name_length, guint value_length)
+add_charstring_tree(proto_tree *tree, tvbuff_t *tvb, int offset,
+    int name_length, int value_length)
 {
        proto_item *ti;
 
-       ti = proto_tree_add_text(tree, offset,
+       ti = proto_tree_add_text(tree, tvb, offset,
            1 + 2 + name_length + 2 + value_length,
            "%.*s: %.*s",
-           name_length, &pd[offset + 1 + 2],
-           value_length, &pd[offset + 1 + 2 + name_length + 2]);
+           name_length,
+           tvb_get_ptr(tvb, offset + 1 + 2, name_length),
+           value_length,
+           tvb_get_ptr(tvb, offset + 1 + 2 + name_length + 2, value_length));
        return proto_item_add_subtree(ti, ett_ipp_attr);
 }
 
 static void
-add_charstring_value(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, int name_length, guint value_length)
+add_charstring_value(gchar *tag_desc, proto_tree *tree, tvbuff_t *tvb,
+    int offset, int name_length, int value_length)
 {
-       offset = add_value_head(tag, tag_desc, tree, pd, offset,
-           name_length, value_length);
-       proto_tree_add_text(tree, offset, value_length,
-           "Value: %.*s", value_length, &pd[offset]);
+       offset = add_value_head(tag_desc, tree, tvb, offset, name_length,
+           value_length);
+       proto_tree_add_text(tree, tvb, offset, value_length,
+           "Value: %.*s", value_length, tvb_get_ptr(tvb, offset, value_length));
 }
 
 static int
-add_value_head(guint tag, gchar *tag_desc, proto_tree *tree,
-    const u_char *pd, int offset, int name_length, guint value_length)
+add_value_head(gchar *tag_desc, proto_tree *tree, tvbuff_t *tvb, int offset,
+    int name_length, int value_length)
 {
-       proto_tree_add_text(tree, offset, 1, "Tag: %s", tag_desc);
+       proto_tree_add_text(tree, tvb, offset, 1, "Tag: %s", tag_desc);
        offset += 1;
-       proto_tree_add_text(tree, offset, 2, "Name length: %u",
+       proto_tree_add_text(tree, tvb, offset, 2, "Name length: %u",
            name_length);
        offset += 2;
        if (name_length != 0) {
-               proto_tree_add_text(tree, offset, name_length,
-                   "Name: %.*s", name_length, &pd[offset]);
+               proto_tree_add_text(tree, tvb, offset, name_length,
+                   "Name: %.*s", name_length,
+                   tvb_get_ptr(tvb, offset, name_length));
        }
        offset += name_length;
-       proto_tree_add_text(tree, offset, 2, "Value length: %u",
+       proto_tree_add_text(tree, tvb, offset, 2, "Value length: %u",
            value_length);
        offset += 2;
        return offset;
@@ -567,7 +608,21 @@ proto_register_ipp(void)
                &ett_ipp_attr,
        };
 
-        proto_ipp = proto_register_protocol("Internet Printing Protocol", "ipp");
+        proto_ipp = proto_register_protocol("Internet Printing Protocol",
+           "IPP", "ipp");
  /*       proto_register_field_array(proto_ipp, hf, array_length(hf));*/
        proto_register_subtree_array(ett, array_length(ett));
 }
+
+void
+proto_reg_handoff_ipp(void)
+{
+       dissector_handle_t ipp_handle;
+
+       /*
+        * Register ourselves as running atop HTTP and using port 631.
+        */
+       ipp_handle = create_dissector_handle(dissect_ipp, proto_ipp);
+       http_dissector_add(631, ipp_handle);
+        data_handle = find_dissector("data");
+}