diff options
author | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2022-02-07 14:21:59 +0000 |
---|---|---|
committer | Martin Mathieson <martin.r.mathieson@googlemail.com> | 2022-02-07 14:21:59 +0000 |
commit | 64c4f748297d955b9f3f1c7c44afdb764573ddae (patch) | |
tree | e0f9b495cae4a6d43136ab7c1fc79becf040dd85 | |
parent | 782671a99a21ff9efa805e36f1edf0f76d22cf59 (diff) | |
download | wireshark-64c4f748297d955b9f3f1c7c44afdb764573ddae.tar.gz wireshark-64c4f748297d955b9f3f1c7c44afdb764573ddae.tar.bz2 wireshark-64c4f748297d955b9f3f1c7c44afdb764573ddae.zip |
RLC-NR: work out a better id/data value for adding fragments.
-rw-r--r-- | epan/dissectors/packet-rlc-nr.c | 169 |
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); |