Add a routine to "epan/filesystem.c" to test whether a file is a FIFO.
[obnox/wireshark/wip.git] / packet-atm.c
index 4fce2749fe270229c6a120e8dc2d9e29782bb855..889264aa2f43c7204533e90b74744d70da19c3e9 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-atm.c
  * Routines for ATM packet disassembly
  *
- * $Id: packet-atm.c,v 1.43 2002/04/30 18:58:14 guy Exp $
+ * $Id: packet-atm.c,v 1.47 2002/06/07 21:11:22 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include "oui.h"
 #include <epan/resolv.h>
 
+#include "packet-atm.h"
 #include "packet-snmp.h"
+#include "packet-eth.h"
+#include "packet-tr.h"
+#include "packet-llc.h"
 
 static int proto_atm = -1;
 static int hf_atm_vpi = -1;
@@ -86,6 +90,8 @@ static dissector_handle_t data_handle;
 #define LE_FLUSH_RESPONSE      0x0107
 #define LE_NARP_REQUEST                0x0008
 #define LE_TOPOLOGY_REQUEST    0x0009
+#define LE_VERIFY_REQUEST      0x000A
+#define LE_VERIFY_RESPONSE     0x010A
 
 static const value_string le_control_opcode_vals[] = {
        { LE_CONFIGURE_REQUEST,   "LE_CONFIGURE_REQUEST" },
@@ -104,6 +110,8 @@ static const value_string le_control_opcode_vals[] = {
        { LE_FLUSH_RESPONSE,      "LE_FLUSH_RESPONSE" },
        { LE_NARP_REQUEST,        "LE_NARP_REQUEST" },
        { LE_TOPOLOGY_REQUEST,    "LE_TOPOLOGY_REQUEST" },
+       { LE_VERIFY_REQUEST,      "LE_VERIFY_REQUEST" },
+       { LE_VERIFY_RESPONSE,     "LE_VERIFY_RESPONSE" },
        { 0,                      NULL }
 };
 
@@ -122,6 +130,7 @@ static const value_string le_control_status_vals[] = {
        { 20, "No configuraton" },
        { 21, "LE_CONFIGURE error" },
        { 22, "Insufficient information" },
+       { 24, "TLV not found" },
        { 0,  NULL }
 };
 
@@ -149,6 +158,15 @@ static const value_string le_control_lan_type_vals[] = {
        { 0,           NULL }
 };
 
+static const value_string le_control_frame_size_vals[] = {
+       { 0x00, "Unspecified" },
+       { 0x01, "1516/1528/1580/1592" },
+       { 0x02, "4544/4556/1580/1592" },
+       { 0x03, "9234/9246" },
+       { 0x04, "18190/18202" },
+       { 0,    NULL }
+};
+
 static void
 dissect_le_client(tvbuff_t *tvb, proto_tree *tree)
 {
@@ -226,6 +244,13 @@ dissect_lan_destination(tvbuff_t *tvb, int offset, const char *type, proto_tree
 #define        LE_MCAST_SEND_VCC_AVGRATE       TLV_TYPE(OUI_ATM_FORUM, 0x0D)
 #define        LE_MCAST_SEND_VCC_PEAKRATE      TLV_TYPE(OUI_ATM_FORUM, 0x0E)
 #define        LE_CONN_COMPLETION_TIMER        TLV_TYPE(OUI_ATM_FORUM, 0x0F)
+#define        LE_CONFIG_FRAG_INFO             TLV_TYPE(OUI_ATM_FORUM, 0x10)
+#define        LE_LAYER_3_ADDRESS              TLV_TYPE(OUI_ATM_FORUM, 0x11)
+#define        LE_ELAN_ID                      TLV_TYPE(OUI_ATM_FORUM, 0x12)
+#define        LE_SERVICE_CATEGORY             TLV_TYPE(OUI_ATM_FORUM, 0x13)
+#define        LE_LLC_MUXED_ATM_ADDRESS        TLV_TYPE(OUI_ATM_FORUM, 0x2B)
+#define        LE_X5_ADJUSTMENT                TLV_TYPE(OUI_ATM_FORUM, 0x2C)
+#define        LE_PREFERRED_LES                TLV_TYPE(OUI_ATM_FORUM, 0x2D)
 
 static const value_string le_tlv_type_vals[] = {
        { LE_CONTROL_TIMEOUT,           "Control Time-out" },
@@ -243,9 +268,200 @@ static const value_string le_tlv_type_vals[] = {
        { LE_MCAST_SEND_VCC_AVGRATE,    "Mcast Send VCC AvgRate" },
        { LE_MCAST_SEND_VCC_PEAKRATE,   "Mcast Send VCC PeakRate" },
        { LE_CONN_COMPLETION_TIMER,     "Connection Completion Timer" },
+       { LE_CONFIG_FRAG_INFO,          "Config Frag Info" },
+       { LE_LAYER_3_ADDRESS,           "Layer 3 Address" },
+       { LE_ELAN_ID,                   "ELAN ID" },
+       { LE_SERVICE_CATEGORY,          "Service Category" },
+       { LE_LLC_MUXED_ATM_ADDRESS,     "LLC-muxed ATM Address" },
+       { LE_X5_ADJUSTMENT,             "X5 Adjustment" },
+       { LE_PREFERRED_LES,             "Preferred LES" },
        { 0,                            NULL },
 };
 
+static void
+dissect_le_control_tlvs(tvbuff_t *tvb, int offset, guint num_tlvs,
+                       proto_tree *tree)
+{
+  guint32 tlv_type;
+  guint8 tlv_length;
+  proto_item *ttlv;
+  proto_tree *tlv_tree;
+
+  while (num_tlvs != 0) {
+    tlv_type = tvb_get_ntohl(tvb, offset);
+    tlv_length = tvb_get_guint8(tvb, offset+4);
+    ttlv = proto_tree_add_text(tree, tvb, offset, 5+tlv_length, "TLV type: %s",
+       val_to_str(tlv_type, le_tlv_type_vals, "Unknown (0x%08x)"));
+    tlv_tree = proto_item_add_subtree(ttlv, ett_atm_lane_lc_tlv);
+    proto_tree_add_text(tlv_tree, tvb, offset, 4, "TLV Type: %s",
+       val_to_str(tlv_type, le_tlv_type_vals, "Unknown (0x%08x)"));
+    proto_tree_add_text(tlv_tree, tvb, offset+4, 1, "TLV Length: %u", tlv_length);
+    offset += 5+tlv_length;
+    num_tlvs--;
+  }
+}
+
+static void
+dissect_le_configure_join_frame(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+  guint8 num_tlvs;
+  guint8 name_size;
+
+  dissect_lan_destination(tvb, offset, "Source", tree);
+  offset += 8;
+
+  dissect_lan_destination(tvb, offset, "Target", tree);
+  offset += 8;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Source ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  proto_tree_add_text(tree, tvb, offset, 1, "LAN type: %s",
+       val_to_str(tvb_get_guint8(tvb, offset), le_control_lan_type_vals,
+                               "Unknown (0x%02X)"));
+  offset += 1;
+
+  proto_tree_add_text(tree, tvb, offset, 1, "Maximum frame size: %s",
+       val_to_str(tvb_get_guint8(tvb, offset), le_control_frame_size_vals,
+                               "Unknown (0x%02X)"));
+  offset += 1;
+
+  num_tlvs = tvb_get_guint8(tvb, offset);
+  proto_tree_add_text(tree, tvb, offset, 1, "Number of TLVs: %u", num_tlvs);
+  offset += 1;
+
+  name_size = tvb_get_guint8(tvb, offset);
+  proto_tree_add_text(tree, tvb, offset, 1, "ELAN name size: %u", name_size);
+  offset += 1;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Target ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  if (name_size > 32)
+    name_size = 32;
+  if (name_size != 0) {
+    proto_tree_add_text(tree, tvb, offset, name_size, "ELAN name: %s",
+                       tvb_bytes_to_str(tvb, offset, name_size));
+  }
+  offset += 32;
+
+  dissect_le_control_tlvs(tvb, offset, num_tlvs, tree);
+}
+
+static void
+dissect_le_registration_frame(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+  guint8 num_tlvs;
+
+  dissect_lan_destination(tvb, offset, "Source", tree);
+  offset += 8;
+
+  dissect_lan_destination(tvb, offset, "Target", tree);
+  offset += 8;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Source ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 2;
+
+  num_tlvs = tvb_get_guint8(tvb, offset);
+  proto_tree_add_text(tree, tvb, offset, 1, "Number of TLVs: %u", num_tlvs);
+  offset += 1;
+
+  /* Reserved */
+  offset += 53;
+
+  dissect_le_control_tlvs(tvb, offset, num_tlvs, tree);
+}
+
+static void
+dissect_le_arp_frame(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+  guint8 num_tlvs;
+
+  dissect_lan_destination(tvb, offset, "Source", tree);
+  offset += 8;
+
+  dissect_lan_destination(tvb, offset, "Target", tree);
+  offset += 8;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Source ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 2;
+
+  num_tlvs = tvb_get_guint8(tvb, offset);
+  proto_tree_add_text(tree, tvb, offset, 1, "Number of TLVs: %u", num_tlvs);
+  offset += 1;
+
+  /* Reserved */
+  offset += 1;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Target ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 32;
+
+  dissect_le_control_tlvs(tvb, offset, num_tlvs, tree);
+}
+
+static void
+dissect_le_verify_frame(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+  guint8 num_tlvs;
+
+  /* Reserved */
+  offset += 38;
+
+  num_tlvs = tvb_get_guint8(tvb, offset);
+  proto_tree_add_text(tree, tvb, offset, 1, "Number of TLVs: %u", num_tlvs);
+  offset += 1;
+
+  /* Reserved */
+  offset += 1;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Target ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 32;
+
+  dissect_le_control_tlvs(tvb, offset, num_tlvs, tree);
+}
+
+static void
+dissect_le_flush_frame(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+  dissect_lan_destination(tvb, offset, "Source", tree);
+  offset += 8;
+
+  dissect_lan_destination(tvb, offset, "Target", tree);
+  offset += 8;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Source ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 4;
+
+  proto_tree_add_text(tree, tvb, offset, 20, "Target ATM Address: %s",
+                     tvb_bytes_to_str(tvb, offset, 20));
+  offset += 20;
+
+  /* Reserved */
+  offset += 32;
+}
+
 static void
 dissect_le_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -254,13 +470,8 @@ dissect_le_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   int offset = 0;
   proto_item *tf;
   proto_tree *flags_tree;
-  proto_item *ttlv;
-  proto_tree *tlv_tree;
   guint16 opcode;
   guint16 flags;
-  guint8 num_tlvs;
-  guint32 tlv_type;
-  guint8 tlv_length;
 
   if (check_col(pinfo->cinfo, COL_INFO))
     col_set_str(pinfo->cinfo, COL_INFO, "LE Control");
@@ -325,65 +536,108 @@ dissect_le_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     tf = proto_tree_add_text(lane_tree, tvb, offset, 2, "Flags: 0x%04X",
                        flags);
     flags_tree = proto_item_add_subtree(tf, ett_atm_lane_lc_flags);
-    proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
-       decode_boolean_bitfield(flags, 0x0001, 8*2,
-                               "Remote address", "Local address"));
-    proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+
+    switch (opcode) {
+
+    case LE_CONFIGURE_REQUEST:
+    case LE_CONFIGURE_RESPONSE:
+      proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+       decode_boolean_bitfield(flags, 0x0002, 8*2,
+                               "V2 capable", "Not V2 capable"));
+      offset += 2;
+      dissect_le_configure_join_frame(tvb, offset, lane_tree);
+      break;
+
+    case LE_JOIN_REQUEST:
+    case LE_JOIN_RESPONSE:
+      proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+       decode_boolean_bitfield(flags, 0x0002, 8*2,
+                               "V2 capable", "Not V2 capable"));
+      if (opcode == LE_JOIN_REQUEST) {
+        proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+               decode_boolean_bitfield(flags, 0x0004, 8*2,
+                               "Selective multicast", "No selective multicast"));
+      } else {
+        proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+               decode_boolean_bitfield(flags, 0x0008, 8*2,
+                               "V2 required", "V2 not required"));
+      }
+      proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
        decode_boolean_bitfield(flags, 0x0080, 8*2,
                                "Proxy", "Not proxy"));
-    proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
-       decode_boolean_bitfield(flags, 0x0100, 8*2,
-                               "Topology change", "No topology change"));
-    offset += 2;
-
-    dissect_lan_destination(tvb, offset, "Source", lane_tree);
-    offset += 8;
+      proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+       decode_boolean_bitfield(flags, 0x0200, 8*2,
+                               "Exclude explorer frames",
+                               "Don't exclude explorer frames"));
+      offset += 2;
+      dissect_le_configure_join_frame(tvb, offset, lane_tree);
+      break;
 
-    dissect_lan_destination(tvb, offset, "Target", lane_tree);
-    offset += 8;
+    case LE_REGISTER_REQUEST:
+    case LE_REGISTER_RESPONSE:
+    case LE_UNREGISTER_REQUEST:
+    case LE_UNREGISTER_RESPONSE:
+      offset += 2;
+      dissect_le_registration_frame(tvb, offset, lane_tree);
+      break;
 
-    proto_tree_add_text(lane_tree, tvb, offset, 20, "Source ATM Address: %s",
-                       tvb_bytes_to_str(tvb, offset, 20));
-    offset += 20;
+    case LE_ARP_REQUEST:
+    case LE_ARP_RESPONSE:
+    case LE_NARP_REQUEST:
+      if (opcode != LE_NARP_REQUEST) {
+        proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+               decode_boolean_bitfield(flags, 0x0001, 8*2,
+                               "Remote address", "Local address"));
+      }
+      offset += 2;
+      dissect_le_arp_frame(tvb, offset, lane_tree);
+      break;
 
-    proto_tree_add_text(lane_tree, tvb, offset, 1, "LAN type: %s",
-       val_to_str(tvb_get_guint8(tvb, offset), le_control_lan_type_vals,
-                               "Unknown (0x%02X)"));
-    offset += 1;
+    case LE_TOPOLOGY_REQUEST:
+      proto_tree_add_text(flags_tree, tvb, offset, 2, "%s",
+       decode_boolean_bitfield(flags, 0x0100, 8*2,
+                               "Topology change", "No topology change"));
+      offset += 2;
+      /* 92 reserved bytes */
+      break;
 
-    proto_tree_add_text(lane_tree, tvb, offset, 1, "Maximum frame size: %u",
-                       tvb_get_guint8(tvb, offset));
-    offset += 1;
+    case LE_VERIFY_REQUEST:
+    case LE_VERIFY_RESPONSE:
+      offset += 2;
+      dissect_le_verify_frame(tvb, offset, lane_tree);
+      break;
 
-    num_tlvs = tvb_get_guint8(tvb, offset);
-    proto_tree_add_text(lane_tree, tvb, offset, 1, "Number of TLVs: %u",
-                       num_tlvs);
-    offset += 1;
+    case LE_FLUSH_REQUEST:
+    case LE_FLUSH_RESPONSE:
+      offset += 2;
+      dissect_le_flush_frame(tvb, offset, lane_tree);
+      break;
+    }
+  }
+}
 
-    proto_tree_add_text(lane_tree, tvb, offset, 1, "ELAN name size: %u",
-                       tvb_get_guint8(tvb, offset));
-    offset += 1;
+static void
+capture_lane(const union wtap_pseudo_header *pseudo_header, const u_char *pd,
+    int len, packet_counts *ld)
+{
+  /* Is it LE Control, 802.3, 802.5, or "none of the above"? */
+  switch (pseudo_header->atm.subtype) {
 
-    proto_tree_add_text(lane_tree, tvb, offset, 20, "Target ATM Address: %s",
-                       tvb_bytes_to_str(tvb, offset, 20));
-    offset += 20;
+  case TRAF_ST_LANE_802_3:
+  case TRAF_ST_LANE_802_3_MC:
+    /* Dissect as Ethernet */
+    capture_eth(pd, 2, len, ld);
+    break;
 
-    proto_tree_add_text(lane_tree, tvb, offset, 32, "ELAN name: %s",
-                       tvb_bytes_to_str(tvb, offset, 32));
-    offset += 32;
+  case TRAF_ST_LANE_802_5:
+  case TRAF_ST_LANE_802_5_MC:
+    /* Dissect as Token-Ring */
+    capture_tr(pd, 2, len, ld);
+    break;
 
-    while (num_tlvs != 0) {
-      tlv_type = tvb_get_ntohl(tvb, offset);
-      tlv_length = tvb_get_guint8(tvb, offset+4);
-      ttlv = proto_tree_add_text(lane_tree, tvb, offset, 5+tlv_length, "TLV type: %s",
-       val_to_str(tlv_type, le_tlv_type_vals, "Unknown (0x%08x)"));
-      tlv_tree = proto_item_add_subtree(ttlv, ett_atm_lane_lc_tlv);
-      proto_tree_add_text(tlv_tree, tvb, offset, 4, "TLV Type: %s",
-       val_to_str(tlv_type, le_tlv_type_vals, "Unknown (0x%08x)"));
-      proto_tree_add_text(tlv_tree, tvb, offset+4, 1, "TLV Length: %u", tlv_length);
-      offset += 5+tlv_length;
-      num_tlvs--;
-    }
+  default:
+    ld->other++;
+    break;
   }
 }
 
@@ -505,6 +759,32 @@ static const value_string ipsilon_type_vals[] = {
        { 0,                NULL }
 };
 
+void
+capture_atm(const union wtap_pseudo_header *pseudo_header, const u_char *pd,
+    int len, packet_counts *ld)
+{
+  if (pseudo_header->atm.aal == AAL_5) {
+    switch (pseudo_header->atm.type) {
+
+    case TRAF_LLCMX:
+      /* Dissect as WTAP_ENCAP_ATM_RFC1483 */
+      /* The ATM iptrace capture that we have shows LLC at this point,
+       * so that's what I'm calling */
+      capture_llc(pd, 0, len, ld);
+      break;
+
+    case TRAF_LANE:
+      capture_lane(pseudo_header, pd, len, ld);
+      break;
+
+    default:
+      ld->other++;
+      break;
+    }
+  } else
+    ld->other++;
+}
+
 static void
 dissect_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -558,10 +838,6 @@ dissect_atm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        "Unknown AAL5 traffic type (%u)"));
       switch (pinfo->pseudo_header->atm.type) {
 
-      case TRAF_LLCMX:
-        proto_tree_add_text(atm_tree, tvb, 0, 0, "LLC multiplexed traffic");
-        break;
-
       case TRAF_VCMX:
         proto_tree_add_text(atm_tree, tvb, 0, 0, "VC multiplexed traffic type: %s",
                val_to_str(pinfo->pseudo_header->atm.subtype,