Fix "packet-netbios.h" to match the new "packet-netbios.c", so that it
[obnox/wireshark/wip.git] / packet-nbipx.c
index d35a7f04a99b7388ce064b41db4d23b3b7509d14..fe983890dd22b037fca29ae962611b57ab2876ce 100644 (file)
@@ -1,8 +1,8 @@
 /* packet-nbipx.c
  * Routines for NetBIOS over IPX packet disassembly
- * Gilbert Ramirez <gram@verdict.uthscsa.edu>
+ * Gilbert Ramirez <gram@xiexie.org>
  *
- * $Id: packet-nbipx.c,v 1.4 1998/11/12 00:06:32 gram Exp $
+ * $Id: packet-nbipx.c,v 1.24 2000/11/10 21:09:49 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 # include "config.h"
 #endif
 
-#include <gtk/gtk.h>
-
-#include <stdio.h>
-#include <memory.h>
-
 #ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
 
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#include "ethereal.h"
+#include <glib.h>
 #include "packet.h"
-#include "packet-ipx.h" /* for ipxnet_to_string() */
+#include "packet-ipx.h"
+#include "packet-netbios.h"
+#include "packet-smb.h"
+
+static int proto_nbipx = -1;
+
+static gint ett_nbipx = -1;
+static gint ett_nbipx_name_type_flags = -1;
 
 enum nbipx_protocol {
        NETBIOS_NETWARE,
@@ -51,141 +49,409 @@ enum nbipx_protocol {
 };
 
 static void
-nbipx_ns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree,
-               enum nbipx_protocol nbipx);
+dissect_nbipx_ns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+static void
+dissect_nbipx_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
 
 /* There is no RFC or public specification of Netware or Microsoft
  * NetBIOS over IPX packets. I have had to decode the protocol myself,
  * so there are holes and perhaps errors in this code. (gram)
+ *
+ * A list of "NovelNetBIOS" packet types can be found at
+ *
+ *     http://www.protocols.com/pbook/novel.htm#NetBIOS
+ *
+ * and at least some of those packet types appear to match what's in
+ * some NBIPX packets.
+ *
+ * Note, however, that the offset of the packet type in an NBIPX packet
+ * *DEPENDS ON THE PACKET TYPE*; "Find name" and "Name recognized" have
+ * it at one offset, "Directed datagram" has it at another.  Does the
+ * NBIPX code base it on the length, or what?  Non-broadcast directed
+ * datagram packets have an IPX type of "IPX", just as "Find name" and
+ * "Name recognized" do....  For now, we base it on the length.
  */
-static char
-*packet_type[] = {
-               "",
-               "Name Query"
+#define NBIPX_FIND_NAME                1
+#define NBIPX_NAME_RECOGNIZED  2
+#define NBIPX_CHECK_NAME       3
+#define NBIPX_NAME_IN_USE      4
+#define NBIPX_DEREGISTER_NAME  5
+#define NBIPX_SESSION_DATA     6
+#define NBIPX_SESSION_END      7
+#define NBIPX_SESSION_END_ACK  8
+#define NBIPX_STATUS_QUERY     9
+#define NBIPX_STATUS_RESPONSE  10
+#define NBIPX_DIRECTED_DATAGRAM        11
+
+static const value_string nbipx_data_stream_type_vals[] = {
+       {NBIPX_FIND_NAME,               "Find name"},
+       {NBIPX_NAME_RECOGNIZED,         "Name recognized"},
+       {NBIPX_CHECK_NAME,              "Check name"},
+       {NBIPX_NAME_IN_USE,             "Name in use"},
+       {NBIPX_DEREGISTER_NAME,         "Deregister name"},
+       {NBIPX_SESSION_DATA,            "Session data"},
+       {NBIPX_SESSION_END,             "Session end"},
+       {NBIPX_SESSION_END_ACK,         "Session end ACK"},
+       {NBIPX_STATUS_QUERY,            "Status query"},
+       {NBIPX_STATUS_RESPONSE,         "Status response"},
+       {NBIPX_DIRECTED_DATAGRAM,       "Directed datagram"},
+       {0,                             NULL}
 };
 
-struct nbipx_header {
-       /* Netware & NT NetBIOS over IPX */
-       guint32         router[8];
-       guint8          name_type;
-       guint8          packet_type;
-
-       char            name[17];
+#define NWLINK_NAME_QUERY      1
+#define        NWLINK_SMB              2
+#define        NWLINK_NETBIOS_DATAGRAM 3
 
-       /* NT NetBIOS over IPX */
-       guint16         junk;
-       char            node_name[17];
-       
+static const value_string nwlink_data_stream_type_vals[] = {
+       {NWLINK_NAME_QUERY,             "Name query"},
+       {NWLINK_SMB,                    "SMB"},
+       {NWLINK_NETBIOS_DATAGRAM,       "NetBIOS datagram"},
+       {0,                             NULL}
 };
 
-
 /* NetWare */
 void
-dissect_nbipx_ns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
+dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       nbipx_ns(pd, offset, fd, tree, NETBIOS_NETWARE);
+       CHECK_DISPLAY_AS_DATA(proto_nbipx, tvb, pinfo, tree);
+
+       if (check_col(pinfo->fd, COL_PROTOCOL))
+               col_add_str(pinfo->fd, COL_PROTOCOL, "NBIPX");
+
+       /*
+        * As said above, we look at the length of the packet to decide
+        * whether to treat it as a name-service packet or a datagram
+        * (the packet type would tell us, but it's at a *DIFFERENT
+        * LOCATION* in different types of packet...).
+        */
+       if (tvb_reported_length(tvb) == 50)
+               dissect_nbipx_ns(tvb, pinfo, tree);
+       else
+               dissect_nbipx_dg(tvb, pinfo, tree);
 }
 
-void
-dissect_nwlink_dg(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
+static void
+add_routers(proto_tree *tree, tvbuff_t *tvb, int offset)
 {
-       nbipx_ns(pd, offset, fd, tree, NETBIOS_NWLINK);
+       int             i;
+       int             rtr_offset;
+       guint32         router;
+
+       /* Eight routers are listed */
+       for (i = 0; i < 8; i++) {
+               rtr_offset = offset + (i << 2);
+               tvb_memcpy(tvb, (guint8 *)&router, rtr_offset, 4);
+               if (router != 0) {
+                       proto_tree_add_text(tree, tvb, rtr_offset, 4,
+                           "IPX Network: %s",
+                           ipxnet_to_string((guint8*)&router));
+               }
+       }
 }
 
-
 static void
-nbipx_ns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree,
-               enum nbipx_protocol nbipx)
+dissect_nbipx_ns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       GtkWidget                       *nbipx_tree, *ti;
-       struct nbipx_header     header;
-       int                                     i, rtr_offset;
-       int                                     name_offset;
-
-       if (nbipx == NETBIOS_NETWARE) {
-               name_offset = 34;
-       }
-       else {
-               name_offset = 36;
+       proto_tree              *nbipx_tree;
+       proto_item              *ti;
+       int                     offset = 0;
+       guint8                  packet_type;
+       guint8                  name_type_flag;
+       proto_tree              *name_type_flag_tree;
+       proto_item              *tf;
+       char                    name[(NETBIOS_NAME_LEN - 1)*4 + 1];
+       int                     name_type;
+
+       name_type_flag = tvb_get_guint8(tvb, offset+32);
+       packet_type = tvb_get_guint8(tvb, offset+33);
+       name_type = get_netbios_name(tvb, offset+34, name);
+
+       if (check_col(pinfo->fd, COL_INFO)) {
+               switch (packet_type) {
+               case NBIPX_FIND_NAME:
+               case NBIPX_NAME_RECOGNIZED:
+               case NBIPX_CHECK_NAME:
+               case NBIPX_NAME_IN_USE:
+               case NBIPX_DEREGISTER_NAME:
+                       col_add_fstr(pinfo->fd, COL_INFO, "%s %s<%02x>",
+                               val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
+                               name, name_type);
+                       break;
+
+               default:
+                       col_add_fstr(pinfo->fd, COL_INFO, "%s",
+                               val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"));
+                       break;
+               }
        }
 
-
-       header.name_type = pd[offset+32];
-       header.packet_type = pd[offset+33];
-       memcpy(header.name, &pd[offset+name_offset], 16);
-       header.name[16] = 0; /* null-terminate the string */
-
-       if (nbipx == NETBIOS_NWLINK) {
-               memcpy(header.node_name, &pd[offset+52], 16);
-               header.node_name[17] = 0; /* null-terminate the string */
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_nbipx, tvb, offset, 50,
+                   FALSE);
+               nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
+
+               add_routers(nbipx_tree, tvb, offset);
+
+               tf = proto_tree_add_text(nbipx_tree, tvb, offset+32, 1,
+                       "Name type flag: 0x%02x", name_type_flag);
+               name_type_flag_tree = proto_item_add_subtree(tf,
+                               ett_nbipx_name_type_flags);
+               proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                   1, "%s",
+                   decode_boolean_bitfield(name_type_flag, 0x80, 8,
+                     "Group name", "Unique name"));
+               proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                   1, "%s",
+                   decode_boolean_bitfield(name_type_flag, 0x40, 8,
+                     "Name in use", "Name not used"));
+               proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                   1, "%s",
+                   decode_boolean_bitfield(name_type_flag, 0x04, 8,
+                     "Name registered", "Name not registered"));
+               proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                   1, "%s",
+                   decode_boolean_bitfield(name_type_flag, 0x02, 8,
+                     "Name duplicated", "Name not duplicated"));
+               proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                   1, "%s",
+                   decode_boolean_bitfield(name_type_flag, 0x01, 8,
+                     "Name deregistered", "Name not deregistered"));
+
+               proto_tree_add_text(nbipx_tree, tvb, offset+33, 1,
+                       "Packet Type: %s (%02X)",
+                       val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
+                       packet_type);
+
+               netbios_add_name("Name", tvb, offset + 34, nbipx_tree);
        }
+}
 
-       if (fd->win_info[COL_NUM]) {
-               if (nbipx == NETBIOS_NETWARE) {
-                       strcpy(fd->win_info[COL_PROTOCOL], "NetBIOS");
-               }
-               else {
-                       strcpy(fd->win_info[COL_PROTOCOL], "NWLink");
-               }
-
-                       switch (header.packet_type) {
-                               case 1:
-                                       sprintf(fd->win_info[COL_INFO], "Name Query for %s",
-                                                       header.name);
-                                       break;
+static void
+dissect_nbipx_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       proto_tree                      *nbipx_tree;
+       proto_item                      *ti;
+       int                             offset = 0;
+       guint8                          packet_type;
+       tvbuff_t                        *next_tvb;
+       const guint8                    *next_pd;
+       int                             next_offset;
 
-                               default:
-                                       strcpy(fd->win_info[COL_INFO], "NetBIOS over IPX");
-                       }
-       }
+       if (check_col(pinfo->fd, COL_INFO))
+               col_add_fstr(pinfo->fd, COL_INFO, "NetBIOS datagram over NBIPX");
 
        if (tree) {
-               ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
-                               "NetBIOS over IPX");
-               nbipx_tree = gtk_tree_new();
-               add_subtree(ti, nbipx_tree, ETT_NBIPX);
-
-               if (header.packet_type <= 1) {
-                       add_item_to_tree(nbipx_tree, offset+33, 1,
-                                       "Packet Type: %s (%02X)", packet_type[header.packet_type],
-                                       header.packet_type);
-               }
-               else {
-                       add_item_to_tree(nbipx_tree, offset+33, 1,
-                                       "Packet Type: Unknown (%02X)", header.packet_type);
+               ti = proto_tree_add_item(tree, proto_nbipx, tvb, offset,
+                   2+NETBIOS_NAME_LEN+NETBIOS_NAME_LEN, FALSE);
+               nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
+
+               proto_tree_add_text(nbipx_tree, tvb, offset, 1,
+                   "Connection control: 0x%02x", tvb_get_guint8(tvb, offset));
+               offset += 1;
+
+               packet_type = tvb_get_guint8(tvb, offset);
+               proto_tree_add_text(nbipx_tree, tvb, offset, 1,
+                               "Packet Type: %s (%02X)",
+                               val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
+                               packet_type);
+               offset += 1;
+
+               if (!netbios_add_name("Receiver's Name", tvb, offset,
+                   nbipx_tree))
+                       return;
+               offset += NETBIOS_NAME_LEN;
+
+               if (!netbios_add_name("Sender's Name", tvb, offset,
+                   nbipx_tree))
+                       return;
+               offset += NETBIOS_NAME_LEN;
+
+               if (tvb_length_remaining(tvb, offset) != 0) {
+                       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+                       tvb_compat(next_tvb, &next_pd, &next_offset);
+                       dissect_smb(next_pd, next_offset, pinfo->fd, tree,
+                           tvb_length(next_tvb));
                }
+       }
+}
 
-               /* Eight routers are listed */
-               for (i = 0; i < 8; i++) {
-                       rtr_offset = offset + (i << 2);
-                       memcpy(&header.router[i], &pd[rtr_offset], 4);
-                       if (header.router[i] != 0) {
-                               add_item_to_tree(nbipx_tree, rtr_offset, 4, "IPX Network: %s",
-                                               ipxnet_to_string((guint8*)&header.router[i]));
-                       }
-               }
-
-               add_item_to_tree(nbipx_tree, offset+32, 1, "Name Type: %02X",
-                               header.name_type);
-
-               if (nbipx == NETBIOS_NETWARE) {
-                       add_item_to_tree(nbipx_tree, offset+name_offset, 16,
-                                       "Name String: %s", header.name);
+static void
+dissect_nwlink_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       proto_tree      *nbipx_tree;
+       proto_item      *ti;
+       int             offset = 0;
+       guint8          packet_type;
+       guint8          name_type_flag;
+       proto_tree      *name_type_flag_tree;
+       proto_item      *tf;
+       char            name[(NETBIOS_NAME_LEN - 1)*4 + 1];
+       int             name_type;
+       char            node_name[(NETBIOS_NAME_LEN - 1)*4 + 1];
+       int             node_name_type = 0;
+       tvbuff_t        *next_tvb;
+       const guint8    *next_pd;
+       int             next_offset;
+
+       name_type_flag = tvb_get_guint8(tvb, offset+32);
+       packet_type = tvb_get_guint8(tvb, offset+33);
+       name_type = get_netbios_name(tvb, offset+36, name);
+       node_name_type = get_netbios_name(tvb, offset+52, node_name);
+
+       if (check_col(pinfo->fd, COL_PROTOCOL))
+               col_add_str(pinfo->fd, COL_PROTOCOL, "NWLink");
+
+       if (check_col(pinfo->fd, COL_INFO)) {
+               /*
+                * XXX - Microsoft Network Monitor thinks that the octet
+                * at 32 is a packet type, e.g. "mailslot write" for
+                * browser announcements, and that the octet at 33 is a
+                * name type, in the sense of the 16th byte of a
+                * NetBIOS name.
+                *
+                * A name type of 2 shows up in a "host announcement",
+                * and a name type of 3 shows up in a "local master
+                * annoumcement", so maybe that field really *is* a
+                * name type - the fact that it's not associated with
+                * any of the NetBIOS names in the packet nonwithstanding.
+                *
+                * I haven't seen any packets with the name type octet
+                * being anything other than 2 or 3, so I don't know
+                * whether those are name service operations; however,
+                * given that NWLink, unlike socket-0x0455 NBIPX,
+                * has separate sockets for name queries and datagrams,
+                * it may be that this really is a name type, and that
+                * these are all datagrams, not name queries.
+                */
+               switch (packet_type) {
+               case NWLINK_NAME_QUERY:
+                       col_add_fstr(pinfo->fd, COL_INFO, "Name Query for %s<%02x>",
+                                       name, name_type);
+                       break;
+
+               case NWLINK_SMB:
+                       /* Session? */
+                       col_add_fstr(pinfo->fd, COL_INFO, "SMB over NBIPX");
+                       break;
+
+               case NWLINK_NETBIOS_DATAGRAM:
+                       /* Datagram? (Where did we see this?) */
+                       col_add_fstr(pinfo->fd, COL_INFO, "NetBIOS datagram over NBIPX");
+                       break;
+                               
+               default:
+                       col_add_str(pinfo->fd, COL_INFO, "NetBIOS over IPX (NWLink)");
+                       break;
                }
-               else {
-                       add_item_to_tree(nbipx_tree, offset+name_offset, 16,
-                                       "Group Name String: %s", header.name);
-                       add_item_to_tree(nbipx_tree, offset+52, 16,
-                                       "Node Name String: %s", header.node_name);
+       }
 
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_nbipx, tvb, offset, 68, FALSE);
+               nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
+
+               add_routers(nbipx_tree, tvb, offset);
+
+               /*
+                * XXX - is "packet_type" really a packet type?  See
+                * above.
+                */
+               if (packet_type != NWLINK_SMB &&
+                     packet_type != NWLINK_NETBIOS_DATAGRAM) {
+                       tf = proto_tree_add_text(nbipx_tree, tvb, offset+32, 1,
+                               "Name type flag: 0x%02x",
+                               name_type_flag);
+                       name_type_flag_tree = proto_item_add_subtree(tf,
+                                       ett_nbipx_name_type_flags);
+                       proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                           1, "%s",
+                           decode_boolean_bitfield(name_type_flag, 0x80, 8,
+                             "Group name", "Unique name"));
+                       proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                           1, "%s",
+                           decode_boolean_bitfield(name_type_flag, 0x40, 8,
+                             "Name in use", "Name not used"));
+                       proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                           1, "%s",
+                           decode_boolean_bitfield(name_type_flag, 0x04, 8,
+                             "Name registered", "Name not registered"));
+                       proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                           1, "%s",
+                           decode_boolean_bitfield(name_type_flag, 0x02, 8,
+                             "Name duplicated", "Name not duplicated"));
+                       proto_tree_add_text(name_type_flag_tree, tvb, offset+32,
+                           1, "%s",
+                           decode_boolean_bitfield(name_type_flag, 0x01, 8,
+                             "Name deregistered", "Name not deregistered"));
+
+                       if (!netbios_add_name("Group name", tvb, offset+36,
+                           nbipx_tree))
+                               return;
+                       if (!netbios_add_name("Node name", tvb, offset+52,
+                           nbipx_tree))
+                               return;
+                       proto_tree_add_text(nbipx_tree, tvb, offset+33, 1,
+                           "Packet Type: %s (%02X)",
+                           val_to_str(packet_type, nwlink_data_stream_type_vals, "Unknown"),
+                           packet_type);
+               } else {
+                       proto_tree_add_text(nbipx_tree, tvb, offset+32, 1,
+                           "Packet type: 0x%02x", name_type_flag);
+                       proto_tree_add_text(nbipx_tree, tvb, offset+33, 1,
+                           "Name Type: %s (0x%02x)",
+                           netbios_name_type_descr(packet_type),
+                           packet_type);
+                       proto_tree_add_text(nbipx_tree, tvb, offset+34, 2,
+                           "Message ID: 0x%04x",
+                           tvb_get_letohs(tvb, offset+34));
+                       if (!netbios_add_name("Requested name", tvb, offset+36,
+                           nbipx_tree))
+                               return;
+                       if (!netbios_add_name("Source name", tvb, offset+52,
+                           nbipx_tree))
+                               return;
                }
        }
 
-       if (nbipx == NETBIOS_NWLINK) {
-               dissect_data(pd, offset + 68, fd, tree);
+       offset += 68;
+
+       if (tvb_length_remaining(tvb, offset) != 0) {
+               next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+
+               switch (packet_type) {
+               case NWLINK_SMB:
+               case NWLINK_NETBIOS_DATAGRAM:
+                       tvb_compat(next_tvb, &next_pd, &next_offset);
+                       dissect_smb(next_pd, next_offset, pinfo->fd, tree,
+                           tvb_length(next_tvb));
+                       break;
+                               
+               default:
+                       dissect_data(next_tvb, pinfo, tree);
+                       break;
+               }
        }
 }
 
+void
+proto_register_nbipx(void)
+{
+/*        static hf_register_info hf[] = {
+                { &variable,
+                { "Name",           "nbipx.abbreviation", TYPE, VALS_POINTER }},
+        };*/
+       static gint *ett[] = {
+               &ett_nbipx,
+               &ett_nbipx_name_type_flags,
+       };
+
+        proto_nbipx = proto_register_protocol("NetBIOS over IPX", "nbipx");
+ /*       proto_register_field_array(proto_nbipx, hf, array_length(hf));*/
+       proto_register_subtree_array(ett, array_length(ett));
+}
 
-
-
+void
+proto_reg_handoff_nbipx(void)
+{
+       dissector_add("ipx.socket", IPX_SOCKET_NWLINK_SMB_DGRAM, dissect_nwlink_dg);
+}