Allow NCP types to define bitfields. In order to implement
authorgram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 10 Jan 2002 04:44:34 +0000 (04:44 +0000)
committergram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 10 Jan 2002 04:44:34 +0000 (04:44 +0000)
sub-trees, I added new functions to ptvcursor:

ptvcursor_add_no_advance()
ptvcursor_tvbuff()
ptvcursor_current_offset()

Note that no NCP type that actually uses bitfields has been
checked in yet.

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

ncp2222.py
packet-ncp-int.h
packet-ncp2222.inc
ptvcursor.c
ptvcursor.h

index 96d913fa818095c5438aeea78e7c75738944c0fd..7d920630a37b73a9894284d33be38303781f6014 100755 (executable)
@@ -20,7 +20,7 @@ http://developer.novell.com/ndk/doc/docui/index.htm#../ncp/ncp__enu/data/
 for a badly-formatted HTML version of the same PDF.
 
 
-$Id: ncp2222.py,v 1.11 2001/11/13 23:55:29 gram Exp $
+$Id: ncp2222.py,v 1.12 2002/01/10 04:44:34 gram Exp $
 
 Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
 
@@ -89,7 +89,10 @@ class UniqueCollection:
                return 0
 
 
-
+# This list needs to be defined before the NCP types are defined,
+# because the NCP types are defined in the global scope, not inside
+# a function's scope.
+ptvc_lists     = UniqueCollection('PTVC Lists')
 
 ##############################################################################
 
@@ -144,22 +147,34 @@ class PTVC(NamedList):
 
        def __init__(self, name, records):
                "Constructor"
-               self.list = []
-               NamedList.__init__(self, name, self.list)
+               NamedList.__init__(self, name, [])
 
                expected_offset = None
 
                # Make a PTVCRecord object for each list in 'records'
                for record in records:
-                       ptvc_rec = PTVCRecord(record)
+                       offset  = record[0]
+                       length  = record[1]
+                       field   = record[2]
+
+                       # Check if an endianness override is given
+                       try:
+                               endianness = record[3]
+
+                       # If no endianness was given in the record, then
+                       # use the field's default endianness.
+                       except IndexError:
+                               endianness = field.Endianness()
+
+                       ptvc_rec = PTVCRecord(field, length, endianness)
 
                        if expected_offset == None:
-                               expected_offset = ptvc_rec.Offset()
+                               expected_offset = offset
 
                        elif expected_offset == -1:
                                pass
 
-                       elif expected_offset != ptvc_rec.Offset():
+                       elif expected_offset != offset:
                                sys.stderr.write("Expected offset in %s to be %d\n" % (name,
                                        expected_offset))
                                sys.exit(1)
@@ -180,33 +195,47 @@ class PTVC(NamedList):
 
                        self.list.append(ptvc_rec)
 
-class PTVCRecord:
-       def __init__(self, record):
-               "Constructor"
-               self.offset     = record[0]
-               self.length     = record[1]
-               self.field      = record[2]
+       def __str__(self):
+               x =  "static const ptvc_record %s[] = {\n" % (self.Name())
+               for ptvc_rec in self.list:
+                       x = x +  "\t%s,\n" % (ptvc_rec)
+               x = x + "\t{ NULL, 0, 0, NULL }\n"
+               x = x + "};\n"
+               return x
 
-               # Small sanity check
-               field_length = self.field.Length()
 
-#              if type(field_length) != type(self.length):
-#                      sys.stderr.write("Length types do not match")
-#                      sys.exit(1)
+class PTVCBitfield(PTVC):
+       def __init__(self, name, vars):
+               NamedList.__init__(self, name, [])
 
-#              if type(field_length) == type(0) and field_length > 0:
-#                      if field_length != self.length:
-#                              sys.stderr.write("Length %d does not match field length %d for field %s\n" % (self.length, field_length, self.field.Abbreviation()))
-#                              sys.exit(1)
+               for var in vars:
+                       ptvc_rec = PTVCRecord(var, var.Length(), var.Endianness())
+                       self.list.append(ptvc_rec)
 
-               # Check if an endianness override is given
-               try:
-                       self.endianness = record[3]
+       def ETTName(self):
+               return "ett_%s" % (self.Name(),)
+       def __str__(self):
+               ett_name = self.ETTName()
+               x = "static gint %s;\n" % (ett_name,)
 
-               # If no endianness was given in the record, then
-               # use the field's default endianness.
-               except IndexError:
-                       self.endianness = self.field.Endianness()
+               x = x + "static const ptvc_record ptvc_%s[] = {\n" % (self.Name())
+               for ptvc_rec in self.list:
+                       x = x +  "\t%s,\n" % (ptvc_rec)
+               x = x + "\t{ NULL, 0, 0, NULL }\n"
+               x = x + "};\n"
+
+               x = x + "static const sub_ptvc_record %s = {\n" % (self.Name(),)
+               x = x + "\t&%s,\n" % (ett_name,)
+               x = x + "\tptvc_%s,\n" % (self.Name(),)
+               x = x + "};\n"
+               return x
+
+class PTVCRecord:
+       def __init__(self, field, length, endianness):
+               "Constructor"
+               self.field      = field
+               self.length     = length
+               self.endianness = endianness
 
        def __cmp__(self, other):
                "Comparison operator"
@@ -222,13 +251,14 @@ class PTVCRecord:
                else:
                        return 0
 
-       def __repr__(self):
+       def __str__(self):
                "String representation"
                endianness = 'FALSE'
                if self.endianness == LE:
                        endianness = 'TRUE'
 
-               length = -1
+               # Default the length to this value
+               length = "PTVC_VARIABLE_LENGTH"
 
                if type(self.length) == type(0):
                        length = self.length
@@ -237,13 +267,12 @@ class PTVCRecord:
                        if var_length > 0:
                                length = var_length
 
-               if length > -1:
-                       return "{ &%s, %d, %s }" % (self.field.HFName(),
-                                       length, endianness)
-               else:
-                       length = "PTVC_VARIABLE_LENGTH"
-                       return "{ &%s, %s, %s }" % (self.field.HFName(),
-                                       length, endianness)
+               sub_ptvc_name = self.field.PTVCName()
+               if sub_ptvc_name != "NULL":
+                       sub_ptvc_name = "&%s" % (sub_ptvc_name,)
+
+               return "{ &%s, %s, %s, %s }" % (self.field.HFName(),
+                               length, endianness, sub_ptvc_name)
 
        def Offset(self):
                return self.offset
@@ -254,7 +283,6 @@ class PTVCRecord:
        def Field(self):
                return self.field
 
-
 ##############################################################################
 
 class NCP:
@@ -398,11 +426,19 @@ class NCP:
                                var = record[2]
                                variables[var] = 1
 
+                               sub_vars = var.SubVariables()
+                               for sv in sub_vars:
+                                       variables[sv] = 1
+
                if self.reply_records:
                        for record in self.reply_records:
                                var = record[2]
                                variables[var] = 1
 
+                               sub_vars = var.SubVariables()
+                               for sv in sub_vars:
+                                       variables[sv] = 1
+
                return variables.keys()
 
 
@@ -503,6 +539,12 @@ class Type:
        def Endianness(self):
                return self.endianness
 
+       def SubVariables(self):
+               return []
+
+       def PTVCName(self):
+               return "NULL"
+
 class byte(Type):
        type    = "byte"
        ftype   = "FT_UINT8"
@@ -513,9 +555,14 @@ class byte(Type):
 class uint8(Type):
        type    = "uint8"
        ftype   = "FT_UINT8"
+       bytes   = 1
        def __init__(self, abbrev, descr):
                Type.__init__(self, abbrev, descr, 1)
 
+class boolean8(uint8):
+       type    = "boolean8"
+       ftype   = "FT_BOOLEAN"
+
 class uint16(Type):
        type    = "uint16"
        ftype   = "FT_UINT16"
@@ -609,6 +656,62 @@ class bytes(Type):
        def __init__(self, abbrev, descr, bytes):
                Type.__init__(self, abbrev, descr, bytes, NA)
 
+
+class bitfield(Type):
+       type    = "bitfield"
+       disp    = 'BASE_HEX'
+
+       def __init__(self, vars):
+               var_hash = {}
+               for var in vars:
+                       var_hash[var.bitmask] = var
+
+               bitmasks = var_hash.keys()
+               bitmasks.sort()
+               bitmasks.reverse()
+
+               ordered_vars = []
+               for bitmask in bitmasks:
+                       var = var_hash[bitmask]
+                       ordered_vars.append(var)
+
+               self.vars = ordered_vars
+               self.sub_ptvc = PTVCBitfield(self.PTVCName(), self.vars)
+
+       def SubVariables(self):
+               return self.vars
+
+       def SubVariablesPTVC(self):
+               return self.sub_ptvc
+
+       def PTVCName(self):
+               return "ncp_%s_bitfield" % (self.abbrev,)
+
+class bitfield8(bitfield, uint8):
+       type    = "bitfield8"
+       ftype   = "FT_UINT8"
+
+       def __init__(self, abbrev, descr, vars):
+               uint8.__init__(self, abbrev, descr)
+               bitfield.__init__(self, vars)
+
+class bf_uint(Type):
+       type    = "bf_uint"
+       disp    = 'BASE_HEX'
+
+       def __init__(self, bitmask, abbrev, descr):
+               self.bitmask = bitmask
+               self.abbrev = abbrev
+               self.descr = descr
+
+       def Mask(self):
+               return self.bitmask
+
+class bf_boolean8(bf_uint, boolean8):
+       type    = "bf_boolean8"
+       ftype   = "FT_BOOLEAN"
+       disp    = "8"
+
 #class data(Type):
 #      type    = "data"
 #      ftype   = "FT_BYTES"
@@ -1136,48 +1239,11 @@ static int hf_ncp_connection_status = -1;
 
        # Print the value_string's
        for var in variables_used_hash.keys():
-               if var.type == "val_string8" or var.type == "val_string16":
+               if isinstance(var, val_string):
                        print ""
                        print `var`
 
 
-       print """
-void
-proto_register_ncp2222(void)
-{
-
-       static hf_register_info hf[] = {
-       { &hf_ncp_func,
-       { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
-
-       { &hf_ncp_length,
-       { "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
-
-       { &hf_ncp_subfunc,
-       { "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
-
-       { &hf_ncp_completion_code,
-       { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
-
-       { &hf_ncp_connection_status,
-       { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
-       """
-
-       # Print the registration code for the hf variables
-       for var in variables_used_hash.keys():
-               print "\t{ &%s," % (var.HFName())
-               print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\", HFILL }},\n" % \
-                       (var.Description(), var.DFilter(),
-                       var.EtherealFType(), var.Display(), var.ValuesName(),
-                       var.Mask())
-
-       print """\t};
-
-               proto_register_field_array(proto_ncp, hf, array_length(hf));
-       }
-       """
-
-
        # Determine which error codes are not used
        errors_not_used = {}
        # Copy the keys from the error list...
@@ -1233,16 +1299,21 @@ proto_register_ncp2222(void)
                print "#define NCP_GROUP_%s\t%d" % (name, groups_used_hash[group])
        print "\n"
 
-       # Print PTVC's
+       # Print PTVC's for bitfields
+       ett_list = []
+       print "/* PTVC records for bit-fields. */"
+       for var in variables_used_hash.keys():
+               if isinstance(var, bitfield):
+                       sub_vars_ptvc = var.SubVariablesPTVC()
+                       print "/* %s */" % (sub_vars_ptvc.Name())
+                       print sub_vars_ptvc
+                       ett_list.append(sub_vars_ptvc.ETTName())
+
+       # Print PTVC's not already printed for bitfields
        print "/* PTVC records. These are re-used to save space. */"
        for ptvc in ptvc_lists.Members():
                if not ptvc.Null() and not ptvc.Empty():
-                       print "static const ptvc_record %s[] = {" % (ptvc.Name())
-                       records = ptvc.Records()
-                       for ptvc_rec in records:
-                               print "\t%s," % (ptvc_rec)
-                       print "\t{ NULL, 0, 0 }"
-                       print "};\n"
+                       print ptvc
 
        # Print error_equivalency tables
        print "/* Error-Equivalency Tables. These are re-used to save space. */"
@@ -1320,7 +1391,7 @@ proto_register_ncp2222(void)
        print "};\n"
 
 
-       print "/* ncp funs that have no length parameter */"
+       print "/* ncp funcs that have no length parameter */"
        print "static const guint8 ncp_func_has_no_length_parameter[] = {"
        funcs = funcs_without_length.keys()
        funcs.sort()
@@ -1328,8 +1399,57 @@ proto_register_ncp2222(void)
                print "\t0x%02x," % (func,)
        print "\t0"
        print "};\n"
-       
 
+       # proto_register_ncp2222()
+       print """
+void
+proto_register_ncp2222(void)
+{
+
+       static hf_register_info hf[] = {
+       { &hf_ncp_func,
+       { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
+
+       { &hf_ncp_length,
+       { "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+
+       { &hf_ncp_subfunc,
+       { "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
+
+       { &hf_ncp_completion_code,
+       { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
+
+       { &hf_ncp_connection_status,
+       { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+       """
+
+       # Print the registration code for the hf variables
+       for var in variables_used_hash.keys():
+               print "\t{ &%s," % (var.HFName())
+               print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\", HFILL }},\n" % \
+                       (var.Description(), var.DFilter(),
+                       var.EtherealFType(), var.Display(), var.ValuesName(),
+                       var.Mask())
+
+       print """
+       };
+
+       static gint *ett[] = {
+       """
+
+       for ett in ett_list:
+               print "\t\t&%s," % (ett,)
+
+       print """
+       };
+
+       proto_register_field_array(proto_ncp, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
+}
+       """
+
+
+       print ""
        print '#include "packet-ncp2222.inc"'
 
 
@@ -1340,7 +1460,6 @@ def main():
 
        packets         = UniqueCollection('NCP Packet Descriptions')
        compcode_lists  = UniqueCollection('Completion Code Lists')
-       ptvc_lists      = UniqueCollection('PTVC Lists')
 
        define_errors()
        define_groups()
index 57262d073488da863c01f36ae5fccfff519a48af..4a4ba14a991099e387170bb866db3999d61503c6 100644 (file)
@@ -2,7 +2,7 @@
  * Structures and functions for NetWare Core Protocol.
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: packet-ncp-int.h,v 1.5 2002/01/05 04:12:14 gram Exp $
+ * $Id: packet-ncp-int.h,v 1.6 2002/01/10 04:44:34 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #ifndef __PACKET_NCP_INT_H__
 #define __PACKET_NCP_INT_H__
 
-typedef struct {
-       int             *hf_ptr;
-       gint            length;
-       gboolean        endianness;
-} ptvc_record;
+typedef struct _ptvc_record ptvc_record;
+typedef struct _sub_ptvc_record sub_ptvc_record;
+
+struct _ptvc_record {
+       int                     *hf_ptr;
+       gint                    length;
+       gboolean                endianness;
+       const sub_ptvc_record   *sub_ptvc_rec;
+};
+
+struct _sub_ptvc_record {
+       gint                    *ett;
+       const ptvc_record       *ptvc_rec;
+};
 
 typedef struct {
        guint8          error_in_packet;
index e1cb842ec245f29bea83f174fd9e6a78b2c11876..57a183484626b39c312acf22e12c5f462f51dea1 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: packet-ncp2222.inc,v 1.7 2002/01/05 04:12:14 gram Exp $
+ * $Id: packet-ncp2222.inc,v 1.8 2002/01/10 04:44:34 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -82,13 +82,59 @@ ncp_record_find(guint8 func, guint8 subfunc)
        return NULL;
 }
 
-/* Run through the table of ptv_record's and add info to the tree */
+/* Add a value for a ptvc_record, and process the sub-ptvc_record
+ * that it points to. */
+static void
+process_sub_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
+{
+       proto_item              *item;
+       proto_tree              *sub_tree;
+       const ptvc_record       *sub_rec;
+       int                     current_offset;
+       gint                    ett;
+       ptvcursor_t             *sub_ptvc;
+
+       /* Save the current offset */
+       current_offset = ptvcursor_current_offset(ptvc);
+
+       /* Add the item */
+       item = ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
+                       rec->endianness);
+
+       ett = *rec->sub_ptvc_rec->ett;
+
+       /* Make a new protocol sub-tree */
+       sub_tree = proto_item_add_subtree(item, ett);
+
+       /* Make a new ptvcursor */
+       sub_ptvc = ptvcursor_new(sub_tree, ptvcursor_tvbuff(ptvc),
+                       current_offset);
+
+       /* Use it */
+       sub_rec = rec->sub_ptvc_rec->ptvc_rec;
+       while(sub_rec->hf_ptr != NULL) {
+               g_assert(!sub_rec->sub_ptvc_rec);
+               ptvcursor_add_no_advance(sub_ptvc, *sub_rec->hf_ptr,
+                               sub_rec->length, sub_rec->endianness);
+               sub_rec++;
+       }
+
+       /* Free it. */
+       ptvcursor_free(sub_ptvc);
+}
+
+/* Run through the table of ptvc_record's and add info to the tree */
 static void
 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
 {
        while(rec->hf_ptr != NULL) {
-               ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
+               if (rec->sub_ptvc_rec) {
+                       process_sub_ptvc_record(ptvc, rec);
+               }
+               else {
+                       ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
                                rec->endianness);
+               }
                rec++;
        }
 }
index 6159e6085cee894da50dec5d17749d04146e1f87..bce7f80dd31ff4e418a24688df71912b33e19a9f 100644 (file)
@@ -3,7 +3,7 @@
  * Proto Tree TVBuff cursor
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: ptvcursor.c,v 1.4 2001/11/13 23:55:30 gram Exp $
+ * $Id: ptvcursor.c,v 1.5 2002/01/10 04:44:34 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -56,10 +56,22 @@ ptvcursor_add(ptvcursor_t *ptvc, int hf, gint length, gboolean endianness)
 {
        proto_item      *item;
 
+       item = ptvcursor_add_no_advance(ptvc, hf, length, endianness);
+       ptvc->offset += proto_item_get_len(item);
+       return item;
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment
+ * offset, and returns proto_item* */
+proto_item*
+ptvcursor_add_no_advance(ptvcursor_t* ptvc, int hf, gint length,
+               gboolean endianness)
+{
+       proto_item      *item;
+
        item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset,
                        length, endianness);
 
-       ptvc->offset += proto_item_get_len(item);
        return item;
 }
 
@@ -69,3 +81,16 @@ ptvcursor_free(ptvcursor_t *ptvc)
 {
        g_free(ptvc);
 }
+/* Returns tvbuff. */
+tvbuff_t*
+ptvcursor_tvbuff(ptvcursor_t* ptvc)
+{
+       return ptvc->tvb;
+}
+
+/* Returns current offset. */
+gint
+ptvcursor_current_offset(ptvcursor_t* ptvc)
+{
+       return ptvc->offset;
+}
index 0926ff8f0601df79af30d5d45c7c9503040fada2..366796954d0799cd2a291c660bc4694eb7867b3d 100644 (file)
@@ -3,7 +3,7 @@
  * Proto Tree TVBuff cursor
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: ptvcursor.h,v 1.3 2001/11/13 23:55:30 gram Exp $
+ * $Id: ptvcursor.h,v 1.4 2002/01/10 04:44:34 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -48,8 +48,22 @@ ptvcursor_new(proto_tree*, tvbuff_t*, gint);
 proto_item*
 ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness);
 
+
+/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment
+ * offset, and returns proto_item* */
+proto_item*
+ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness);
+
 /* Frees memory for ptvcursor_t, but nothing deeper than that. */
 void
 ptvcursor_free(ptvcursor_t*);
 
+/* Returns tvbuff. */
+tvbuff_t*
+ptvcursor_tvbuff(ptvcursor_t*);
+
+/* Returns current offset. */
+gint
+ptvcursor_current_offset(ptvcursor_t*);
+
 #endif /* __PTVCURSOR_H__ */