Make various lengths unsigned in "dissect_fhandle_data_unknown()", so
[obnox/wireshark/wip.git] / packet-ipx.c
index 23fece10d22f16892d46f7955a76283e11565377..ccad627d8ee1fe23e9119280a072885a61105d9c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 2000-2002 by Gilbert Ramirez.
  * Portions Copyright (c) Novell, Inc. 2002-2003
  *
- * $Id: packet-ipx.c,v 1.127 2003/04/12 05:36:10 guy Exp $
+ * $Id: packet-ipx.c,v 1.136 2003/08/24 05:37:57 sahlberg Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -43,6 +43,9 @@
 #include "aftypes.h"
 #include "arcnet_pids.h"
 #include <epan/conversation.h>
+#include "tap.h"
+
+static int ipx_tap = -1;
 
 #define SPX_PACKET_INIT_COUNT  200
 
@@ -68,6 +71,9 @@ static int hf_ipx_dsocket = -1;
 static int hf_ipx_snet = -1;
 static int hf_ipx_snode = -1;
 static int hf_ipx_ssocket = -1;
+static int hf_ipx_net = -1;
+static int hf_ipx_node = -1;
+static int hf_ipx_socket = -1;
 
 static gint ett_ipx = -1;
 
@@ -223,16 +229,26 @@ dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        tvbuff_t        *next_tvb;
 
-       proto_tree      *ipx_tree;
-       proto_item      *ti;
+       proto_tree      *ipx_tree = NULL;
+       proto_item      *ti = NULL;
 
        const guint8    *src_net_node, *dst_net_node;
 
-       guint8          ipx_type, ipx_hops;
-       guint16         ipx_length;
+       guint8          ipx_hops;
 
-       guint16         ipx_dsocket, ipx_ssocket;
        guint16         first_socket, second_socket;
+       guint32         ipx_snet, ipx_dnet;
+       const guint8    *ipx_snode, *ipx_dnode;
+       static ipxhdr_t ipxh_arr[4];
+       static int ipx_current=0;
+       ipxhdr_t *ipxh;
+
+       ipx_current++;
+       if(ipx_current==4){
+               ipx_current=0;
+       }
+       ipxh=&ipxh_arr[ipx_current];
+
 
        if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX");
@@ -240,63 +256,85 @@ dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                col_clear(pinfo->cinfo, COL_INFO);
 
        /* Calculate here for use in pinfo and in tree */
-       ipx_dsocket     = tvb_get_ntohs(tvb, 16);
-       ipx_ssocket     = tvb_get_ntohs(tvb, 28);
-       ipx_type        = tvb_get_guint8(tvb, 5);
-       ipx_length      = tvb_get_ntohs(tvb, 2);
+       ipxh->ipx_dsocket = tvb_get_ntohs(tvb, 16);
+       ipxh->ipx_ssocket = tvb_get_ntohs(tvb, 28);
+       ipxh->ipx_type    = tvb_get_guint8(tvb, 5);
+       ipxh->ipx_length  = tvb_get_ntohs(tvb, 2);
 
        pinfo->ptype = PT_IPX;
-       pinfo->srcport = ipx_ssocket;
-       pinfo->destport = ipx_dsocket;
+       pinfo->srcport = ipxh->ipx_ssocket;
+       pinfo->destport = ipxh->ipx_dsocket;
 
        /* Adjust the tvbuff length to include only the IPX datagram. */
-       set_actual_length(tvb, ipx_length);
+       set_actual_length(tvb, ipxh->ipx_length);
 
        src_net_node = tvb_get_ptr(tvb, 18, 10);
        dst_net_node = tvb_get_ptr(tvb, 6,  10);
 
        SET_ADDRESS(&pinfo->net_src,    AT_IPX, 10, src_net_node);
        SET_ADDRESS(&pinfo->src,        AT_IPX, 10, src_net_node);
+       SET_ADDRESS(&ipxh->ipx_src,     AT_IPX, 10, src_net_node);
        SET_ADDRESS(&pinfo->net_dst,    AT_IPX, 10, dst_net_node);
        SET_ADDRESS(&pinfo->dst,        AT_IPX, 10, dst_net_node);
+       SET_ADDRESS(&ipxh->ipx_dst,     AT_IPX, 10, dst_net_node);
 
        if (check_col(pinfo->cinfo, COL_INFO))
                col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%04x)",
-                               socket_text(ipx_dsocket), ipx_dsocket);
+                               socket_text(ipxh->ipx_dsocket), ipxh->ipx_dsocket);
 
        if (tree) {
 
                ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
                ipx_tree = proto_item_add_subtree(ti, ett_ipx);
-
-               proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
-               proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
-                       "Length: %d bytes", ipx_length);
-               ipx_hops = tvb_get_guint8(tvb, 4);
-               proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
-                       "Transport Control: %d hops", ipx_hops);
-               proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
-
-               /* Destination */
-               proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
-               proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
-               proto_tree_add_uint(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
-                       ipx_dsocket);
-
-               /* Source */
-               proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
-               proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
-               proto_tree_add_uint(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
-                       ipx_ssocket);
        }
 
+       proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
+       proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipxh->ipx_length,
+               "Length: %d bytes", ipxh->ipx_length);
+       ipx_hops = tvb_get_guint8(tvb, 4);
+       proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
+               "Transport Control: %d hops", ipx_hops);
+       proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipxh->ipx_type);
+
+       /* Destination */
+       ipx_dnet = tvb_get_ntohl(tvb, 6);
+       proto_tree_add_ipxnet(ipx_tree, hf_ipx_dnet, tvb, 6, 4,
+               ipx_dnet);
+       proto_tree_add_ipxnet_hidden(ipx_tree, hf_ipx_net, tvb, 6, 4,
+               ipx_dnet);
+       ipx_dnode = tvb_get_ptr(tvb, 10,  6);
+       proto_tree_add_ether(ipx_tree, hf_ipx_dnode, tvb, 10, 6,
+               ipx_dnode);
+       proto_tree_add_ether_hidden(ipx_tree, hf_ipx_node, tvb, 10, 6,
+               ipx_dnode);
+       proto_tree_add_uint(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
+               ipxh->ipx_dsocket);
+       proto_tree_add_uint_hidden(ipx_tree, hf_ipx_socket, tvb, 16, 2,
+               ipxh->ipx_dsocket);
+
+       /* Source */
+       ipx_snet = tvb_get_ntohl(tvb, 18);
+       proto_tree_add_ipxnet(ipx_tree, hf_ipx_snet, tvb, 18, 4,
+               ipx_snet);
+       proto_tree_add_ipxnet_hidden(ipx_tree, hf_ipx_net, tvb, 18, 4,
+               ipx_snet);
+       ipx_snode = tvb_get_ptr(tvb, 22, 6);
+       proto_tree_add_ether(ipx_tree, hf_ipx_snode, tvb, 22, 6,
+               ipx_snode);
+       proto_tree_add_ether_hidden(ipx_tree, hf_ipx_node, tvb, 22, 6,
+               ipx_snode);
+       proto_tree_add_uint(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
+               ipxh->ipx_ssocket);
+       proto_tree_add_uint_hidden(ipx_tree, hf_ipx_socket, tvb, 28, 2,
+               ipxh->ipx_ssocket);
+
        /* Make the next tvbuff */
        next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN, -1, -1);
 
        /*
         * Let the subdissector know what type of IPX packet this is.
         */
-       pinfo->ipxptype = ipx_type;
+       pinfo->ipxptype = ipxh->ipx_type;
 
        /*
         * Check the socket numbers before we check the packet type;
@@ -325,13 +363,16 @@ dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         * IPX_SOCKET_NWLINK_SMB_NAMEQUERY, we assume that it's a
         * NMPI query, and test only that socket.
         */
-       if (ipx_ssocket > ipx_dsocket) {
-               first_socket = ipx_dsocket;
-               second_socket = ipx_ssocket;
+       if (ipxh->ipx_ssocket > ipxh->ipx_dsocket) {
+               first_socket = ipxh->ipx_dsocket;
+               second_socket = ipxh->ipx_ssocket;
        } else {
-               first_socket = ipx_ssocket;
-               second_socket = ipx_dsocket;
+               first_socket = ipxh->ipx_ssocket;
+               second_socket = ipxh->ipx_dsocket;
        }
+
+       tap_queue_packet(ipx_tap, pinfo, ipxh);
+
        if (second_socket != IPX_SOCKET_NWLINK_SMB_NAMEQUERY) {
                if (dissector_try_port(ipx_socket_dissector_table, first_socket,
                    next_tvb, pinfo, tree))
@@ -345,7 +386,7 @@ dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         * Neither of them are known; try the packet type, which will
         * at least let us, for example, dissect SPX packets as SPX.
         */
-       if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_tvb,
+       if (dissector_try_port(ipx_type_dissector_table, ipxh->ipx_type, next_tvb,
            pinfo, tree))
                return;
 
@@ -357,11 +398,11 @@ dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
 typedef struct {
        conversation_t  *conversation;
-       guint32             spx_src;
+       guint32         spx_src;
+       guint16         spx_seq;
 } spx_hash_key;
 
 typedef struct {
-        guint16             spx_seq;
         guint16             spx_ack;
         guint16             spx_all;
         guint32             num;
@@ -388,7 +429,8 @@ spx_equal(gconstpointer v, gconstpointer v2)
        const spx_hash_key      *val2 = (const spx_hash_key*)v2;
 
        if (val1->conversation == val2->conversation &&
-           val1->spx_src  == val2->spx_src ) {
+           val1->spx_src == val2->spx_src &&
+           val1->spx_seq == val2->spx_seq) {
                return 1;
        }
        return 0;
@@ -456,7 +498,7 @@ spx_postseq_cleanup(void)
 }
 
 spx_hash_value*
-spx_hash_insert(conversation_t *conversation, guint32 spx_src)
+spx_hash_insert(conversation_t *conversation, guint32 spx_src, guint16 spx_seq)
 {
        spx_hash_key            *key;
        spx_hash_value          *value;
@@ -465,9 +507,9 @@ spx_hash_insert(conversation_t *conversation, guint32 spx_src)
        key = g_mem_chunk_alloc(spx_hash_keys);
        key->conversation = conversation;
        key->spx_src = spx_src;
+       key->spx_seq = spx_seq;
 
        value = g_mem_chunk_alloc(spx_hash_values);
-       value->spx_seq = 0;
        value->spx_ack = 0;
        value->spx_all = 0;
        value->num = 0;
@@ -479,12 +521,13 @@ spx_hash_insert(conversation_t *conversation, guint32 spx_src)
 
 /* Returns the spx_hash_value*, or NULL if not found. */
 spx_hash_value*
-spx_hash_lookup(conversation_t *conversation, guint32 spx_src)
+spx_hash_lookup(conversation_t *conversation, guint32 spx_src, guint32 spx_seq)
 {
        spx_hash_key            key;
 
        key.conversation = conversation;
        key.spx_src = spx_src;
+       key.spx_seq = spx_seq;
 
        return g_hash_table_lookup(spx_hash, &key);
 }
@@ -504,6 +547,7 @@ spx_conn_ctrl(guint8 ctrl)
        const char *p;
 
        static const value_string conn_vals[] = {
+               { 0x00,                        "Data, No Ack Required" },
                { SPX_EOM,                     "End-of-Message" },
                { SPX_ATTN,                    "Attention" },
                { SPX_SEND_ACK,                "Acknowledgment Required"},
@@ -532,7 +576,7 @@ spx_datastream(guint8 type)
                case 0xff:
                        return "End-of-Connection Acknowledgment";
                default:
-                       return "Client-Defined";
+                       return NULL;
        }
 }
 
@@ -547,6 +591,8 @@ dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        guint8          conn_ctrl;
        proto_tree      *cc_tree;
        guint8          datastream_type;
+       const char      *datastream_type_string;
+       guint16         spx_seq;
        const char      *spx_msg_string;
        guint16         low_socket, high_socket;
        guint32         src;
@@ -586,15 +632,31 @@ dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        datastream_type = tvb_get_guint8(tvb, 1);
+       datastream_type_string = spx_datastream(datastream_type);
+       if (datastream_type_string != NULL) {
+               if (check_col(pinfo->cinfo, COL_INFO))
+                       col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
+                           datastream_type_string);
+       }
        if (tree) {
-               proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
-                                          1, 1, datastream_type,
-                                          "Datastream Type: %s (0x%02X)",
-                                          spx_datastream(datastream_type), datastream_type);
-
+               if (datastream_type_string != NULL) {
+                       proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
+                                                  1, 1, datastream_type,
+                                                  "Datastream Type: %s (0x%02X)",
+                                                  datastream_type_string,
+                                                  datastream_type);
+               } else {
+                       proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
+                                                  1, 1, datastream_type,
+                                                  "Datastream Type: 0x%02X",
+                                                  datastream_type);
+               }
                proto_tree_add_item(spx_tree, hf_spx_src_id, tvb,  2, 2, FALSE);
                proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb,  4, 2, FALSE);
-               proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb,  6, 2, FALSE);
+       }
+       spx_seq = tvb_get_ntohs(tvb, 6);
+       if (tree) {
+               proto_tree_add_uint(spx_tree, hf_spx_seq_nr, tvb,  6, 2, spx_seq);
                proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb,  8, 2, FALSE);
                proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
        }
@@ -614,67 +676,94 @@ dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         * we should probably use the direction, as well as the conversation,
         * as part of the hash key; if we do that, we can probably just
         * use PT_IPX as the port type, and possibly get rid of PT_NCP.
+        *
+        * According to
+        *
+        *      http://developer.novell.com/research/appnotes/1995/december/03/apv.htm
+        *
+        * the sequence number is not incremented for system packets, so
+        * presumably that means there is no notion of a system packet
+        * being retransmitted; that document also says that system
+        * packets are used as "I'm still here" keepalives and as
+        * acknowledgements (presumably meaning ACK-only packets), which
+        * suggests that they might not be ACKed and thus might not
+        * be retransmitted.
         */
-       if (!pinfo->fd->flags.visited) {
-               conversation = find_conversation(&pinfo->src, &pinfo->dst,
-                   PT_NCP, pinfo->srcport, pinfo->srcport, 0);
-               if (conversation == NULL) {
-                       /*
-                        * It's not part of any conversation - create a new
-                        * one.
-                        */
-                       conversation = conversation_new(&pinfo->src,
-                           &pinfo->dst, PT_NCP, pinfo->srcport,
-                           pinfo->srcport, 0);
-               }
-
+       if (conn_ctrl & SPX_SYS_PACKET) {
                /*
-                * Now we'll hash the SPX header and use the result of that,
-                * plus the conversation, as a hash key to identify this
-                * packet.
-                *
-                * If we don't find it in the hash table, it's not a
-                * retransmission, otherwise it is.  If we don't find it,
-                * we enter it into the hash table, with the frame number.
-                * If we do, we attach to this frame a structure giving
-                * the frame number of the original transmission, so that
-                * we, and subdissectors, know it's a retransmission.
+                * It's a system packet, so it isn't a retransmission.
                 */
-               src = tvb_get_ntohs(tvb, 0)+tvb_get_ntohs(tvb, 2)+tvb_get_ntohs(tvb, 4)+tvb_get_ntohs(tvb, 6)+tvb_get_ntohs(tvb, 8);
-               pkt_value = spx_hash_lookup(conversation, src);
-               if (pkt_value == NULL) {
-                       /*
-                        * Not found in the hash table.
-                        * Enter it into the hash table.
-                        */
-                       pkt_value = spx_hash_insert(conversation, src);
-                       pkt_value->spx_seq = tvb_get_ntohs(tvb, 6);
-                       pkt_value->spx_ack = tvb_get_ntohs(tvb, 8);
-                       pkt_value->spx_all = tvb_get_ntohs(tvb, 10);
-                       pkt_value->num = pinfo->fd->num;
+               spx_rexmit_info = NULL;
+       } else {
+               /*
+                * Not a system packet - check for retransmissions.
+                */
+               if (!pinfo->fd->flags.visited) {
+                       conversation = find_conversation(&pinfo->src,
+                           &pinfo->dst, PT_NCP, pinfo->srcport,
+                           pinfo->srcport, 0);
+                       if (conversation == NULL) {
+                               /*
+                                * It's not part of any conversation - create
+                                * a new one.
+                                */
+                               conversation = conversation_new(&pinfo->src,
+                                   &pinfo->dst, PT_NCP, pinfo->srcport,
+                                   pinfo->srcport, 0);
+                       }
 
                        /*
-                        * This is not a retransmission, so we shouldn't
-                        * have any retransmission indicator.
+                        * Now we'll hash the SPX header and use the result
+                        * of that, plus the conversation, as a hash key to
+                        * identify this packet.
+                        *
+                        * If we don't find it in the hash table, it's not a
+                        * retransmission, otherwise it is.  If we don't find
+                        * it, we enter it into the hash table, with the
+                        * frame number.
+                        * If we do, we attach to this frame a structure giving
+                        * the frame number of the original transmission, so
+                        * that we, and subdissectors, know it's a
+                        * retransmission.
                         */
-                       spx_rexmit_info = NULL;
+                       src = tvb_get_ntohs(tvb, 0)+tvb_get_ntohs(tvb, 2)+tvb_get_ntohs(tvb, 4)+tvb_get_ntohs(tvb, 6)+tvb_get_ntohs(tvb, 8);
+                       pkt_value = spx_hash_lookup(conversation, src, spx_seq);
+                       if (pkt_value == NULL) {
+                               /*
+                                * Not found in the hash table.
+                                * Enter it into the hash table.
+                                */
+                               pkt_value = spx_hash_insert(conversation, src,
+                                   spx_seq);
+                               pkt_value->spx_ack = tvb_get_ntohs(tvb, 8);
+                               pkt_value->spx_all = tvb_get_ntohs(tvb, 10);
+                               pkt_value->num = pinfo->fd->num;
+
+                               /*
+                                * This is not a retransmission, so we shouldn't
+                                * have any retransmission indicator.
+                                */
+                               spx_rexmit_info = NULL;
+                       } else {
+                               /*
+                                * Found in the hash table.  Mark this frame as
+                                * a retransmission.
+                                */
+                               spx_rexmit_info = g_mem_chunk_alloc(spx_rexmit_infos);
+                               spx_rexmit_info->num = pkt_value->num;
+                               p_add_proto_data(pinfo->fd, proto_spx,
+                                   spx_rexmit_info);
+                       }
                } else {
                        /*
-                        * Found in the hash table.  Mark this frame as
-                        * a retransmission.
+                        * Do we have per-packet SPX data for this frame?
+                        * If so, it's a retransmission, and the per-packet
+                        * data indicates which frame had the original
+                        * transmission.
                         */
-                       spx_rexmit_info = g_mem_chunk_alloc(spx_rexmit_infos);
-                       spx_rexmit_info->num = pkt_value->num;
-                       p_add_proto_data(pinfo->fd, proto_spx, spx_rexmit_info);
+                       spx_rexmit_info = p_get_proto_data(pinfo->fd,
+                           proto_spx);
                }
-       } else {
-               /*
-                * Do we have per-packet SPX data for this frame?
-                * If so, it's a retransmission, and the per-packet
-                * data indicates which frame had the original
-                * transmission.
-                */
-               spx_rexmit_info = p_get_proto_data(pinfo->fd, proto_spx);
        }
 
        /*
@@ -1226,6 +1315,19 @@ proto_register_ipx(void)
                { "Source Socket",      "ipx.src.socket", FT_UINT16, BASE_HEX,
                        VALS(ipx_socket_vals), 0x0,
                        "", HFILL }},
+
+               { &hf_ipx_net,
+               { "Source or Destination Network","ipx.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+
+               { &hf_ipx_node,
+               { "Source or Destination Node", "ipx.node", FT_ETHER, BASE_NONE, NULL, 0x0,
+                       "", HFILL }},
+        
+               { &hf_ipx_socket,
+               { "Source or Destination Socket", "ipx.socket", FT_UINT16, BASE_HEX,
+                       VALS(ipx_socket_vals), 0x0,
+                       "", HFILL }},
        };
 
        static hf_register_info hf_spx[] = {
@@ -1371,6 +1473,7 @@ proto_register_ipx(void)
        
        register_init_routine(&spx_init_protocol);
        register_postseq_cleanup_routine(&spx_postseq_cleanup);
+        ipx_tap=register_tap("ipx");
 }
 
 void
@@ -1385,7 +1488,8 @@ proto_reg_handoff_ipx(void)
        dissector_add("ethertype", ETHERTYPE_IPX, ipx_handle);
        dissector_add("chdlctype", ETHERTYPE_IPX, ipx_handle);
        dissector_add("ppp.protocol", PPP_IPX, ipx_handle);
-       dissector_add("llc.dsap", SAP_NETWARE, ipx_handle);
+       dissector_add("llc.dsap", SAP_NETWARE1, ipx_handle);
+       dissector_add("llc.dsap", SAP_NETWARE2, ipx_handle);
        dissector_add("null.type", BSD_AF_IPX, ipx_handle);
        dissector_add("gre.proto", ETHERTYPE_IPX, ipx_handle);
        dissector_add("arcnet.protocol_id", ARCNET_PROTO_IPX, ipx_handle);