aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-rlc-nr.c169
1 files changed, 131 insertions, 38 deletions
diff --git a/epan/dissectors/packet-rlc-nr.c b/epan/dissectors/packet-rlc-nr.c
index e4e8adf16b..883658de5f 100644
--- a/epan/dissectors/packet-rlc-nr.c
+++ b/epan/dissectors/packet-rlc-nr.c
@@ -67,6 +67,13 @@ static gboolean global_rlc_nr_reassemble_am_pdus = TRUE;
/* Tree storing UE related parameters (ueid, drbid) -> pdcp_bearer_parameters */
static wmem_tree_t *ue_parameters_tree;
+/* Table storing starting frame for reassembly session during first pass */
+/* Key is (ueId, direction, bearertype, bearerid, sn) */
+static wmem_tree_t *reassembly_start_table;
+
+/* Table storing starting frame for reassembly session during subsequent passes */
+/* Key is (ueId, direction, bearertype, bearerid, sn, frame) */
+static wmem_tree_t *reassembly_start_table_stored;
/**************************************************/
/* Initialize the protocol and registered fields. */
@@ -570,6 +577,93 @@ static void dissect_rlc_nr_tm(tvbuff_t *tvb, packet_info *pinfo,
}
}
+/* Look up / set the frame thought to be the start segment of this RLC PDU. */
+/* N.B. this algorithm will not be correct in all cases, but is good enough to be useful.. */
+static guint32 get_reassembly_start_frame(packet_info *pinfo, guint32 seg_info,
+ rlc_nr_info *p_rlc_nr_info, guint32 sn)
+{
+ guint32 frame_id = 0;
+
+ guint32 key_values[] = { p_rlc_nr_info->ueid,
+ p_rlc_nr_info->direction,
+ p_rlc_nr_info->bearerType,
+ p_rlc_nr_info->bearerId,
+ sn,
+ pinfo->num /* N.B. only used for subsquent/_stored table */
+ };
+
+ /* Is this the first segment of SN? */
+ gboolean first_segment = (seg_info & 0x2) == 0;
+
+ /* Set Key. */
+ wmem_tree_key_t key[2];
+ key[0].length = 5; /* Ignoring this frame num */
+ key[0].key = key_values;
+ key[1].length = 0;
+ key[1].key = NULL;
+
+ guint32 *p_frame_id = NULL;
+
+ if (!PINFO_FD_VISITED(pinfo)) {
+ /* On first pass, maintain reassembly_start_table. */
+
+ /* Look for existing entry. */
+ p_frame_id = (guint32*)wmem_tree_lookup32_array(reassembly_start_table, key);
+
+
+ if (first_segment) {
+ /* Let it start from here */
+ wmem_tree_insert32_array(reassembly_start_table, key, GUINT_TO_POINTER(pinfo->num));
+ frame_id = pinfo->num;
+ }
+ else {
+ if (p_frame_id) {
+ /* Use existing entry (or zero) if not found */
+ frame_id = GPOINTER_TO_UINT(p_frame_id);
+ }
+ }
+
+ /* Store this result for subsequent passes. Don't store 0 though. */
+ if (frame_id) {
+ key[0].length = 6;
+ wmem_tree_insert32_array(reassembly_start_table_stored, key, GUINT_TO_POINTER(frame_id));
+ }
+ }
+ else {
+ /* For subsequent passes, use stored value */
+ key[0].length = 6; /* i.e. include this framenum in key */
+ p_frame_id = (guint32*)wmem_tree_lookup32_array(reassembly_start_table_stored, key);
+ if (p_frame_id) {
+ /* Use found value */
+ frame_id = GPOINTER_TO_UINT(p_frame_id);
+ }
+ }
+
+ return frame_id;
+}
+
+static void reassembly_frame_complete(packet_info *pinfo,
+ rlc_nr_info *p_rlc_nr_info, guint32 sn)
+{
+ if (!PINFO_FD_VISITED(pinfo)) {
+ guint32 key_values[] = { p_rlc_nr_info->ueid,
+ p_rlc_nr_info->direction,
+ p_rlc_nr_info->bearerType,
+ p_rlc_nr_info->bearerId,
+ sn
+ };
+
+ /* Set Key. */
+ wmem_tree_key_t key[2];
+ key[0].length = 4; /* Ignoring this frame num */
+ key[0].key = key_values;
+ key[1].length = 0;
+ key[1].key = NULL;
+
+ /* Clear entry out */
+ wmem_tree_insert32_array(reassembly_start_table, key, GUINT_TO_POINTER(0));
+ }
+}
/***************************************************/
@@ -672,25 +766,22 @@ static void dissect_rlc_nr_um(tvbuff_t *tvb, packet_info *pinfo,
pinfo->fragmented = TRUE;
fragment_head *fh;
gboolean more_frags = seg_info & 0x01;
- /* TODO: This should be unique enough, but is there a way to get frame number of first frame in reassembly table? */
- guint32 id = p_rlc_nr_info->direction + /* 1 bit */
- (p_rlc_nr_info->ueid<<1) + /* 7 bits */
- (p_rlc_nr_info->bearerId<<8) + /* 5 bits */
- (sn<<13); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
-
- fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
- id, /* id */
- GUINT_TO_POINTER(id), /* data */
- so, /* frag_offset */
- tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
- more_frags /* more_frags */
- );
-
- gboolean update_col_info = TRUE;
- next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
- fh, &rlc_nr_frag_items,
- &update_col_info, tree);
- pinfo->fragmented = save_fragmented;
+ guint32 id = get_reassembly_start_frame(pinfo, seg_info, p_rlc_nr_info, sn); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
+ if (id != 0) {
+ fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
+ id, /* id */
+ GUINT_TO_POINTER(id), /* data */
+ so, /* frag_offset */
+ tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
+ more_frags /* more_frags */
+ );
+
+ gboolean update_col_info = TRUE;
+ next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
+ fh, &rlc_nr_frag_items,
+ &update_col_info, tree);
+ pinfo->fragmented = save_fragmented;
+ }
}
if (tvb_reported_length_remaining(tvb, offset) > 0) {
@@ -703,6 +794,9 @@ static void dissect_rlc_nr_um(tvbuff_t *tvb, packet_info *pinfo,
add_new_data_source(pinfo, next_tvb, "Reassembled RLC-NR PDU");
show_PDU_in_tree(pinfo, tree, next_tvb, 0, tvb_captured_length(next_tvb),
p_rlc_nr_info, seg_info, TRUE);
+
+ /* Note that PDU is now completed (so won't try to add to it) */
+ reassembly_frame_complete(pinfo, p_rlc_nr_info, sn);
}
} else if (!global_rlc_nr_headers_expected) {
/* Report that expected data was missing (unless we know it might happen) */
@@ -1026,25 +1120,22 @@ static void dissect_rlc_nr_am(tvbuff_t *tvb, packet_info *pinfo,
pinfo->fragmented = TRUE;
fragment_head *fh;
gboolean more_frags = seg_info & 0x01;
- /* TODO: This should be unique enough, but is there a way to get frame number of first frame in reassembly table? */
- guint32 id = p_rlc_nr_info->direction + /* 1 bit */
- (p_rlc_nr_info->ueid<<1) + /* 7 bits */
- (p_rlc_nr_info->bearerId<<8) + /* 5 bits */
- (sn<<13); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
-
- fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
- id, /* id */
- GUINT_TO_POINTER(id), /* data */
- so, /* frag_offset */
- tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
- more_frags /* more_frags */
- );
-
- gboolean update_col_info = TRUE;
- next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
- fh, &rlc_nr_frag_items,
- &update_col_info, tree);
- pinfo->fragmented = save_fragmented;
+ guint32 id = get_reassembly_start_frame(pinfo, seg_info, p_rlc_nr_info, sn);
+ if (id != 0) {
+ fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
+ id, /* id */
+ GUINT_TO_POINTER(id), /* data */
+ so, /* frag_offset */
+ tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
+ more_frags /* more_frags */
+ );
+
+ gboolean update_col_info = TRUE;
+ next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
+ fh, &rlc_nr_frag_items,
+ &update_col_info, tree);
+ pinfo->fragmented = save_fragmented;
+ }
}
@@ -1756,6 +1847,8 @@ void proto_register_rlc_nr(void)
&global_rlc_nr_reassemble_um_pdus);
ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
+ reassembly_start_table = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
+ reassembly_start_table_stored = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
/* Register reassembly table. */
reassembly_table_register(&pdu_reassembly_table, &pdu_reassembly_table_functions);