aboutsummaryrefslogtreecommitdiffstats
path: root/packet-sna.c
diff options
context:
space:
mode:
authorgram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>2002-09-23 21:58:22 +0000
committergram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>2002-09-23 21:58:22 +0000
commit2bd94b552d5c786865c6ee1915ba4a8e8cd5021c (patch)
treebbd6969449060270d7fdd995b8d45ac873f20200 /packet-sna.c
parent7eb03ae98351bac834896f6653d6d782f9cc5f6f (diff)
Support re-assembly of fragmented BIUs in SNA packets of TH FID 2
Other SNA TH types support fragmentation, but denote it much differently thant TH FID2. Since I have only FID-2 fragmented packet traces, it's the only type I could test, and thus the only FID type I coded for. Many thanks to Nick Baldwin <nick.baldwin@satelcom.co.uk> for providing the traces and for testing the changes. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@6325 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'packet-sna.c')
-rw-r--r--packet-sna.c246
1 files changed, 223 insertions, 23 deletions
diff --git a/packet-sna.c b/packet-sna.c
index 12487a1d79..7820f3785d 100644
--- a/packet-sna.c
+++ b/packet-sna.c
@@ -2,7 +2,7 @@
* Routines for SNA
* Gilbert Ramirez <gram@alumni.rice.edu>
*
- * $Id: packet-sna.c,v 1.42 2002/08/28 21:00:34 jmayer Exp $
+ * $Id: packet-sna.c,v 1.43 2002/09/23 21:58:22 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -32,6 +32,8 @@
#include "llcsaps.h"
#include "ppptypes.h"
#include <epan/sna-utils.h>
+#include "prefs.h"
+#include "reassemble.h"
/*
* http://www.wanresources.com/snacell.html
@@ -155,6 +157,11 @@ static gint ett_sna_rh_2 = -1;
static dissector_handle_t data_handle;
+/* Defragment fragmented SNA BIUs*/
+static gboolean sna_defragment = FALSE;
+static GHashTable *sna_fragment_table = NULL;
+static GHashTable *sna_reassembled_table = NULL;
+
/* Format Identifier */
static const value_string sna_th_fid_vals[] = {
{ 0x0, "SNA device <--> Non-SNA Device" },
@@ -172,11 +179,16 @@ static const value_string sna_th_fid_vals[] = {
};
/* Mapping Field */
+#define MPF_MIDDLE_SEGMENT 0
+#define MPF_LAST_SEGMENT 1
+#define MPF_FIRST_SEGMENT 2
+#define MPF_WHOLE_BIU 3
+
static const value_string sna_th_mpf_vals[] = {
- { 0, "Middle segment of a BIU" },
- { 1, "Last segment of a BIU" },
- { 2, "First segment of a BIU" },
- { 3 , "Whole BIU" },
+ { MPF_MIDDLE_SEGMENT, "Middle segment of a BIU" },
+ { MPF_LAST_SEGMENT, "Last segment of a BIU" },
+ { MPF_FIRST_SEGMENT, "First segment of a BIU" },
+ { MPF_WHOLE_BIU, "Whole BIU" },
{ 0, NULL }
};
@@ -404,8 +416,20 @@ static const true_false_string sna_nlp_osi_truth =
{ "Optional segments present", "No optional segments present" };
+/* Values to direct the top-most dissector what to dissect
+ * after the TH. */
+enum next_dissection_enum {
+ stop_here,
+ rh_only,
+ everything
+};
+
+typedef enum next_dissection_enum next_dissection_t;
+
+
static int dissect_fid0_1 (tvbuff_t*, packet_info*, proto_tree*);
-static int dissect_fid2 (tvbuff_t*, packet_info*, proto_tree*);
+static int dissect_fid2 (tvbuff_t*, packet_info*, proto_tree*, tvbuff_t**,
+ next_dissection_t*);
static int dissect_fid3 (tvbuff_t*, proto_tree*);
static int dissect_fid4 (tvbuff_t*, packet_info*, proto_tree*);
static int dissect_fid5 (tvbuff_t*, proto_tree*);
@@ -414,6 +438,13 @@ static void dissect_fid (tvbuff_t*, packet_info*, proto_tree*, proto_tree*);
static void dissect_nlp (tvbuff_t*, packet_info*, proto_tree*, proto_tree*);
static void dissect_rh (tvbuff_t*, int, proto_tree*);
+static unsigned int
+mpf_value(guint8 th_byte)
+{
+ return (th_byte & 0x0c) >> 2;
+}
+
+
static void
dissect_sna(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@@ -451,6 +482,8 @@ dissect_sna(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
+#define RH_LEN 3
+
static void
dissect_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree *parent_tree)
@@ -459,8 +492,10 @@ dissect_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree *th_tree = NULL, *rh_tree = NULL;
proto_item *th_ti = NULL, *rh_ti = NULL;
guint8 th_fid;
- int sna_header_len = 0, th_header_len = 0;
- int offset;
+ int th_header_len = 0;
+ int offset, rh_offset;
+ tvbuff_t *rh_tvb = NULL;
+ next_dissection_t continue_dissecting = everything;
/* Transmission Header Format Identifier */
th_fid = hi_nibble(tvb_get_guint8(tvb, 0));
@@ -486,7 +521,8 @@ dissect_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
th_header_len = dissect_fid0_1(tvb, pinfo, th_tree);
break;
case 0x2:
- th_header_len = dissect_fid2(tvb, pinfo, th_tree);
+ th_header_len = dissect_fid2(tvb, pinfo, th_tree, &rh_tvb,
+ &continue_dissecting);
break;
case 0x3:
th_header_len = dissect_fid3(tvb, th_tree);
@@ -506,29 +542,154 @@ dissect_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return;
}
- sna_header_len += th_header_len;
offset = th_header_len;
+ /* Short-circuit ? */
+ if (continue_dissecting == stop_here) {
+ if (tree) {
+ proto_tree_add_text(tree, tvb, offset, -1,
+ "BIU segment data");
+ }
+ return;
+ }
+
+
+ /* If the FID dissector function didn't create an rh_tvb, then we just
+ * use the rest of our tvbuff as the rh_tvb. */
+ if (!rh_tvb) {
+ rh_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ }
+ rh_offset = 0;
+
+ /* Process the rest of the SNA packet, starting with RH */
if (tree) {
+
proto_item_set_len(th_ti, th_header_len);
/* --- RH --- */
- rh_ti = proto_tree_add_item(tree, hf_sna_rh, tvb, offset, 3, FALSE);
+ rh_ti = proto_tree_add_item(tree, hf_sna_rh, rh_tvb, rh_offset, RH_LEN, FALSE);
rh_tree = proto_item_add_subtree(rh_ti, ett_sna_rh);
- dissect_rh(tvb, offset, rh_tree);
+ dissect_rh(rh_tvb, rh_offset, rh_tree);
+ }
+
- sna_header_len += 3;
- offset += 3;
+ rh_offset += RH_LEN;
+
+ if (tvb_offset_exists(rh_tvb, rh_offset+1)) {
+ /* Short-circuit ? */
+ if (continue_dissecting == rh_only) {
+ if (tree) {
+ proto_tree_add_text(tree, rh_tvb, rh_offset, -1,
+ "BIU segment data");
+ }
+ return;
+ }
+
+ call_dissector(data_handle, tvb_new_subset(rh_tvb, rh_offset, -1, -1),
+ pinfo, parent_tree);
}
- else {
- sna_header_len += 3;
- offset += 3;
+}
+
+#define FIRST_FRAG_NUMBER 0
+#define MIDDLE_FRAG_NUMBER 1
+#define LAST_FRAG_NUMBER 2
+
+/* FID2 is defragged by sequence. The weird thing is that we have neither
+ * absolute sequence numbers, nor byte offets. Other FIDs have byte offsets
+ * (the DCF field), but not FID2. The only thing we have to go with is "FIRST",
+ * "MIDDLE", or "LAST". If the BIU is split into 3 frames, then everything is
+ * fine, * "FIRST", "MIDDLE", and "LAST" map nicely onto frag-number 0, 1,
+ * and 2. However, if the BIU is split into 2 frames, then we only have
+ * "FIRST" and "LAST", and the mapping *should* be frag-number 0 and 1,
+ * *NOT* 0 and 2.
+ *
+ * The SNA docs say "FID2 PIUs cannot be blocked because there is no DCF in the
+ * TH format for deblocking" (note on Figure 4-2 in the IBM SNA documention,
+ * see the FTP URL in the comment near the top of this file). I *think*
+ * this means that the fragmented frames cannot arrive out of order.
+ * Well, I *want* it to mean this, because w/o this limitation, if you
+ * get a "FIRST" frame and a "LAST" frame, how long should you wait to
+ * see if a "MIDDLE" frame every arrives????? Thus, if frames *have* to
+ * arrive in order, then we're saved.
+ *
+ * The problem then boils down to figuring out if "LAST" means frag-number 1
+ * (in the case of a BIU split into 2 frames) or frag-number 2
+ * (in the case of a BIU split into 3 frames).
+ *
+ * Assuming fragmented FID2 BIU frames *do* arrive in order, the obvious
+ * way to handle the mapping of "LAST" to either frag-number 1 or
+ * frag-number 2 is to keep a hash which tracks the frames seen, etc.
+ * This consumes resources. A trickier way, but a way which works, is to
+ * always map the "LAST" BIU segment to frag-number 2. Here's the trickery:
+ * if we add frag-number 2, which we know to be the "LAST" BIU segment,
+ * and the reassembly code tells us that the the BIU is still not reassmebled,
+ * then, owing to the, ahem, /fact/, that fragmented BIU segments arrive
+ * in order :), we know that 1) "FIRST" did come, and 2) there's no "MIDDLE",
+ * because this BIU was fragmented into 2 frames, not 3. So, we'll be
+ * tricky and add a zero-length "MIDDLE" BIU frame (i.e, frag-number 1)
+ * to complete the reassembly.
+ */
+static tvbuff_t*
+defragment_by_sequence(packet_info *pinfo, tvbuff_t *tvb, int offset, int mpf, int id)
+{
+ fragment_data *fd_head;
+ int frag_number = -1;
+ int more_frags = TRUE;
+ tvbuff_t *rh_tvb = NULL;
+
+ /* Determine frag_number and more_frags */
+ switch(mpf) {
+ case MPF_WHOLE_BIU:
+ /* nothing */
+ break;
+ case MPF_FIRST_SEGMENT:
+ frag_number = FIRST_FRAG_NUMBER;
+ break;
+ case MPF_MIDDLE_SEGMENT:
+ frag_number = MIDDLE_FRAG_NUMBER;
+ break;
+ case MPF_LAST_SEGMENT:
+ frag_number = LAST_FRAG_NUMBER;
+ more_frags = FALSE;
+ break;
+ default:
+ g_assert_not_reached();
}
- if (tvb_offset_exists(tvb, offset+1)) {
- call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
- pinfo, parent_tree);
+ /* If sna_defragment is on, and this is a fragment.. */
+ if (frag_number > -1) {
+
+ /* XXX - check length ??? */
+ fd_head = fragment_add_seq(tvb, offset, pinfo, id,
+ sna_fragment_table,
+ frag_number,
+ tvb_length_remaining(tvb, offset),
+ more_frags);
+
+ /* We added the LAST segment and reassembly didn't complete. Insert
+ * a zero-length MIDDLE segment to turn a 2-frame BIU-fragmentation
+ * into a 3-frame BIU-fragmentation (empty middle frag).
+ * See above long comment about this trickery. */
+ if (mpf == MPF_LAST_SEGMENT && !fd_head) {
+ fd_head = fragment_add_seq(tvb, offset, pinfo, id,
+ sna_fragment_table, MIDDLE_FRAG_NUMBER,
+ 0, TRUE);
+ }
+
+ if (fd_head != NULL) {
+ /* We have the complete reassembled payload. */
+ rh_tvb = tvb_new_real_data(fd_head->data,
+ fd_head->len, fd_head->len);
+
+ /* Add the tvbuff to the chain of tvbuffs so that
+ * it will get cleaned up too. */
+ tvb_set_child_real_data_tvbuff(tvb, rh_tvb);
+
+ /* Add the defragmented data to the data source list. */
+ add_new_data_source(pinfo, rh_tvb, "Reassembled SNA BIU");
+ }
}
+ return rh_tvb;
}
#define SNA_FID01_ADDR_LEN 2
@@ -590,17 +751,21 @@ dissect_fid0_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* FID Type 2 */
static int
-dissect_fid2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_fid2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ tvbuff_t **rh_tvb_ptr, next_dissection_t *continue_dissecting)
{
proto_tree *bf_tree;
proto_item *bf_item;
guint8 th_0=0, daf=0, oaf=0;
const guint8 *ptr;
+ unsigned int mpf, id;
const int bytes_in_header = 6;
+ th_0 = tvb_get_guint8(tvb, 0);
+ mpf = mpf_value(th_0);
+
if (tree) {
- th_0 = tvb_get_guint8(tvb, 0);
daf = tvb_get_guint8(tvb, 2);
oaf = tvb_get_guint8(tvb, 3);
@@ -613,6 +778,7 @@ dissect_fid2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint(bf_tree, hf_sna_th_odai,tvb, 0, 1, th_0);
proto_tree_add_uint(bf_tree, hf_sna_th_efi, tvb, 0, 1, th_0);
+
/* Byte 1 */
proto_tree_add_text(tree, tvb, 1, 1, "Reserved");
@@ -637,10 +803,25 @@ dissect_fid2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
SET_ADDRESS(&pinfo->net_src, AT_SNA, SNA_FID2_ADDR_LEN, ptr);
SET_ADDRESS(&pinfo->src, AT_SNA, SNA_FID2_ADDR_LEN, ptr);
+ id = tvb_get_ntohs(tvb, 4);
if (tree) {
- proto_tree_add_item(tree, hf_sna_th_snf, tvb, 4, 2, FALSE);
+ proto_tree_add_uint(tree, hf_sna_th_snf, tvb, 4, 2, id);
}
+ if (mpf != MPF_WHOLE_BIU && !sna_defragment) {
+ if (mpf == MPF_FIRST_SEGMENT) {
+ *continue_dissecting = rh_only;
+ }
+ else {
+ *continue_dissecting = stop_here;
+ }
+
+ }
+ else if (sna_defragment) {
+ *rh_tvb_ptr = defragment_by_sequence(pinfo, tvb, bytes_in_header,
+ mpf, id);
+ }
+
return bytes_in_header;
}
@@ -1136,6 +1317,14 @@ dissect_rh(tvbuff_t *tvb, int offset, proto_tree *tree)
/* XXX - check for sdi. If TRUE, the next 4 bytes will be sense data */
}
+static void
+sna_init(void)
+{
+ fragment_table_init(&sna_fragment_table);
+ reassembled_table_init(&sna_reassembled_table);
+}
+
+
void
proto_register_sna(void)
{
@@ -1590,12 +1779,21 @@ proto_register_sna(void)
&ett_sna_rh_1,
&ett_sna_rh_2,
};
+ module_t *sna_module;
proto_sna = proto_register_protocol("Systems Network Architecture",
"SNA", "sna");
proto_register_field_array(proto_sna, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector("sna", dissect_sna, proto_sna);
+
+ /* Register configuration options */
+ sna_module = prefs_register_protocol(proto_sna, NULL);
+ prefs_register_bool_preference(sna_module, "defragment",
+ "Reassemble fragmented BIUs",
+ "Whether fragmented BIUs should be reassembled",
+ &sna_defragment);
+
}
void
@@ -1608,4 +1806,6 @@ proto_reg_handoff_sna(void)
/* RFC 2043 */
dissector_add("ppp.protocol", PPP_SNA, sna_handle);
data_handle = find_dissector("data");
+
+ register_init_routine(sna_init);
}