Allow a length of -1 to be specified when adding FT_NONE and FT_PROTOCOL
[obnox/wireshark/wip.git] / packet-atalk.c
index 28cadc24734c76b20dda89fd2aedd099e6e676ef..918ca1a46a173c7eda4ce62e0151b9e27c888d97 100644 (file)
@@ -1,10 +1,14 @@
 /* packet-atalk.c
  * Routines for Appletalk packet disassembly (DDP, currently).
  *
- * $Id: packet-atalk.c,v 1.56 2001/11/26 01:03:35 hagbard Exp $
+ * $Id: packet-atalk.c,v 1.61 2002/01/20 22:12:25 guy Exp $
  *
  * Simon Wilkinson <sxw@dcs.ed.ac.uk>
  *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998
+ *
  * 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
 #include "aftypes.h"
 #include "atalk-utils.h"
 
+static int proto_llap = -1;
+static int hf_llap_dst = -1;
+static int hf_llap_src = -1;
+static int hf_llap_type = -1;
+
 static int proto_ddp = -1;
 static int hf_ddp_hopcount = -1;
 static int hf_ddp_len = -1;
@@ -81,12 +90,15 @@ static gint ett_nbp_node = -1;
 static gint ett_rtmp = -1;
 static gint ett_rtmp_tuple = -1;
 static gint ett_ddp = -1;
+static gint ett_llap = -1;
 static gint ett_pstring = -1;
 
 static dissector_table_t ddp_dissector_table;
 
 static dissector_handle_t data_handle;
 
+#define DDP_SHORT_HEADER_SIZE 5
+
 /*
  * P = Padding, H = Hops, L = Len
  *
@@ -183,15 +195,15 @@ dissect_rtmp_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   proto_item *ti;
   guint8 function;
 
-  if (check_col(pinfo->fd, COL_PROTOCOL))
-    col_set_str(pinfo->fd, COL_PROTOCOL, "RTMP");
-  if (check_col(pinfo->fd, COL_INFO))
-    col_clear(pinfo->fd, COL_INFO);
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   function = tvb_get_guint8(tvb, 0);
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_fstr(pinfo->fd, COL_INFO, "%s",
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
        val_to_str(function, rtmp_function_vals, "Unknown function (%02)"));
   
   if (tree) {
@@ -212,10 +224,10 @@ dissect_rtmp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   guint16 node; /* might be more than 8 bits */
   int i;
 
-  if (check_col(pinfo->fd, COL_PROTOCOL))
-    col_set_str(pinfo->fd, COL_PROTOCOL, "RTMP");
-  if (check_col(pinfo->fd, COL_INFO))
-    col_clear(pinfo->fd, COL_INFO);
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   net = tvb_get_ntohs(tvb, offset);
   nodelen_bits = tvb_get_guint8(tvb, offset+2);
@@ -227,13 +239,12 @@ dissect_rtmp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
     nodelen = 2;
   }
   
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_fstr(pinfo->fd, COL_INFO, "Net: %u  Node Len: %u  Node: %u",
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_fstr(pinfo->cinfo, COL_INFO, "Net: %u  Node Len: %u  Node: %u",
                net, nodelen_bits, node);
   
   if (tree) {
-    ti = proto_tree_add_item(tree, proto_rtmp, tvb, offset,
-                            tvb_length_remaining(tvb, offset), FALSE);
+    ti = proto_tree_add_item(tree, proto_rtmp, tvb, offset, -1, FALSE);
     rtmp_tree = proto_item_add_subtree(ti, ett_rtmp);
 
     proto_tree_add_uint(rtmp_tree, hf_rtmp_net, tvb, offset, 2, net);
@@ -300,22 +311,21 @@ dissect_nbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   guint op, count;
   unsigned int i;
 
-  if (check_col(pinfo->fd, COL_PROTOCOL))
-    col_set_str(pinfo->fd, COL_PROTOCOL, "NBP");
-  if (check_col(pinfo->fd, COL_INFO))
-    col_clear(pinfo->fd, COL_INFO);
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   info = tvb_get_guint8(tvb, offset);
   op = info >> 4;
   count = info & 0x0F;
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_fstr(pinfo->fd, COL_INFO, "Op: %s  Count: %u",
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_fstr(pinfo->cinfo, COL_INFO, "Op: %s  Count: %u",
       val_to_str(op, nbp_op_vals, "Unknown (0x%01x)"), count);
   
   if (tree) {
-    ti = proto_tree_add_item(tree, proto_nbp, tvb, offset,
-               tvb_length_remaining(tvb, offset), FALSE);
+    ti = proto_tree_add_item(tree, proto_nbp, tvb, offset, -1, FALSE);
     nbp_tree = proto_item_add_subtree(ti, ett_nbp);
 
     info_item = proto_tree_add_uint_format(nbp_tree, hf_nbp_info, tvb, offset, 1,
@@ -333,7 +343,7 @@ dissect_nbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
       proto_tree *node_item,*node_tree;
       int soffset = offset;
 
-      node_item = proto_tree_add_text(nbp_tree, tvb, offset, 4
+      node_item = proto_tree_add_text(nbp_tree, tvb, offset, -1
                        "Node %d", i+1);
       node_tree = proto_item_add_subtree(node_item, ett_nbp_node);
 
@@ -358,17 +368,76 @@ dissect_nbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 }
 
 static void
-dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+dissect_ddp_short(tvbuff_t *tvb, packet_info *pinfo, guint8 dnode,
+                 guint8 snode, proto_tree *tree)
+{
+  guint16 len;
+  guint8  dport;
+  guint8  sport;
+  guint8  type;
+  proto_tree *ddp_tree = NULL;
+  proto_item *ti;
+  static struct atalk_ddp_addr src, dst;
+  tvbuff_t   *new_tvb;
+
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
+
+  if (tree) {
+    ti = proto_tree_add_item(tree, proto_ddp, tvb, 0, DDP_SHORT_HEADER_SIZE,
+                            FALSE);
+    ddp_tree = proto_item_add_subtree(ti, ett_ddp);
+  }
+  len = tvb_get_ntohs(tvb, 0);
+  if (tree)
+      proto_tree_add_uint(ddp_tree, hf_ddp_len, tvb, 0, 2, len);
+  dport = tvb_get_guint8(tvb, 2);
+  if (tree)
+    proto_tree_add_uint(ddp_tree, hf_ddp_dst_socket, tvb, 2, 1, dport);
+  sport = tvb_get_guint8(tvb, 3);
+  if (tree)
+    proto_tree_add_uint(ddp_tree, hf_ddp_src_socket, tvb, 3, 1, sport);
+  type = tvb_get_guint8(tvb, 4);
+  
+  src.net = 0;
+  src.node = snode;
+  src.port = sport;
+  dst.net = 0;
+  dst.node = dnode;
+  dst.port = dport;
+  SET_ADDRESS(&pinfo->net_src, AT_ATALK, sizeof src, (guint8 *)&src);
+  SET_ADDRESS(&pinfo->src, AT_ATALK, sizeof src, (guint8 *)&src);
+  SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
+  SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
+
+  if (check_col(pinfo->cinfo, COL_INFO)) {
+    col_add_str(pinfo->cinfo, COL_INFO,
+      val_to_str(type, op_vals, "Unknown DDP protocol (%02x)"));
+  }
+  if (tree)
+    proto_tree_add_uint(ddp_tree, hf_ddp_type, tvb, 4, 1, type);
+  
+  new_tvb = tvb_new_subset(tvb, DDP_SHORT_HEADER_SIZE, -1, -1);
+
+  if (!dissector_try_port(ddp_dissector_table, type, new_tvb, pinfo, tree))
+    call_dissector(data_handle,new_tvb, pinfo, tree);
+}
+
+static void
+dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
   e_ddp       ddp;
   proto_tree *ddp_tree;
   proto_item *ti;
   static struct atalk_ddp_addr src, dst;
   tvbuff_t   *new_tvb;
 
-  if (check_col(pinfo->fd, COL_PROTOCOL))
-    col_set_str(pinfo->fd, COL_PROTOCOL, "DDP");
-  if (check_col(pinfo->fd, COL_INFO))
-    col_clear(pinfo->fd, COL_INFO);
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DDP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   tvb_memcpy(tvb, (guint8 *)&ddp, 0, sizeof(e_ddp));
   ddp.dnet=ntohs(ddp.dnet);
@@ -387,8 +456,8 @@ dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
   SET_ADDRESS(&pinfo->net_dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
   SET_ADDRESS(&pinfo->dst, AT_ATALK, sizeof dst, (guint8 *)&dst);
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_str(pinfo->fd, COL_INFO,
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_str(pinfo->cinfo, COL_INFO,
       val_to_str(ddp.type, op_vals, "Unknown DDP protocol (%02x)"));
   
   if (tree) {
@@ -423,9 +492,91 @@ dissect_ddp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
     call_dissector(data_handle,new_tvb, pinfo, tree);
 }
 
+static const value_string llap_type_vals[] = {
+  {0x01, "Short DDP"},
+  {0x02, "DDP" },
+  {0x81, "Enquiry"},
+  {0x82, "Acknowledgement"},
+  {0x84, "RTS"},
+  {0x85, "CTS"},
+  {0, NULL}
+};
+
+void
+capture_llap(const u_char *pd, int len, packet_counts *ld)
+{
+  ld->other++;
+}
+
+static void
+dissect_llap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  guint8 dnode;
+  guint8 snode;
+  guint8 type;
+  proto_tree *llap_tree = NULL;
+  proto_item *ti;
+  tvbuff_t   *new_tvb;
+
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLAP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
+
+  if (tree) {
+    ti = proto_tree_add_item(tree, proto_llap, tvb, 0, 3, FALSE);
+    llap_tree = proto_item_add_subtree(ti, ett_llap);
+  }
+
+  dnode = tvb_get_guint8(tvb, 0);
+  if (tree)  
+    proto_tree_add_uint(llap_tree, hf_llap_dst, tvb, 0, 1, dnode);
+  snode = tvb_get_guint8(tvb, 1);
+  if (tree)
+    proto_tree_add_uint(llap_tree, hf_llap_src, tvb, 1, 1, snode);
+  type = tvb_get_guint8(tvb, 2);
+  if (check_col(pinfo->cinfo, COL_INFO)) {
+    col_add_str(pinfo->cinfo, COL_INFO,
+      val_to_str(type, llap_type_vals, "Unknown LLAP type (%02x)"));
+  }
+  if (tree)
+    proto_tree_add_uint(llap_tree, hf_llap_type, tvb, 2, 1, type);
+  
+  new_tvb = tvb_new_subset(tvb, 3, -1, -1);
+
+  if (proto_is_protocol_enabled(proto_ddp)) {
+    pinfo->current_proto = "DDP";
+    switch (type) {
+
+    case 0x01:
+      dissect_ddp_short(new_tvb, pinfo, dnode, snode, tree);
+      return;
+
+    case 0x02:
+      dissect_ddp(new_tvb, pinfo, tree);
+      return;
+    }
+  }
+  call_dissector(data_handle,new_tvb, pinfo, tree);
+}
+
 void
 proto_register_atalk(void)
 {
+  static hf_register_info hf_llap[] = {
+    { &hf_llap_dst,
+      { "Destination Node",    "llap.dst",     FT_UINT8,  BASE_DEC, NULL, 0x0,
+       "", HFILL }},
+
+    { &hf_llap_src,
+      { "Source Node",         "llap.src",     FT_UINT8,  BASE_DEC, NULL, 0x0,
+       "", HFILL }},
+
+    { &hf_llap_type,
+      { "Type",                        "llap.type",    FT_UINT8,  BASE_HEX, VALS(llap_type_vals), 0x0,
+       "", HFILL }},
+  };
+
   static hf_register_info hf_ddp[] = {
     { &hf_ddp_hopcount,
       { "Hop count",           "ddp.hopcount", FT_UINT8,  BASE_DEC, NULL, 0x0,
@@ -533,6 +684,7 @@ proto_register_atalk(void)
 
 
   static gint *ett[] = {
+       &ett_llap,
        &ett_ddp,
        &ett_nbp,
        &ett_nbp_info,
@@ -542,6 +694,9 @@ proto_register_atalk(void)
        &ett_rtmp_tuple
   };
 
+  proto_llap = proto_register_protocol("LocalTalk Link Access Protocol", "LLAP", "llap");
+  proto_register_field_array(proto_llap, hf_llap, array_length(hf_llap));
+
   proto_ddp = proto_register_protocol("Datagram Delivery Protocol", "DDP", "ddp");
   proto_register_field_array(proto_ddp, hf_ddp, array_length(hf_ddp));
 
@@ -555,18 +710,32 @@ proto_register_atalk(void)
   proto_register_subtree_array(ett, array_length(ett));
 
   /* subdissector code */
-  ddp_dissector_table = register_dissector_table("ddp.type");
+  ddp_dissector_table = register_dissector_table("ddp.type", "DDP packet type",
+                                                FT_UINT8, BASE_HEX);
 }
 
 void
 proto_reg_handoff_atalk(void)
 {
-  dissector_add("ethertype", ETHERTYPE_ATALK, dissect_ddp, proto_ddp);
-  dissector_add("chdlctype", ETHERTYPE_ATALK, dissect_ddp, proto_ddp);
-  dissector_add("ppp.protocol", PPP_AT, dissect_ddp, proto_ddp);
-  dissector_add("null.type", BSD_AF_APPLETALK, dissect_ddp, proto_ddp);
-  dissector_add("ddp.type", DDP_NBP, dissect_nbp, proto_nbp);
-  dissector_add("ddp.type", DDP_RTMPREQ, dissect_rtmp_request, proto_rtmp);
-  dissector_add("ddp.type", DDP_RTMPDATA, dissect_rtmp_data, proto_rtmp);
+  dissector_handle_t ddp_handle, nbp_handle, rtmp_request_handle;
+  dissector_handle_t rtmp_data_handle, llap_handle;
+
+  ddp_handle = create_dissector_handle(dissect_ddp, proto_ddp);
+  dissector_add("ethertype", ETHERTYPE_ATALK, ddp_handle);
+  dissector_add("chdlctype", ETHERTYPE_ATALK, ddp_handle);
+  dissector_add("ppp.protocol", PPP_AT, ddp_handle);
+  dissector_add("null.type", BSD_AF_APPLETALK, ddp_handle);
+
+  nbp_handle = create_dissector_handle(dissect_nbp, proto_nbp);
+  dissector_add("ddp.type", DDP_NBP, nbp_handle);
+
+  rtmp_request_handle = create_dissector_handle(dissect_rtmp_request, proto_rtmp);
+  rtmp_data_handle = create_dissector_handle(dissect_rtmp_data, proto_rtmp);
+  dissector_add("ddp.type", DDP_RTMPREQ, rtmp_request_handle);
+  dissector_add("ddp.type", DDP_RTMPDATA, rtmp_data_handle);
+
+  llap_handle = create_dissector_handle(dissect_llap, proto_llap);
+  dissector_add("wtap_encap", WTAP_ENCAP_LOCALTALK, llap_handle);
+
   data_handle = find_dissector("data");
 }