Use MAC address documentation range in filter examples
[metze/wireshark/wip.git] / epan / dissectors / packet-esis.c
index ffb99e1bee4cd150ba25a1a15ed75377f0d83d6c..35142fb6e170ada90306497aeb85b99a4cbee112 100644 (file)
 
 #include "config.h"
 
-#include <glib.h>
 #include <epan/packet.h>
-#include <wsutil/pint.h>
+#include <epan/expert.h>
 #include <epan/nlpid.h>
 #include "packet-osi.h"
 #include "packet-osi-options.h"
-#include "packet-esis.h"
+
+/* The version we support is 1 */
+#define ESIS_REQUIRED_VERSION    1
+
+/* ESIS PDU types */
+#define ESIS_ESH_PDU    02
+#define ESIS_ISH_PDU    04
+#define ESIS_RD_PDU     06
+
+/* The length of the fixed part */
+#define ESIS_HDR_FIXED_LENGTH 9
 
 void proto_register_esis(void);
 void proto_reg_handoff_esis(void);
@@ -51,6 +60,7 @@ static int hf_esis_dal = -1;
 static int hf_esis_number_of_source_addresses = -1;
 static int hf_esis_netl = -1;
 static int hf_esis_sal = -1;
+static int hf_esis_sa = -1;
 static int hf_esis_bsnpal = -1;
 static int hf_esis_net = -1;
 static int hf_esis_da = -1;
@@ -58,6 +68,14 @@ static int hf_esis_bsnpa = -1;
 
 static gint ett_esis              = -1;
 static gint ett_esis_area_addr    = -1;
+static gint ett_esis_network      = -1;
+static gint ett_esis_dest_addr    = -1;
+static gint ett_esis_subnetwork   = -1;
+
+
+static expert_field ei_esis_version = EI_INIT;
+static expert_field ei_esis_length = EI_INIT;
+static expert_field ei_esis_type = EI_INIT;
 
 static const value_string esis_vals[] = {
   { ESIS_ESH_PDU, "ES HELLO"},
@@ -65,15 +83,6 @@ static const value_string esis_vals[] = {
   { ESIS_RD_PDU,  "RD REQUEST"},
   { 0,             NULL} };
 
-/* internal prototypes */
-
-static void esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb,
-                           proto_tree *treepd);
-static void esis_dissect_ish_pdu( guint8 len, tvbuff_t *tvb,
-                           proto_tree *tree);
-static void esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb,
-                           proto_tree *tree);
-
 /* ################## Descriptions ###########################################*/
 /* Parameters for the ESH PDU
  * Source Address Parameter:
@@ -123,48 +132,15 @@ static void esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb,
 /* ############################ Tool Functions ############################## */
 
 
-/* ############################## Dissection Functions ###################### */
-/*
- * Name: dissect_esis_unknown()
- *
- * Description:
- *   There was some error in the protocol and we are in unknown space
- *   here.  Add a tree item to cover the error and go on.  Note
- *   that we make sure we don't go off the end of the bleedin packet here!
- *
- *   This is just a copy of isis.c and isis.h, so I keep the stuff also
- *   and adapt the names to cover possible protocol errors! I've really no
- *   idea whether I need this or not.
- *
- * Input
- *   tvbuff_t *      : tvbuff with packet data.
- *   proto_tree *    : tree of display data.  May be NULL.
- *   char *          : format text
- *   subsequent args : arguments to format
- *
- * Output:
- *   void (may modify proto tree)
- */
 static void
-esis_dissect_unknown( tvbuff_t *tvb, proto_tree *tree, const char *fmat, ...){
-  va_list ap;
-
-  va_start(ap, fmat);
-  proto_tree_add_text_valist(tree, tvb, 0, -1, fmat, ap);
-  va_end(ap);
-}
+esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) {
+    proto_tree *esis_area_tree;
+    int         offset  = 0;
+    int         no_sa   = 0;
+    int         sal     = 0;
 
+    proto_item  *ti;
 
-static void
-esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) {
-  proto_tree *esis_area_tree;
-  int         offset  = 0;
-  int         no_sa   = 0;
-  int         sal     = 0;
-
-  proto_item  *ti;
-
-  if (tree) {
     offset += ESIS_HDR_FIXED_LENGTH;
 
     no_sa  = tvb_get_guint8(tvb, offset);
@@ -178,81 +154,77 @@ esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) {
       sal = (int) tvb_get_guint8(tvb, offset);
       proto_tree_add_uint_format_value(esis_area_tree, hf_esis_sal, tvb, offset, 1, sal, "%2u Octets", sal);
       offset++;
-      proto_tree_add_text(esis_area_tree, tvb, offset, sal,
-                          " SA: %s",
-                          print_nsap_net( tvb_get_ptr(tvb, offset, sal), sal ) );
+      proto_tree_add_string(esis_area_tree, hf_esis_sa, tvb, offset, sal, print_nsap_net(tvb, offset, sal ) );
       offset += sal;
       len    -= ( sal + 1 );
     }
-    dissect_osi_options( len, tvb, offset, tree );
-  }
+    dissect_osi_options( len, tvb, offset, tree, pinfo );
+
 } /* esis_dissect_esh_pdu */
 
 static void
-esis_dissect_ish_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) {
+esis_dissect_ish_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) {
 
-  int   offset  = 0;
-  int   netl    = 0;
+    int   offset  = 0;
+    int   netl    = 0;
+    proto_tree* network_tree;
 
-  if (tree) {
     offset += ESIS_HDR_FIXED_LENGTH;
 
     netl = (int) tvb_get_guint8(tvb, offset);
-    proto_tree_add_text( tree, tvb, offset, netl + 1,
+    network_tree = proto_tree_add_subtree( tree, tvb, offset, netl + 1, ett_esis_network, NULL,
                          "### Network Entity Title Section ###");
-    proto_tree_add_uint_format_value(tree, hf_esis_netl, tvb, offset++, 1, netl, "%2u Octets", netl);
-    proto_tree_add_string( tree, hf_esis_net, tvb, offset, netl, print_nsap_net( tvb_get_ptr(tvb, offset, netl), netl ) );
+    proto_tree_add_uint_format_value(network_tree, hf_esis_netl, tvb, offset++, 1, netl, "%2u Octets", netl);
+    proto_tree_add_string(network_tree, hf_esis_net, tvb, offset, netl, print_nsap_net( tvb, offset, netl ) );
     offset += netl;
     len    -= ( netl + 1 );
 
-    dissect_osi_options( len, tvb, offset, tree );
-  }
+    dissect_osi_options( len, tvb, offset, network_tree, pinfo );
 }
 
 static void
-esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) {
+esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) {
 
-  int   offset  = 0;
-  int   tmpl    = 0;
+    int   offset  = 0;
+    int   tmpl    = 0;
+    proto_tree *dest_tree, *subnet_tree, *network_tree;
 
-  if (tree) {
     offset += ESIS_HDR_FIXED_LENGTH;
 
     tmpl = (int) tvb_get_guint8(tvb, offset);
-    proto_tree_add_text( tree, tvb, offset, tmpl + 1,
+    dest_tree = proto_tree_add_subtree( tree, tvb, offset, tmpl + 1, ett_esis_dest_addr, NULL,
                          "### Destination Address Section ###" );
-    proto_tree_add_uint_format_value(tree, hf_esis_dal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl);
-    proto_tree_add_string( tree, hf_esis_da, tvb, offset, tmpl,
-                         print_nsap_net( tvb_get_ptr(tvb, offset, tmpl), tmpl ) );
+    proto_tree_add_uint_format_value(dest_tree, hf_esis_dal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl);
+    proto_tree_add_string( dest_tree, hf_esis_da, tvb, offset, tmpl,
+                         print_nsap_net( tvb, offset, tmpl ) );
     offset += tmpl;
     len    -= ( tmpl + 1 );
     tmpl    = (int) tvb_get_guint8(tvb, offset);
 
-    proto_tree_add_text( tree, tvb, offset, tmpl + 1,
+    subnet_tree = proto_tree_add_subtree( tree, tvb, offset, tmpl + 1, ett_esis_subnetwork, NULL,
                          "###  Subnetwork Address Section ###");
-    proto_tree_add_uint_format_value(tree, hf_esis_bsnpal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl);
-    proto_tree_add_item( tree, hf_esis_bsnpa, tvb, offset, tmpl, ENC_NA);
+    proto_tree_add_uint_format_value(subnet_tree, hf_esis_bsnpal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl);
+    proto_tree_add_item(subnet_tree, hf_esis_bsnpa, tvb, offset, tmpl, ENC_NA);
     offset += tmpl;
     len    -= ( tmpl + 1 );
     tmpl    = (int) tvb_get_guint8(tvb, offset);
 
     if ( 0 == tmpl ) {
-      proto_tree_add_text( tree, tvb, offset, 1,
+      network_tree = proto_tree_add_subtree( tree, tvb, offset, 1, ett_esis_network, NULL,
                            "### No Network Entity Title Section ###" );
       offset++;
       len--;
     }
     else {
-      proto_tree_add_text( tree, tvb, offset, 1,
+      network_tree = proto_tree_add_subtree( tree, tvb, offset, 1, ett_esis_network, NULL,
                            "### Network Entity Title Section ###" );
-      proto_tree_add_uint_format_value(tree, hf_esis_netl, tvb, offset++, 1, tmpl, "%2u Octets", tmpl );
-      proto_tree_add_string( tree, hf_esis_net, tvb, offset, tmpl,
-                           print_nsap_net( tvb_get_ptr(tvb, offset, tmpl), tmpl ) );
+      proto_tree_add_uint_format_value(network_tree, hf_esis_netl, tvb, offset++, 1, tmpl, "%2u Octets", tmpl );
+      proto_tree_add_string( network_tree, hf_esis_net, tvb, offset, tmpl,
+                           print_nsap_net( tvb, offset, tmpl ) );
       offset += tmpl;
       len    -= ( tmpl + 1 );
     }
-    dissect_osi_options( len, tvb, offset, tree );
-  }
+    dissect_osi_options( len, tvb, offset, network_tree, pinfo );
 }
 
 
@@ -273,64 +245,48 @@ esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) {
  */
 static void
 dissect_esis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
-  const char *pdu_type_string        = NULL;
-  const char *pdu_type_format_string = "PDU Type      : %s (R:%s%s%s)";
-  esis_hdr_t  ehdr;
-  proto_item *ti;
+  guint8 version, length;
+  proto_item *ti, *type_item;
   proto_tree *esis_tree    = NULL;
-  guint8      variable_len;
-  guint       tmp_uint     = 0;
+  guint8      variable_len, type;
+  guint16     holdtime, checksum;
   const char *cksum_status;
 
   col_set_str(pinfo->cinfo, COL_PROTOCOL, "ESIS");
   col_clear(pinfo->cinfo, COL_INFO);
 
-  tvb_memcpy(tvb, (guint8 *)&ehdr, 0, sizeof ehdr);
-
-  if (tree) {
     ti = proto_tree_add_item(tree, proto_esis, tvb, 0, -1, ENC_NA);
     esis_tree = proto_item_add_subtree(ti, ett_esis);
 
-    if (ehdr.esis_version != ESIS_REQUIRED_VERSION){
-      esis_dissect_unknown(tvb, esis_tree,
-                           "Unknown ESIS version (%u vs %u)",
-                           ehdr.esis_version, ESIS_REQUIRED_VERSION );
+    proto_tree_add_item( esis_tree, hf_esis_nlpi, tvb, 0, 1, ENC_BIG_ENDIAN);
+    ti = proto_tree_add_item( esis_tree, hf_esis_length, tvb, 1, 1, ENC_BIG_ENDIAN );
+    length = tvb_get_guint8(tvb, 1);
+    if (length < ESIS_HDR_FIXED_LENGTH) {
+      expert_add_info_format(pinfo, ti, &ei_esis_length,
+                           "Bogus ESIS length (%u, must be >= %u)",
+                           length, ESIS_HDR_FIXED_LENGTH );
       return;
     }
 
-    if (ehdr.esis_length < ESIS_HDR_FIXED_LENGTH) {
-      esis_dissect_unknown(tvb, esis_tree,
-                           "Bogus ESIS length (%u, must be >= %u)",
-                           ehdr.esis_length, ESIS_HDR_FIXED_LENGTH );
-      return;
+    version = tvb_get_guint8(tvb, 2);
+    ti = proto_tree_add_item( esis_tree, hf_esis_version, tvb, 2, 1, ENC_BIG_ENDIAN);
+    if (version != ESIS_REQUIRED_VERSION){
+      expert_add_info_format(pinfo, ti, &ei_esis_version,
+                           "Unknown ESIS version (%u vs %u)",
+                           version, ESIS_REQUIRED_VERSION );
     }
-    proto_tree_add_uint( esis_tree, hf_esis_nlpi, tvb, 0, 1, ehdr.esis_nlpi );
-    proto_tree_add_uint( esis_tree, hf_esis_length, tvb,
-                         1, 1, ehdr.esis_length );
-    proto_tree_add_uint( esis_tree, hf_esis_version, tvb, 2, 1,
-                         ehdr.esis_version );
-    proto_tree_add_uint( esis_tree, hf_esis_reserved, tvb, 3, 1,
-                         ehdr.esis_reserved );
-
-    pdu_type_string = val_to_str(ehdr.esis_type&OSI_PDU_TYPE_MASK,
-                                 esis_vals, "Unknown (0x%x)");
-
-    proto_tree_add_uint_format( esis_tree, hf_esis_type, tvb, 4, 1,
-                                ehdr.esis_type,
-                                pdu_type_format_string,
-                                pdu_type_string,
-                                (ehdr.esis_type&0x80) ? "1" : "0",
-                                (ehdr.esis_type&0x40) ? "1" : "0",
-                                (ehdr.esis_type&0x20) ? "1" : "0");
-
-    tmp_uint = pntoh16( ehdr.esis_holdtime );
-    proto_tree_add_uint_format_value(esis_tree, hf_esis_holdtime, tvb, 5, 2,
-                               tmp_uint, "%u seconds",
-                               tmp_uint );
 
-    tmp_uint = pntoh16( ehdr.esis_checksum );
+    proto_tree_add_item( esis_tree, hf_esis_reserved, tvb, 3, 1, ENC_BIG_ENDIAN);
+
+    type_item = proto_tree_add_item( esis_tree, hf_esis_type, tvb, 4, 1, ENC_BIG_ENDIAN);
+    type = tvb_get_guint8(tvb, 4) & OSI_PDU_TYPE_MASK;
 
-    switch (calc_checksum( tvb, 0, ehdr.esis_length, tmp_uint )) {
+    holdtime = tvb_get_ntohs(tvb, 5);
+    proto_tree_add_uint_format_value(esis_tree, hf_esis_holdtime, tvb, 5, 2,
+                               holdtime, "%u seconds", holdtime);
+
+    checksum = tvb_get_ntohs(tvb, 7);
+    switch (calc_checksum( tvb, 0, length, checksum)) {
 
     case NO_CKSUM:
       cksum_status = "Not Used";
@@ -353,9 +309,7 @@ dissect_esis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
       DISSECTOR_ASSERT_NOT_REACHED();
     }
     proto_tree_add_uint_format_value( esis_tree, hf_esis_checksum, tvb, 7, 2,
-                                tmp_uint, "0x%x ( %s )",
-                                tmp_uint, cksum_status );
-  }
+                                checksum, "0x%x ( %s )", checksum, cksum_status );
 
 
   /*
@@ -364,25 +318,23 @@ dissect_esis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
    * dispatch the sub-type.
    */
   col_add_str(pinfo->cinfo, COL_INFO,
-                val_to_str( ehdr.esis_type&OSI_PDU_TYPE_MASK, esis_vals,
+                val_to_str( type, esis_vals,
                             "Unknown (0x%x)" ) );
 
-  variable_len = ehdr.esis_length - ESIS_HDR_FIXED_LENGTH;
+  variable_len = length - ESIS_HDR_FIXED_LENGTH;
 
-  switch (ehdr.esis_type & OSI_PDU_TYPE_MASK) {
+  switch (type) {
   case ESIS_ESH_PDU:
-    esis_dissect_esh_pdu( variable_len, tvb, esis_tree);
+    esis_dissect_esh_pdu( variable_len, tvb, esis_tree, pinfo);
     break;
   case ESIS_ISH_PDU:
-    esis_dissect_ish_pdu( variable_len, tvb, esis_tree);
+    esis_dissect_ish_pdu( variable_len, tvb, esis_tree, pinfo);
     break;
   case ESIS_RD_PDU:
-    esis_dissect_redirect_pdu( variable_len, tvb, esis_tree);
+    esis_dissect_redirect_pdu( variable_len, tvb, esis_tree, pinfo);
     break;
   default:
-    esis_dissect_unknown(tvb, esis_tree,
-                         "Unknown ESIS packet type 0x%x",
-                         ehdr.esis_type & OSI_PDU_TYPE_MASK );
+    expert_add_info(pinfo, type_item, &ei_esis_type);
   }
 } /* dissect_esis */
 
@@ -414,13 +366,13 @@ proto_register_esis(void) {
       { "PDU Length", "esis.length",  FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
 
     { &hf_esis_version,
-      { "Version (==1)", "esis.ver",  FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+      { "Version", "esis.ver",  FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
 
     { &hf_esis_reserved,
       { "Reserved(==0)", "esis.res",  FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
 
     { &hf_esis_type,
-      { "PDU Type", "esis.type",      FT_UINT8, BASE_DEC, VALS(esis_vals), 0xff, NULL, HFILL }},
+      { "PDU Type", "esis.type",      FT_UINT8, BASE_DEC, VALS(esis_vals), OSI_PDU_TYPE_MASK, NULL, HFILL }},
 
     { &hf_esis_holdtime,
       { "Holding Time", "esis.htime", FT_UINT16, BASE_DEC, NULL, 0x0, "s", HFILL }},
@@ -431,6 +383,7 @@ proto_register_esis(void) {
       /* Generated from convert_proto_tree_add_text.pl */
       { &hf_esis_number_of_source_addresses, { "Number of Source Addresses (SA, Format: NSAP)", "esis.number_of_source_addresses", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
       { &hf_esis_sal, { "SAL", "esis.sal", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+      { &hf_esis_sa, { "SA", "esis.sa", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
       { &hf_esis_netl, { "NETL", "esis.netl", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
       { &hf_esis_dal, { "DAL", "esis.dal", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
       { &hf_esis_bsnpal, { "BSNPAL", "esis.bsnpal", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
@@ -438,18 +391,28 @@ proto_register_esis(void) {
       { &hf_esis_da, { "DA", "esis.da", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
       { &hf_esis_bsnpa, { "BSNPA", "esis.bsnpa", FT_SYSTEM_ID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
   };
-  /*
-   *
-   *
-   */
+
   static gint *ett[] = {
     &ett_esis,
     &ett_esis_area_addr,
+    &ett_esis_network,
+    &ett_esis_dest_addr,
+    &ett_esis_subnetwork
   };
 
+  static ei_register_info ei[] = {
+    { &ei_esis_version, { "esis.ver.unknown", PI_PROTOCOL, PI_WARN, "Unknown ESIS version", EXPFILL }},
+    { &ei_esis_length, { "esis.length.invalid", PI_MALFORMED, PI_ERROR, "Bogus ESIS length", EXPFILL }},
+    { &ei_esis_type, { "esis.type.unknown", PI_PROTOCOL, PI_WARN, "Unknown ESIS packet type", EXPFILL }},
+  };
+
+  expert_module_t* expert_esis;
+
   proto_esis = proto_register_protocol( PROTO_STRING_ESIS, "ESIS", "esis");
   proto_register_field_array(proto_esis, hf, array_length(hf));
   proto_register_subtree_array(ett, array_length(ett));
+  expert_esis = expert_register_protocol(proto_esis);
+  expert_register_field_array(expert_esis, ei, array_length(ei));
   register_dissector("esis", dissect_esis, proto_esis);
 }
 
@@ -461,3 +424,16 @@ proto_reg_handoff_esis(void)
   esis_handle = find_dissector("esis");
   dissector_add_uint("osinl.incl", NLPID_ISO9542_ESIS, esis_handle);
 }
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local Variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */