* 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>
#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
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;
{
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");
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;
* 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))
* 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;
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;
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;
}
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;
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;
/* 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);
}
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"},
case 0xff:
return "End-of-Connection Acknowledgment";
default:
- return "Client-Defined";
+ return NULL;
}
}
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;
}
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);
}
* 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);
}
/*
{ "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[] = {
register_init_routine(&spx_init_protocol);
register_postseq_cleanup_routine(&spx_postseq_cleanup);
+ ipx_tap=register_tap("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);