* Portions Copyright (c) 2000-2002 by Gilbert Ramirez.
* Portions Copyright (c) Novell, Inc. 2002-2003
*
- * $Id: packet-ipx.c,v 1.124 2003/04/08 02:00:53 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;
static int proto_spx = -1;
static int hf_spx_connection_control = -1;
+static int hf_spx_connection_control_sys = -1;
+static int hf_spx_connection_control_send_ack = -1;
+static int hf_spx_connection_control_attn = -1;
+static int hf_spx_connection_control_eom = -1;
static int hf_spx_datastream_type = -1;
static int hf_spx_src_id = -1;
static int hf_spx_dst_id = -1;
static int hf_spx_seq_nr = -1;
static int hf_spx_ack_nr = -1;
static int hf_spx_all_nr = -1;
+static int hf_spx_rexmt_frame = -1;
static gint ett_spx = -1;
+static gint ett_spx_connctrl = -1;
static int proto_ipxrip = -1;
static int hf_ipxrip_request = -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_ack;
+ guint16 spx_all;
+ guint32 num;
+} spx_hash_value;
+
+/*
+ * Structure attached to retransmitted SPX frames; it contains the
+ * frame number of the original transmission.
+ */
+typedef struct {
+ guint32 num;
+} spx_rexmit_info;
+
static GHashTable *spx_hash = NULL;
static GMemChunk *spx_hash_keys = NULL;
static GMemChunk *spx_hash_values = NULL;
+static GMemChunk *spx_rexmit_infos = NULL;
/* Hash Functions */
gint
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;
g_mem_chunk_destroy(spx_hash_keys);
if (spx_hash_values)
g_mem_chunk_destroy(spx_hash_values);
+ if (spx_rexmit_infos)
+ g_mem_chunk_destroy(spx_rexmit_infos);
spx_hash = g_hash_table_new(spx_hash_func, spx_equal);
spx_hash_keys = g_mem_chunk_new("spx_hash_keys",
SPX_PACKET_INIT_COUNT * sizeof(spx_hash_key),
G_ALLOC_ONLY);
spx_hash_values = g_mem_chunk_new("spx_hash_values",
- sizeof(spx_info),
- SPX_PACKET_INIT_COUNT * sizeof(spx_info),
+ sizeof(spx_hash_value),
+ SPX_PACKET_INIT_COUNT * sizeof(spx_hash_value),
+ G_ALLOC_ONLY);
+ spx_rexmit_infos = g_mem_chunk_new("spx_rexmit_infos",
+ sizeof(spx_rexmit_infos),
+ SPX_PACKET_INIT_COUNT * sizeof(spx_rexmit_infos),
G_ALLOC_ONLY);
}
-/* After the sequential run, we don't need the spx hash and keys
- * anymore; the lookups have already been done and the vital info
- * saved in the reply-packets' private_data in the frame_data struct. */
+/* After the sequential run, we don't need the spx hash table, or
+ * the keys and values, anymore; the lookups have already been done
+ * and the relevant info saved as SPX private data with the frame
+ * if the frame was a retransmission. */
static void
spx_postseq_cleanup(void)
{
g_mem_chunk_destroy(spx_hash_keys);
spx_hash_keys = NULL;
}
- /* Don't free the spx_hash_values, as they're
+ if (spx_hash_values) {
+ g_mem_chunk_destroy(spx_hash_values);
+ spx_hash_values = NULL;
+ }
+ /* Don't free the spx_rexmit_infos, as they're
* needed during random-access processing of the proto_tree.*/
}
-spx_info*
-spx_hash_insert(conversation_t *conversation, guint32 spx_src)
+spx_hash_value*
+spx_hash_insert(conversation_t *conversation, guint32 spx_src, guint16 spx_seq)
{
spx_hash_key *key;
- spx_info *value;
+ spx_hash_value *value;
/* Now remember the packet, so we can find it if we later. */
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;
-
+
g_hash_table_insert(spx_hash, key, value);
return value;
}
-/* Returns the spx_rec*, or NULL if not found. */
-spx_info*
-spx_hash_lookup(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, 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);
}
/* ================================================================= */
/* SPX */
/* ================================================================= */
+
+#define SPX_SYS_PACKET 0x80
+#define SPX_SEND_ACK 0x40
+#define SPX_ATTN 0x20
+#define SPX_EOM 0x10
+
static const char*
spx_conn_ctrl(guint8 ctrl)
{
const char *p;
static const value_string conn_vals[] = {
- { 0x10, "End-of-Message" },
- { 0x20, "Attention" },
- { 0x40, "Acknowledgment Required"},
- { 0x50, "Send Ack: End Message"},
- { 0x80, "System Packet"},
- { 0xc0, "System Packet: Send Ack"},
- { 0x00, NULL }
+ { 0x00, "Data, No Ack Required" },
+ { SPX_EOM, "End-of-Message" },
+ { SPX_ATTN, "Attention" },
+ { SPX_SEND_ACK, "Acknowledgment Required"},
+ { SPX_SEND_ACK|SPX_EOM, "Send Ack: End Message"},
+ { SPX_SYS_PACKET, "System Packet"},
+ { SPX_SYS_PACKET|SPX_SEND_ACK, "System Packet: Send Ack"},
+ { 0x00, NULL }
};
p = match_strval((ctrl & 0xf0), conn_vals );
case 0xff:
return "End-of-Connection Acknowledgment";
default:
- return "Client-Defined";
+ return NULL;
}
}
proto_tree *spx_tree = NULL;
proto_item *ti;
tvbuff_t *next_tvb;
-
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;
- spx_info *pkt_value = NULL;
- conversation_t *conversation = NULL;
+ conversation_t *conversation;
+ spx_hash_value *pkt_value;
+ spx_rexmit_info *spx_rexmit_info;
+ spx_info spx_info;
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPX");
if (check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO, " %s", spx_msg_string);
if (tree) {
- proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
- 0, 1, conn_ctrl,
- "Connection Control: %s (0x%02X)",
- spx_msg_string, conn_ctrl);
-
- datastream_type = tvb_get_guint8(tvb, 1);
- 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);
+ ti = proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
+ 0, 1, conn_ctrl,
+ "Connection Control: %s (0x%02X)",
+ spx_msg_string, conn_ctrl);
+ cc_tree = proto_item_add_subtree(ti, ett_spx_connctrl);
+ proto_tree_add_boolean(cc_tree, hf_spx_connection_control_sys, tvb,
+ 0, 1, conn_ctrl);
+ proto_tree_add_boolean(cc_tree, hf_spx_connection_control_send_ack, tvb,
+ 0, 1, conn_ctrl);
+ proto_tree_add_boolean(cc_tree, hf_spx_connection_control_attn, tvb,
+ 0, 1, conn_ctrl);
+ proto_tree_add_boolean(cc_tree, hf_spx_connection_control_eom, tvb,
+ 0, 1, conn_ctrl);
+ }
+ 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) {
+ 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);
}
/*
* SPX is Connection Oriented and Delivery Guaranteed.
- * We need to flag retransmissions by the SPX protocol, so that
- * subdissectors know whether a packet was retransmitted.
+ * On the first pass, we need to flag retransmissions by the SPX
+ * protocol, so that subdissectors know whether a packet was
+ * retransmitted.
*
- * We start out by creating a conversation for this IPX session.
- * XXX - should we be using "pinfo->srcport" twice, or
- * "pinfo->srcport" and "pinfo->destport"? For that matter, should
- * we just be using PT_IPX, and get rid of PT_NCP?
- */
- 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);
- }
-
- /*
- * Now we'll hash the SPX header and use the result of that,
- * plus the conversation, as a hash key to identify this packet,
- * and, if it's not already in the SPX packet hash table, enter
- * it into that hash table so we can detect retransmissions.
+ * We start out by creating a conversation for this direction of the
+ * IPX session; we use "pinfo->srcport" twice, so that we have
+ * separate conversations for the two directions.
+ *
+ * XXX - that might not work correctly if there's more than one
+ * SPX session using that source port; can that happen? If so,
+ * 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
*
- * On the first pass, 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.
+ * http://developer.novell.com/research/appnotes/1995/december/03/apv.htm
*
- * On subsequent passes, we should find it in the frame table
- * whether it's a retransmission or not; it's a retransmission
- * iff the frame number doesn't match the frame number in the
- * hash table.
+ * 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.
*/
- 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) {
+ if (conn_ctrl & SPX_SYS_PACKET) {
/*
- * Not found in the hash table.
- * Enter it into the hash table.
+ * It's a system packet, so it isn't a retransmission.
*/
- 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);
+ }
+
+ /*
+ * 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.
+ */
+ 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 {
+ /*
+ * 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);
+ }
}
/*
- * It's a retransmission iff the frame number in the hash table
- * entry (which is the frame number of the original transmission)
- * isn't the frame number of this frame.
- *
- * XXX - put something into the protocol tree as well?
- * If so, give the frame number, as an FT_FRAMENUM.
+ * It's a retransmission if we have a retransmission indicator.
+ * Flag this as a retransmission, but don't pass it to the
+ * subdissector.
*/
- if (pkt_value->num != pinfo->fd->num) {
+ if (spx_rexmit_info != NULL) {
if (check_col(pinfo->cinfo, COL_INFO)) {
col_add_fstr(pinfo->cinfo, COL_INFO,
"[Retransmission] Original Packet %u",
- pkt_value->num);
+ spx_rexmit_info->num);
}
+ if (tree) {
+ proto_tree_add_uint_format(spx_tree, hf_spx_rexmt_frame,
+ tvb, 0, 0, spx_rexmit_info->num,
+ "This is a retransmission of frame %u",
+ spx_rexmit_info->num);
+ if (tvb_length_remaining(tvb, SPX_HEADER_LEN) > 0) {
+ proto_tree_add_text(spx_tree, tvb,
+ SPX_HEADER_LEN, -1,
+ "Retransmitted data");
+ }
+ }
+ return;
}
if (tvb_reported_length_remaining(tvb, SPX_HEADER_LEN) > 0) {
}
/*
- * Pass the SPX info to subdissectors, so that they know
- * what this is.
- * Note: num will equal retransmitted source packet number.
+ * Pass information to subdissectors.
*/
- pinfo->private_data = pkt_value;
+ spx_info.eom = conn_ctrl & SPX_EOM;
+ spx_info.datastream_type = datastream_type;
+ pinfo->private_data = &spx_info;
next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
if (dissector_try_port(spx_socket_dissector_table, low_socket,
{ "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[] = {
FT_UINT8, BASE_HEX, NULL, 0x0,
"", HFILL }},
+ { &hf_spx_connection_control_sys,
+ { "System Packet", "spx.ctl.sys",
+ FT_BOOLEAN, 8, NULL, SPX_SYS_PACKET,
+ "", HFILL }},
+
+ { &hf_spx_connection_control_send_ack,
+ { "Send Ack", "spx.ctl.send_ack",
+ FT_BOOLEAN, 8, NULL, SPX_SEND_ACK,
+ "", HFILL }},
+
+ { &hf_spx_connection_control_attn,
+ { "Attention", "spx.ctl.attn",
+ FT_BOOLEAN, 8, NULL, SPX_ATTN,
+ "", HFILL }},
+
+ { &hf_spx_connection_control_eom,
+ { "End of Message", "spx.ctl.eom",
+ FT_BOOLEAN, 8, NULL, SPX_EOM,
+ "", HFILL }},
+
{ &hf_spx_datastream_type,
{ "Datastream type", "spx.type",
FT_UINT8, BASE_HEX, NULL, 0x0,
{ &hf_spx_all_nr,
{ "Allocation Number", "spx.alloc",
FT_UINT16, BASE_DEC, NULL, 0x0,
- "", HFILL }} };
+ "", HFILL }},
+
+ { &hf_spx_rexmt_frame,
+ { "Retransmitted Frame Number", "spx.rexmt_frame",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ };
static hf_register_info hf_ipxrip[] = {
{ &hf_ipxrip_request,
static gint *ett[] = {
&ett_ipx,
&ett_spx,
+ &ett_spx_connctrl,
&ett_ipxmsg,
&ett_ipxrip,
&ett_ipxsap,
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);