summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2012-07-24 07:31:46 +0000
committerAnders Broman <anders.broman@ericsson.com>2012-07-24 07:31:46 +0000
commit3743a01714a4febbcf33714da6454fdd65ec2eff (patch)
tree8b03af0336d0cab393845ba901f58f51c36dc5a1
parent2e74809c332d93b3088b57ea678bccd197a8b7de (diff)
downloadwireshark-3743a01714a4febbcf33714da6454fdd65ec2eff.tar.gz
From Jacob Nordgren and Rishie Sharma:
- Added support for EDCH type 2 MAC-is reassembly and slightly improved RLC error reporting - RLC: fixed bug where complete sequences in the end of a trace where not reassembled svn path=/trunk/; revision=43954
-rw-r--r--epan/dissectors/packet-rlc.c229
-rw-r--r--epan/dissectors/packet-umts_fp.c185
-rw-r--r--epan/dissectors/packet-umts_mac.c150
-rw-r--r--epan/dissectors/packet-umts_mac.h4
4 files changed, 397 insertions, 171 deletions
diff --git a/epan/dissectors/packet-rlc.c b/epan/dissectors/packet-rlc.c
index df6527e80a..d6cb170c7d 100644
--- a/epan/dissectors/packet-rlc.c
+++ b/epan/dissectors/packet-rlc.c
@@ -323,6 +323,7 @@ rlc_channel_create(enum rlc_mode mode, packet_info *pinfo)
/* channel assignment failed */
g_free(ch);
ch = NULL;
+ REPORT_DISSECTOR_BUG("Failed to assign channel");
}
return ch;
}
@@ -449,7 +450,7 @@ static int special_cmp(gconstpointer a, gconstpointer b)
return -1;
}
}
- return (p < q)? -1 : (p > q)? 1 : 0;
+ return (p < q)? -1 : (p > q)? 1 : 0;
}
/* callback function to use for g_hash_table_foreach_remove()
@@ -714,7 +715,7 @@ rlc_sdu_add_fragment(enum rlc_mode mode, struct rlc_sdu *sdu, struct rlc_frag *f
case RLC_AM:
/* insert ordered */
tmp = sdu->frags;
-
+
/* If receiving exotic border line sequence, e.g. 4094, 4095, 0, 1 */
if (frag->seq+2048 < tmp->seq) {
while (tmp->next && frag->seq+2048 < tmp->seq)
@@ -752,7 +753,7 @@ rlc_sdu_add_fragment(enum rlc_mode mode, struct rlc_sdu *sdu, struct rlc_frag *f
}
static void
-reassemble_message(struct rlc_channel *ch, struct rlc_sdu *sdu, struct rlc_frag *frag)
+reassemble_data(struct rlc_channel *ch, struct rlc_sdu *sdu, struct rlc_frag *frag)
{
struct rlc_frag *temp;
guint16 offs = 0;
@@ -765,14 +766,14 @@ reassemble_message(struct rlc_channel *ch, struct rlc_sdu *sdu, struct rlc_frag
sdu->reassembled_in = frag;
else
sdu->reassembled_in = sdu->last;
-
+
sdu->data = se_alloc(sdu->len);
temp = sdu->frags;
while (temp && ((offs + temp->len) <= sdu->len)) {
memcpy(sdu->data + offs, temp->data, temp->len);
/* mark this fragment in reassembled table */
g_hash_table_insert(reassembled_table, temp, sdu);
-
+
offs += temp->len;
temp = temp->next;
}
@@ -794,6 +795,69 @@ static void printends(GList * list)
}
#endif
+static struct rlc_frag ** get_frags(packet_info * pinfo, struct rlc_channel * ch_lookup)
+{
+ gpointer value = NULL;
+ struct rlc_frag ** frags = NULL;
+ /* Look for already created frags table */
+ if (g_hash_table_lookup_extended(fragment_table, ch_lookup, NULL, &value)) {
+ frags = value;
+ } else {
+ struct rlc_channel *ch;
+ ch = rlc_channel_create(ch_lookup->mode, pinfo);
+ frags = se_alloc0(sizeof(struct rlc_frag *) * 4096);
+ g_hash_table_insert(fragment_table, ch, frags);
+ }
+ return frags;
+}
+static struct rlc_seqlist * get_endlist(packet_info * pinfo, struct rlc_channel * ch_lookup)
+{
+ gpointer value = NULL;
+ struct rlc_seqlist * endlist = NULL;
+ /* If there already exists a frag table for this channel use that one. */
+ if (g_hash_table_lookup_extended(endpoints, ch_lookup, NULL, &value)) {
+ endlist = value;
+ } else { /* Else create a new one. */
+ struct rlc_channel * ch;
+
+ endlist = se_new(struct rlc_seqlist);
+ ch = rlc_channel_create(ch_lookup->mode, pinfo);
+
+ endlist->list = NULL;
+ endlist->list = g_list_prepend(endlist->list, GINT_TO_POINTER(-1));
+ g_hash_table_insert(endpoints, ch, endlist);
+ }
+ return endlist;
+}
+
+static void reassemble_sequence(struct rlc_frag ** frags, struct rlc_seqlist * endlist, struct rlc_channel * ch_lookup, guint16 start, guint end)
+{
+ GList * element = NULL;
+ struct rlc_sdu * sdu = rlc_sdu_create();
+
+ /* Insert fragments into SDU. */
+ for (; special_cmp(GINT_TO_POINTER((gint)start), GINT_TO_POINTER((gint)end)) <= 0; start = (start+1)%4096)
+ {
+ struct rlc_frag * tempfrag = NULL;
+ tempfrag = frags[start]->next;
+ frags[start]->next = NULL;
+ rlc_sdu_add_fragment(ch_lookup->mode, sdu, frags[start]);
+ frags[start] = tempfrag;
+ }
+
+ /* Remove first endpoint. */
+ element = g_list_first(endlist->list);
+ if (element) {
+ endlist->list = g_list_remove_link(endlist->list, element);
+ if (frags[end] != NULL) {
+ if (endlist->list) {
+ endlist->list->data = GINT_TO_POINTER((GPOINTER_TO_INT(endlist->list->data) - 1 + 4096) % 4096);
+ }
+ }
+ }
+ reassemble_data(ch_lookup, sdu, NULL);
+}
+
/* add a new fragment to an SDU
* if length == 0, just finalize the specified SDU
*/
@@ -830,33 +894,8 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
return frag;
}
- /* Look for already created frags table */
- if (g_hash_table_lookup_extended(fragment_table, &ch_lookup, &orig_key, &value)) {
- frags = value;
- } else {
- struct rlc_channel *ch;
- ch = rlc_channel_create(mode, pinfo);
- frags = se_alloc0(sizeof(struct rlc_frag *) * 4096);
- g_hash_table_insert(fragment_table, ch, frags);
- }
-
- /* Look for already created list of endpoints */
- if (g_hash_table_lookup_extended(endpoints, &ch_lookup, &orig_key, &value)) {
- endlist = value;
- } else {
- struct rlc_channel *ch;
-
- endlist = se_new(struct rlc_seqlist);
- ch = rlc_channel_create(mode, pinfo);
- if (ch == NULL) { /* DEBUG */
- REPORT_DISSECTOR_BUG("Failed to assign channel");
- return NULL;
- }
-
- endlist->list = NULL;
- endlist->list = g_list_prepend(endlist->list, GINT_TO_POINTER(-1));
- g_hash_table_insert(endpoints, ch, endlist);
- }
+ frags = get_frags(pinfo, &ch_lookup);
+ endlist = get_endlist(pinfo, &ch_lookup);
/* If already done reassembly */
if (pinfo->fd->flags.visited) {
@@ -865,16 +904,25 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
gint16 start = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
gint16 end = GPOINTER_TO_INT(endlist->list->next->data);
gint16 missing = start;
- for (; missing < end; missing++)
+ gboolean wecanreasmmore = TRUE;
+
+ for (; special_cmp(GINT_TO_POINTER((gint)missing), GINT_TO_POINTER((gint)end)) <= 0; missing = (missing+1)%4096)
{
if (frags[missing] == NULL) {
+ wecanreasmmore = FALSE;
break;
}
}
- if (end != -1 && frags[end]) {
- g_warning("Unfinished sequence (%u->%u [packet %u]) could not find %u.", start, end, frags[end]->frame_num, missing);
+
+ if (wecanreasmmore) {
+ reassemble_sequence(frags, endlist, &ch_lookup, start, end);
} else {
- g_warning("Unfinished sequence (%u->%u [could not determine packet]) could not find %u.", start, end, missing);
+ if (end >= 0 && end < 4096 && frags[end]) {
+ proto_tree_add_text(tree, tvb, 0, 0, "Did not perform reassembly because of unfinished sequence (%u->%u [packet %u]), could not find %u.", start, end, frags[end]->frame_num, missing);
+ } else {
+ proto_tree_add_text(tree, tvb, 0, 0, "Did not perform reassembly because of unfinished sequence (%u->%u [could not determine packet]), could not find %u.", start, end, missing);
+ }
+ expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_ERROR, "Did not perform reassembly because of previous unfinished sequence.");
}
} else if (endlist->list) {
/*gint16 end = *((gint16*)endlist->list->data);
@@ -883,13 +931,13 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
}
return NULL; /* If already done reassembly and no SDU found, too bad */
}
-
+
if (fail) { /* don't continue after sh*t has hit the fan */
return NULL;
}
frag = rlc_frag_create(tvb, mode, pinfo, offset, len, seq, num_li);
-
+
/* If frags[seq] is not NULL then we must have data from several PDUs in the
* same RLC packet (using Length Indicators) or something has gone terribly
* wrong. */
@@ -900,54 +948,32 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
tempfrag = tempfrag->next;
tempfrag->next = frag;
} else { /* This should never happen */
- g_print("frags[%d] was not null, numli: %u, paket: %u\n", seq, num_li, pinfo->fd->num);
+ fail = TRUE;
+ return NULL;
}
- return NULL;
} else {
frags[seq] = frag;
}
-
+
/* It is also possible that frags[seq] is NULL even though we do have data
* from several PDUs in the same RLC packet. This is if the reassembly is
* not lagging behind at all because of perfectly ordered sequences. */
if (endlist->list && num_li != 0) {
gint16 first = GPOINTER_TO_INT(endlist->list->data);
- if (seq <= first) {
+ if (seq == first) {
endlist->list->data = GINT_TO_POINTER(first-1);
}
}
-
+
/* If this is an endpoint */
if (final) {
- if (endlist->list) {
- gint16 first = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
- if (MIN((first-seq+4096)%4096, (seq-first+4096)%4096) >= 1028) {
- g_warning("setting fail flag at packet %u, seq %u was too far away from first %d (packet %d)",
- pinfo->fd->num, seq, first, (frags[first] == NULL) ? -1 : (int)frags[first]->frame_num);
- if (endlist->list->next) {
- gint16 start = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
- gint16 end = GPOINTER_TO_INT(endlist->list->next->data);
- for (; special_cmp(GINT_TO_POINTER((gint)start), GINT_TO_POINTER((gint)end)) == -1; start = (start+1)%4096)
- {
- if (frags[start] == NULL) {
-
- break;
- }
- }
- g_warning("missing is %u\n", start);
- }
- fail = TRUE; /* Give up if things have gone too far. */
- return NULL;
- }
- }
-
endlist->list = g_list_insert_sorted(endlist->list, GINT_TO_POINTER((gint)seq), special_cmp);
}
-
+
#if RLC_ADD_FRAGMENT_DEBUG_PRINT
printends(endlist->list);
#endif
-
+
/* Try to reassemble SDU. */
if (endlist->list && endlist->list->next) {
gint16 start = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
@@ -957,49 +983,49 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
fail = TRUE;
return NULL;
}
-
+
+ /* If our endpoint is a LI=0 with no data. */
+ if (start == end && frags[start]->len == 0) {
+ element = g_list_first(endlist->list);
+ if (element) {
+ endlist->list = g_list_remove_link(endlist->list, element);
+ }
+ frags[start] = NULL;
+ /* NOTE: frags[start] is se_alloced and will remain until file closes, we would want to free it here. */
+ return NULL;
+ }
+
#if RLC_ADD_FRAGMENT_DEBUG_PRINT
g_print("start: %d, end: %d\n",start, end);
#endif
-
+
for (; special_cmp(GINT_TO_POINTER((gint)start), GINT_TO_POINTER((gint)end)) == -1; start = (start+1)%4096)
{
if (frags[start] == NULL) {
if (MIN((start-seq+4096)%4096, (seq-start+4096)%4096) >= 1028) {
- g_warning("setting fail flag at packet %u, SDU (%u->%u[packet %u]), lost seq number was %u and current seq number is %u",
- pinfo->fd->num, (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096, end, frags[end]->frame_num, start, seq);
+ g_warning(
+"Setting fail flag because RLC fragment with sequence number %u was too far \
+away from an unfinished sequence (%u->%u). The missing sequence number is %u. \
+The most recently complete sequence ended in packet %u.", seq, 0, end, start, 0);
fail = TRUE; /* If it has gone too far, give up */
return NULL;
}
return frag;
}
}
-
- /* Full sequence found */
- sdu = rlc_sdu_create();
start = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
-
- /* Insert fragments into SDU. */
- for (; special_cmp(GINT_TO_POINTER((gint)start), GINT_TO_POINTER((gint)end)) <= 0; start = (start+1)%4096)
- {
- struct rlc_frag * tempfrag = NULL;
- tempfrag = frags[start]->next;
- frags[start]->next = NULL;
- rlc_sdu_add_fragment(mode, sdu, frags[start]);
- frags[start] = tempfrag;
- }
-
- /* Remove first endpoint. */
- element = g_list_first(endlist->list);
- if (element) {
- endlist->list = g_list_remove_link(endlist->list, element);
- if (frags[end] != NULL) {
- if (endlist->list) {
- endlist->list->data = GINT_TO_POINTER((GPOINTER_TO_INT(endlist->list->data) - 1 + 4096) % 4096);
- }
- }
+ reassemble_sequence(frags, endlist, &ch_lookup, start, end);
+ } else if (endlist->list) {
+ gint16 first = (GPOINTER_TO_INT(endlist->list->data) + 1) % 4096;
+ /* If the distance between the oldest stored endpoint in endlist and
+ * this endpoint is too large, set fail flag. */
+ if (MIN((first-seq+4096)%4096, (seq-first+4096)%4096) >= 1028) {
+ g_warning(
+"Setting fail flag because RLC fragment with sequence number %u was too far \
+away from an unfinished sequence with start %u and without end.", seq, first);
+ fail = TRUE; /* Give up if things have gone too far. */
+ return NULL;
}
- reassemble_message(&ch_lookup, sdu, NULL);
}
return frag;
@@ -1051,7 +1077,7 @@ get_reassembled_data(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
add_new_data_source(pinfo, sdu->tvb, "Reassembled RLC Message");
/* reassembly happened here, so create the fragment list */
- if (tree)
+ if (tree && sdu->fragcnt > 1)
tree_add_fragment_list(sdu, sdu->tvb, tree);
return sdu->tvb;
@@ -1115,7 +1141,6 @@ rlc_call_subdissector(enum rlc_channel_type channel, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree)
{
enum rrc_message_type msgtype;
-
switch (channel) {
case RLC_UL_CCCH:
msgtype = RRC_MESSAGE_TYPE_UL_CCCH;
@@ -1259,10 +1284,10 @@ rlc_decode_li(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo, proto_tree
switch (mode) {
case RLC_AM:
- offs = 1;
+ offs = 1;
break;
case RLC_UM:
- offs = 0;
+ offs = 0;
break;
case RLC_TM:
/* fall trough */
@@ -1743,7 +1768,7 @@ rlc_am_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo,
}
offs += tvb_length_remaining(tvb, offs);
} else {
- if (tree && li[i].len) {
+ if (tree) {
proto_tree_add_item(tree, hf_rlc_data, tvb, offs, li[i].len, ENC_NA);
}
if (global_rlc_perform_reassemby) {
@@ -1820,7 +1845,7 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
seq <<= 5;
next_byte = tvb_get_guint8(tvb, offs++);
seq |= (next_byte >> 3);
-
+
ext = next_byte & 0x03;
/* show header fields */
proto_tree_add_bits_item(tree, hf_rlc_seq, tvb, 1, 12, ENC_BIG_ENDIAN);
@@ -1837,7 +1862,7 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
col_append_str(pinfo->cinfo, COL_INFO, "[Malformed Packet]");
return;
}
-
+
fpinf = p_get_proto_data(pinfo->fd, proto_fp);
rlcinf = p_get_proto_data(pinfo->fd, proto_rlc);
if (!fpinf || !rlcinf) {
diff --git a/epan/dissectors/packet-umts_fp.c b/epan/dissectors/packet-umts_fp.c
index 264084a4e5..9bed7683db 100644
--- a/epan/dissectors/packet-umts_fp.c
+++ b/epan/dissectors/packet-umts_fp.c
@@ -225,7 +225,6 @@ static proto_tree *top_level_tree = NULL;
static gboolean preferences_call_mac_dissectors = TRUE;
static gboolean preferences_show_release_info = TRUE;
-
/* E-DCH (T1) channel header information */
struct edch_t1_subframe_info
{
@@ -588,7 +587,7 @@ dissect_tb_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
}
/* Calculate offset to CRCI bits */
-
+
if(p_fp_info->is_uplink){
for (chan=0; chan < p_fp_info->num_chans; chan++) {
int n;
@@ -615,11 +614,11 @@ dissect_tb_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
p_fp_info->chan_tf_size[chan]);
PROTO_ITEM_SET_GENERATED(no_tb_ti);
}
-
+
/* Show TBs from non-empty channels */
pinfo->fd->subnum = chan; /* set subframe number to current TB */
for (n=0; n < p_fp_info->chan_num_tbs[chan]; n++) {
-
+
proto_item *ti;
p_fp_info->cur_tb = chan; /*Set current transport block?*/
if (data_tree) {
@@ -630,24 +629,24 @@ dissect_tb_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_item_set_text(ti, "TB (chan %u, tb %u, %u bits)",
chan+1, n+1, p_fp_info->chan_tf_size[chan]);
}
-
+
if (preferences_call_mac_dissectors && data_handle &&
(p_fp_info->chan_tf_size[chan] > 0)) {
tvbuff_t *next_tvb;
proto_item *item;
/* If this is DL we should not care about crci bits (since they dont exists)*/
- if(p_fp_info->is_uplink){
+ if(p_fp_info->is_uplink){
item = proto_tree_add_item(data_tree, hf_fp_crci[n%8], tvb, (crci_bit_offset/8)+(n/8), 1, ENC_BIG_ENDIAN);
PROTO_ITEM_SET_GENERATED(item);
-
+
crci_bit = tvb_get_bits8(tvb,crci_bit_offset+(n/8),1);
}
-
+
if(crci_bit == 0 || !p_fp_info->is_uplink) {
next_tvb = tvb_new_subset(tvb, offset + bit_offset/8,
((bit_offset % 8) + p_fp_info->chan_tf_size[chan] + 7) / 8, -1);
-
-
+
+
/****************/
/* TODO: maybe this decision can be based only on info available in fp_info */
call_dissector(*data_handle, next_tvb, pinfo, top_level_tree);
@@ -659,7 +658,7 @@ dissect_tb_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
expert_add_info_format(pinfo, item, PI_UNDECODED, PI_NOTE, "Not sent to subdissectors as CRCI is set");
PROTO_ITEM_SET_GENERATED(item);
}
-
+
}
num_tbs++;
@@ -795,7 +794,7 @@ dissect_macd_pdu_data_type_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
if (preferences_call_mac_dissectors) {
-
+
tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, length, -1);
fpi->cur_tb = pdu; /*Set proper pdu index for MAC and higher layers*/
call_dissector(mac_fdd_hsdsch_handle, next_tvb, pinfo, top_level_tree);
@@ -2435,7 +2434,7 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
number_of_subframes, is_common);
return;
}
-
+
/* EDCH subframe header list */
for (n=0; n < number_of_subframes; n++) {
int i;
@@ -2480,7 +2479,7 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/* DDI (6 bits) */
ddi_ti = proto_tree_add_bits_ret_val(subframe_header_tree, hf_fp_edch_ddi, tvb,
offset*8 + bit_offset, 6, &ddi, ENC_BIG_ENDIAN);
-
+
if(rlcinf){
rlcinf->rbid[i] = (guint8)ddi;
}
@@ -2490,11 +2489,11 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
for (p=0; p < p_fp_info->no_ddi_entries; p++) {
if (ddi == p_fp_info->edch_ddi[p]) {
ddi_size = p_fp_info->edch_macd_pdu_size[p];
-
+
break;
}
}
-
+
if (ddi_size == -1) {
expert_add_info_format(pinfo, ddi_ti,
PI_MALFORMED, PI_ERROR,
@@ -2555,16 +2554,15 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
size = p_fp_info->edch_macd_pdu_size[m];
break;
}
- }
+ }
/* Look up logicalchannel id for this DDI value */
for (m=0; m < p_fp_info->no_ddi_entries; m++) {
if (subframes[n].ddi[i] == p_fp_info->edch_ddi[m]) {
lchid = p_fp_info->edch_lchId[m];
-
break;
}
}
-
+
if (m == p_fp_info->no_ddi_entries) {
/* Not found. Oops */
expert_add_info_format(pinfo,NULL,PI_UNDECODED,PI_ERROR,"Unable to locate DDI entry.");
@@ -2599,21 +2597,21 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
maces_tree = proto_item_add_subtree(ti, ett_fp_edch_maces);
}
for (macd_idx = 0; macd_idx < subframes[n].number_of_mac_d_pdus[i]; macd_idx++) {
-
+
if (preferences_call_mac_dissectors) {
tvbuff_t *next_tvb;
pinfo->fd->subnum = macd_idx; /* set subframe number to current TB */
/* create new TVB and pass further on */
next_tvb = tvb_new_subset(tvb, offset + bit_offset/8,
((bit_offset % 8) + size + 7) / 8, -1);
-
-
+
+
/*This was all previously stored in [0] rather than [macd_idx] and cur_tb wasnt updated!*/
/*Set up information needed for MAC and lower layers*/
macinf->content[macd_idx] = lchId_type_table[lchid]; /*Set the proper Content type for the mac layer.*/
macinf->lchid[macd_idx] = lchid;
rlcinf->mode[macd_idx] = lchId_rlc_map[lchid]; /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
-
+
/***************/
/* FIXME: This is probably wrong, but im writing it anyways*/
rlcinf->urnti[macd_idx] = p_fp_info->channel;
@@ -2624,7 +2622,7 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
rlcinf->ciphered[macd_idx] = FALSE;
rlcinf->deciphered[macd_idx] = FALSE;
p_fp_info->cur_tb = macd_idx; /*Set the transport block index (NOTE: This and not subnum is used in MAC dissector!)*/
-
+
/* TODO: use maces_tree? */
call_dissector(mac_fdd_edch_handle, next_tvb, pinfo, top_level_tree);
dissected = TRUE;
@@ -2689,7 +2687,6 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
guint32 total_bytes = 0;
gboolean F = TRUE; /* We want to continue loop if get E-RNTI indication... */
gint bit_offset;
-
proto_item *subframe_macis_descriptors_ti = NULL;
static struct edch_t2_subframe_info subframes[16];
@@ -2849,6 +2846,8 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
proto_item *macis_pdu_ti;
proto_tree *macis_pdu_tree;
+ umts_mac_info * macinf = (umts_mac_info *)p_get_proto_data(pinfo->fd, proto_umts_mac);
+ rlc_info * rlcinf = (rlc_info *)p_get_proto_data(pinfo->fd, proto_rlc);
/* Add subframe header subtree */
macis_pdu_ti = proto_tree_add_string_format(tree, hf_fp_edch_subframe_header, tvb, offset, 0,
@@ -2860,16 +2859,48 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
/* SS */
ss = (tvb_get_guint8(tvb, offset) & 0xc0) >> 6;
proto_tree_add_item(macis_pdu_tree, hf_fp_edch_macis_ss, tvb, offset, 1, ENC_BIG_ENDIAN);
+ switch (ss) {
+ case 0:
+ if (subframes[n].number_of_mac_is_sdus[pdu_no] > 1) {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU.");
+ } else {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU.");
+ }
+ break;
+ case 1:
+ if (subframes[n].number_of_mac_is_sdus[pdu_no] > 1) {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The last MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU.");
+ } else {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU.");
+ }
+ break;
+ case 2:
+ if (subframes[n].number_of_mac_is_sdus[pdu_no] > 1) {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The first MAC-is SDU of the MAC-is PDU is a complete MAC-d PDU or MAC-c PDU. The last MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
+ } else {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The MAC-is SDU of the MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
+ }
+ break;
+ case 3:
+ if (subframes[n].number_of_mac_is_sdus[pdu_no] > 1) {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The first MAC-is SDU of the MAC-is PDU is the last segment of a MAC-d PDU or MAC-c PDU and the last MAC-is SDU of MAC-is PDU is the first segment of a MAC-d PDU or MAC-c PDU.");
+ } else {
+ proto_tree_add_text(macis_pdu_tree, tvb, offset, 1, "SS interpretation: The MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU.");
+ }
+ break;
+ }
/* TSN */
- tsn = tvb_get_guint8(tvb, offset) & 0x03;
+ tsn = tvb_get_bits8(tvb, offset*8+2, 6);
proto_tree_add_item(macis_pdu_tree, hf_fp_edch_macis_tsn, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
+
/* MAC-is SDUs (i.e. MACd PDUs) */
for (sdu_no=0; sdu_no < subframes[n].number_of_mac_is_sdus[pdu_no]; sdu_no++) {
-
+ tvbuff_t * asm_tvb;
+ guint lchid = subframes[n].mac_is_lchid[pdu_no][sdu_no] + 1;
ti = proto_tree_add_item(macis_pdu_tree, hf_fp_edch_macis_sdu, tvb,
offset,
subframes[n].mac_is_length[pdu_no][sdu_no],
@@ -2879,6 +2910,24 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
subframes[n].mac_is_length[pdu_no][sdu_no],
tvb_bytes_to_str(tvb, offset, subframes[n].mac_is_length[pdu_no][sdu_no]));
+ /*Set up information needed for MAC and lower layers*/
+ macinf->content[sdu_no] = lchId_type_table[lchid]; /*Set the proper Content type for the mac layer.*/
+ macinf->lchid[sdu_no] = lchid;
+ rlcinf->mode[sdu_no] = lchId_rlc_map[lchid]; /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
+
+ /* FIXME: This is probably wrong, but im writing it anyways*/
+ rlcinf->urnti[sdu_no] = p_fp_info->channel;
+ rlcinf->rbid[sdu_no] = lchid; /*subframes[n].ddi[i];*/ /*Save the DDI value for RLC*/
+ rlcinf->li_size[sdu_no] = RLC_LI_7BITS;
+ rlcinf->ciphered[sdu_no] = FALSE;
+ rlcinf->deciphered[sdu_no] = FALSE;
+ p_fp_info->cur_tb = sdu_no; /*Set the transport block index (NOTE: This and not subnum is used in MAC dissector!)*/
+
+ asm_tvb = mac_is_add_fragment(tvb, pinfo, lchid, offset, ss, tsn, sdu_no, subframes[n].number_of_mac_is_sdus[pdu_no], subframes[n].mac_is_length[pdu_no][sdu_no]);
+ if (asm_tvb != NULL) {
+ call_dissector(mac_fdd_edch_handle, asm_tvb, pinfo, top_level_tree);
+ }
+
offset += subframes[n].mac_is_length[pdu_no][sdu_no];
subframe_bytes += subframes[n].mac_is_length[pdu_no][sdu_no];
}
@@ -2935,7 +2984,7 @@ dissect_hsdsch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
rlcinf = (rlc_info *)p_get_proto_data(pinfo->fd, proto_rlc);
macinf = (umts_mac_info *)p_get_proto_data(pinfo->fd, proto_umts_mac);
-
+
/**************************************/
/* HS-DCH data here (type 1 in R7) */
@@ -2979,11 +3028,11 @@ dissect_hsdsch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
user_buffer_size = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(tree, hf_fp_user_buffer_size, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
-
-
+
+
/************************/
/*Configure the pdus*/
- for(i=0;i<number_of_pdus; i++){
+ for(i=0;i<number_of_pdus; i++){
macinf->content[i] = hsdsch_macdflow_id_mac_content_map[p_fp_info->hsdsch_macflowd_id]; /*MAC_CONTENT_PS_DTCH;*/
macinf->lchid[i] = fake_lchid_macd_flow[p_fp_info->hsdsch_macflowd_id];/*Faked logical channel id 255 used as a mark it doesnt exists...*/
/*DEBUG: Remove ME!!*/
@@ -3005,8 +3054,8 @@ dissect_hsdsch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
rlcinf->deciphered[i] = FALSE;
rlcinf->rbid[i] = 16;
}
-
-
+
+
/* MAC-d PDUs */
offset = dissect_macd_pdu_data(tvb, pinfo, tree, offset, pdu_length,
number_of_pdus,p_fp_info);
@@ -3248,14 +3297,14 @@ dissect_hsdsch_type_2_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree
/* Now read the MAC-d/c PDUs for each block using info from headers */
for (n=0; n < number_of_pdu_blocks; n++) {
for(j=0;j<no_of_pdus[n];j++){
-
+
/*Configure (signal to lower layers) the PDU!*/
macinf->content[j] = lchId_type_table[lchid[n]+1];/*hsdsch_macdflow_id_mac_content_map[p_fp_info->hsdsch_macflowd_id];*/ /*MAC_CONTENT_PS_DTCH;*/
macinf->lchid[j] = (guint8)lchid[n]+1; /*Add 1 since C/T is zero indexed? ie C/T =0 => L-CHID = 1*/
macinf->macdflow_id[j] = p_fp_info->hsdsch_macflowd_id;
/*Figure out RLC_MODE based on MACd-flow-ID, basically MACd-flow-ID = 0 then its SRB0 == UM else AM*/
rlcinf->mode[j] = lchId_rlc_map[lchid[n]+1];/*hsdsch_macdflow_id_rlc_map[p_fp_info->hsdsch_macflowd_id];*/
-
+
/*macinf->ctmux[n] = TRUE;*/
/*FIXMED: We should also configure stuff like encypriont here, basically all the stuff RLC needs*/
rlcinf->li_size[j] = RLC_LI_7BITS;
@@ -3294,8 +3343,8 @@ heur_dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if ((oct & 0x01) == 1){
/*
* 6.3.2.1 Frame CRC
- * Description: It is the result of the CRC applied to the remaining part of the frame,
- * i.e. from bit 0 of the first byte of the header (the FT IE) to bit 0 of the last byte of the payload,
+ * Description: It is the result of the CRC applied to the remaining part of the frame,
+ * i.e. from bit 0 of the first byte of the header (the FT IE) to bit 0 of the last byte of the payload,
* with the corresponding generator polynomial: G(D) = D7+D6+D2+1. See subclause 7.2.
*/
length = tvb_length(tvb);
@@ -3339,17 +3388,17 @@ static guint8 fake_map[31];
* */
static guint8
make_fake_lchid(packet_info *pinfo _U_, gint trchld){
-
+
if( fake_map[trchld] == 0){
fake_map[trchld] = fakes;
fakes++;
}
-
+
return fake_map[trchld];
-
+
}
/*
- * july 2012:
+ * july 2012:
* Alot of configuration has been move into the actual dissecting functions
* since most of the configuration/signalign has to be set per tb (pdu) rather
* for the channel!
@@ -3366,7 +3415,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
umts_mac_info *macinf;
rlc_info *rlcinf;
guint8 fake_lchid=0;
-
+
fpi = se_new0(fp_info);
p_add_proto_data(pinfo->fd, proto_fp, fpi);
@@ -3407,7 +3456,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
/*Figure out RLC_MODE based on MACd-flow-ID, basically MACd-flow-ID = 0 then its SRB0 == UM else AM*/
rlcinf->mode[0] = hsdsch_macdflow_id_rlc_map[p_conv_data->hsdsch_macdflow_id];
-
+
/* Make configurable ?(available in NBAP?) */
/* urnti[MAX_RLC_CHANS] */
@@ -3448,8 +3497,8 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
fpi->edch_lchId[i] = p_conv_data->edch_lchId[i]; /*Set the channel id for this entry*/
/*macinf->content[i] = lchId_type_table[p_conv_data->edch_lchId[i]]; */ /*Set the proper Content type for the mac layer.*/
/* rlcinf->mode[i] = lchId_rlc_map[p_conv_data->edch_lchId[i]];*/ /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
-
- }
+
+ }
fpi->edch_type = p_conv_data->edch_type;
/* macinf = se_new0(umts_mac_info);
@@ -3463,7 +3512,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
rlcinf->li_size[0] = RLC_LI_7BITS;
rlcinf->ciphered[0] = FALSE;
rlcinf->deciphered[0] = FALSE;
-
+
p_add_proto_data(pinfo->fd, proto_rlc, rlcinf);
return fpi;
@@ -3486,7 +3535,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
/* control frame, we're done */
return fpi;
}
-
+
rlcinf = se_new0(rlc_info);
macinf = se_new0(umts_mac_info);
offset = 2; /*To correctly read the tfi*/
@@ -3495,7 +3544,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
/*tfi = tvb_get_guint8(tvb,offset);*/
/*TFI is 5 bits according to 3GPP TS 25.321, paragraph 6.2.4.4*/
tfi = tvb_get_bits8(tvb,3+offset*8,5);
-
+
/*Figure out the number of tbs and size*/
num_tbs = (fpi->is_uplink) ? p_conv_data->fp_dch_channel_info[chan].ul_chan_num_tbs[tfi] : p_conv_data->fp_dch_channel_info[chan].dl_chan_num_tbs[tfi];
tb_size= (fpi->is_uplink) ? p_conv_data->fp_dch_channel_info[i].ul_chan_tf_size[tfi] : p_conv_data->fp_dch_channel_info[i].dl_chan_tf_size[tfi];
@@ -3511,40 +3560,40 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
for(j=0; j < num_tbs; j++){
/*Set transport channel id (useful for debugging)*/
macinf->trchid[j+chan] = p_conv_data->dchs_in_flow_list[chan];
-
+
/*Transport Channel m31 and 24 might be multiplexed!*/
if( p_conv_data->dchs_in_flow_list[chan] == 31 || p_conv_data->dchs_in_flow_list[chan] == 24){
-
+
/****** MUST FIGURE OUT IF THIS IS REALLY MULTIPLEXED OR NOT*******/
/*If Trchid == 31 and only on TB, we have no multiplexing*/
if(0/*p_conv_data->dchs_in_flow_list[chan] == 31 && num_tbs == 1*/){
macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/
-
+
macinf->lchid[j+chan] = 1;
-
+
macinf->content[j+chan] = lchId_type_table[1]; /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
rlcinf->mode[j+chan] = lchId_rlc_map[1]; /*Based RLC mode on logical channel id*/
-
+
}
/*Indicate we don't have multiplexing.*/
else if (p_conv_data->dchs_in_flow_list[chan] == 24 && tb_size != 340){
macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/
-
+
/*g_warning("settin this for %d", pinfo->fd->num);*/
macinf->lchid[j+chan] = fake_lchid;
macinf->fake_chid[j+chan] = TRUE;
macinf->content[j+chan] = MAC_CONTENT_PS_DTCH; /*lchId_type_table[fake_lchid];*/ /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
rlcinf->mode[j+chan] = RLC_AM;/*lchId_rlc_map[fake_lchid];*/ /*Based RLC mode on logical channel id*/
- }
+ }
/*We have multiplexing*/
else{
macinf->ctmux[j+chan] = TRUE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/
-
+
/* Peek at C/T, different RLC params for different logical channels */
/*C/T is 4 bits according to 3GPP TS 25.321, paragraph 9.2.1, from MAC header (not FP)*/
c_t = tvb_get_bits8(tvb, tb_bit_off/*(2+p_conv_data->num_dch_in_flow)*8*/, 4); /* c_t = tvb_get_guint8(tvb,offset);*/
macinf->lchid[j+chan] = c_t+1;
-
+
macinf->content[j+chan] = lchId_type_table[c_t+1]; /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
rlcinf->mode[j+chan] = lchId_rlc_map[c_t+1]; /*Based RLC mode on logical channel id*/
}
@@ -3552,10 +3601,10 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/
/*macinf->content[j+chan] = MAC_CONTENT_CS_DTCH;*/
macinf->content[j+chan] = lchId_type_table[fake_lchid];
-
-
+
+
rlcinf->mode[j+chan] = lchId_rlc_map[fake_lchid];
-
+
/*Generate virtual logical channel id*/
/************************/
/*TODO: Once proper lchid is always set, this has to be removed*/
@@ -3563,18 +3612,18 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
macinf->lchid[j+chan] = fake_lchid; /*make_fake_lchid(pinfo, p_conv_data->dchs_in_flow_list[chan]);*/
/************************/
}
-
+
/*FIXME: NBAP should signal this?*/
/*Set rlc info*/
rlcinf->urnti[j+chan] = fpi->channel; /*Faked URNTI*/
rlcinf->li_size[j+chan] = RLC_LI_7BITS;
rlcinf->ciphered[j+chan] = FALSE;
rlcinf->deciphered[j+chan] = FALSE;
-
+
/*Step over this TB and it's C/T flag.*/
tb_bit_off += tb_size+4;
}
-
+
offset++;
}
p_add_proto_data(pinfo->fd, proto_umts_mac, macinf);
@@ -3681,8 +3730,8 @@ dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
p_conv = (conversation_t *)find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src,
pinfo->ptype,
pinfo->destport, pinfo->srcport, NO_ADDR_B);
-
-
+
+
if (p_conv) {
/*Find correct conversation, basically find the on thats closest to this frame*/
while(p_conv->next != NULL && p_conv->next->setup_frame < pinfo->fd->num){
@@ -3708,7 +3757,7 @@ dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Maybe the frame number should be stored in the proper location already in nbap?, in ul_frame_number*/
proto_item* item= proto_tree_add_uint(fp_tree, hf_fp_dl_setup_frame,
tvb, 0, 0, p_conv_data->ul_frame_number);
-
+
PROTO_ITEM_SET_GENERATED(item);
pinfo->link_dir=P2P_DIR_DL;
if (p_fp_info == NULL) {
@@ -3887,7 +3936,7 @@ dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
break;
case CHANNEL_HSDSCH_COMMON_T3:
expert_add_info_format(pinfo, NULL, PI_DEBUG, PI_ERROR, "HSDSCH COMMON T3 - Not implemeneted!");
-
+
/* TODO: */
break;
case CHANNEL_IUR_CPCHF:
@@ -4325,7 +4374,7 @@ void proto_register_fp(void)
},
{ &hf_fp_edch_macis_tsn,
{ "TSN",
- "fp.edch.mac-is.tsn", FT_UINT8, BASE_HEX, 0, 0x3f,
+ "fp.edch.mac-is.tsn", FT_UINT8, BASE_DEC, 0, 0x3f,
"Transmission Sequence Number", HFILL
}
},
diff --git a/epan/dissectors/packet-umts_mac.c b/epan/dissectors/packet-umts_mac.c
index a7cea8db62..607280d322 100644
--- a/epan/dissectors/packet-umts_mac.c
+++ b/epan/dissectors/packet-umts_mac.c
@@ -73,6 +73,33 @@ static dissector_handle_t rlc_dcch_handle;
static dissector_handle_t rlc_ps_dtch_handle;
static dissector_handle_t rrc_handle;
+/* MAC-is reassembly */
+typedef struct {
+ guint32 frame_num;
+ guint16 tsn;
+ guint8 * data;
+ guint32 length;
+ tvbuff_t * tvb;
+} mac_is_sdu;
+typedef struct {
+ guint8 * data;
+ guint32 length;
+ guint32 frame_num;
+} mac_is_fragment;
+static GHashTable * mac_is_sdus = NULL;
+static GHashTable * mac_is_fragments = NULL;
+
+static gboolean mac_is_sdu_equal(gconstpointer a, gconstpointer b)
+{
+ const mac_is_sdu *x = a, *y = b;
+ return x->frame_num == y->frame_num && x->tsn == y->tsn;
+}
+
+static guint mac_is_sdu_hash(gconstpointer key)
+{
+ const mac_is_sdu *sdu = key;
+ return (sdu->frame_num << 6) | sdu->tsn;
+}
static const value_string rach_fdd_tctf_vals[] = {
{ TCTF_CCCH_RACH_FDD , "CCCH over RACH (FDD)" },
@@ -525,6 +552,115 @@ static void dissect_mac_fdd_dch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
}
}
+static void init_frag(tvbuff_t * tvb, mac_is_fragment ** mifref, guint length, guint32 frame_num, guint offset)
+{
+ *mifref = g_new(mac_is_fragment, 1);
+ (*mifref)->length = length;
+ (*mifref)->data = g_malloc(length);
+ (*mifref)->frame_num = frame_num;
+ tvb_memcpy(tvb, (*mifref)->data, offset, length);
+}
+
+static tvbuff_t * reassemble(tvbuff_t * tvb, mac_is_fragment ** mifref, guint frame_num, guint16 tsn, guint maclength, guint offset, gboolean reverse)
+{
+ mac_is_sdu * sdu;
+ mac_is_fragment * mif = *mifref;
+
+ sdu = se_new(mac_is_sdu);
+ if (reverse) {
+ sdu->frame_num = mif->frame_num;
+ sdu->tsn = tsn-1;
+ } else {
+ sdu->frame_num = frame_num;
+ sdu->tsn = tsn;
+ }
+ sdu->length = mif->length + maclength;
+ sdu->data = se_alloc(sdu->length);
+
+ if (reverse == FALSE) {
+ memcpy(sdu->data, mif->data, mif->length);
+ tvb_memcpy(tvb, sdu->data+mif->length, offset, maclength);
+ } else {
+ tvb_memcpy(tvb, sdu->data, offset, maclength);
+ memcpy(sdu->data+maclength, mif->data, mif->length);
+ }
+ g_free(mif->data);
+ g_free(mif);
+ sdu->tvb = tvb_new_child_real_data(tvb, sdu->data, sdu->length, sdu->length);
+ g_hash_table_insert(mac_is_sdus, sdu, NULL);
+ *mifref = NULL; /* Reset the pointer. */
+ return sdu->tvb;
+}
+
+static tvbuff_t * get_sdu(tvbuff_t * tvb, packet_info * pinfo, guint16 tsn)
+{
+ gpointer orig_key = NULL;
+ mac_is_sdu sdu_lookup_key;
+ sdu_lookup_key.frame_num = pinfo->fd->num;
+ sdu_lookup_key.tsn = tsn;
+
+ if (g_hash_table_lookup_extended(mac_is_sdus, &sdu_lookup_key, &orig_key, NULL)) {
+ mac_is_sdu * sdu = orig_key;
+ sdu->tvb = tvb_new_child_real_data(tvb, sdu->data, sdu->length, sdu->length);
+ add_new_data_source(pinfo, sdu->tvb, "Reassembled MAC-is SDU");
+ return sdu->tvb;
+ }
+ return NULL;
+}
+
+tvbuff_t * mac_is_add_fragment(tvbuff_t * tvb, packet_info *pinfo, guint8 lchid, int offset, guint8 ss, guint16 tsn, int sdu_no, guint8 no_sdus, guint16 maclength)
+{
+ /* Get fragment table for this logical channel. */
+ mac_is_fragment ** fragments = g_hash_table_lookup(mac_is_fragments, GINT_TO_POINTER((gint)lchid));
+ /* If this is the first time we see this channel. */
+ if (fragments == NULL) {
+ /* Create new table */
+ fragments = se_alloc_array(mac_is_fragment*, 64);
+ memset(fragments, 0, sizeof(mac_is_fragment*)*64);
+ g_hash_table_insert(mac_is_fragments, GINT_TO_POINTER((gint)lchid), fragments);
+ }
+
+ /* If in first scan-through. */
+ if (pinfo->fd->flags.visited == FALSE) {
+ /* If first SDU is last segment of previous. A tail. */
+ if (sdu_no == 0 && (ss & 1) == 1) {
+ /* If no one has inserted the head for our tail yet. */
+ if (fragments[tsn] == NULL) {
+ init_frag(tvb, &fragments[tsn], maclength, pinfo->fd->num, offset);
+ /* If there is a head, attach a tail to it and return. */
+ } else {
+ return reassemble(tvb, &(fragments[tsn]), pinfo->fd->num, tsn, maclength, offset, FALSE);
+ }
+ }
+ /* If last SDU is first segment of next. A head. */
+ else if (sdu_no == no_sdus-1 && (ss & 2) == 2) {
+ /* If there is no tail yet, store away a head for a future tail. */
+ if (fragments[(tsn+1) % 64] == NULL) {
+ init_frag(tvb, &(fragments[(tsn+1)%64]), maclength, pinfo->fd->num, offset);
+ /* If there already is a tail for our head here, attach it. */
+ } else {
+ return reassemble(tvb, &fragments[(tsn+1)%64], pinfo->fd->num, tsn, maclength, offset, TRUE);
+ }
+ /* If our SDU is not fragmented. */
+ } else {
+ DISSECTOR_ASSERT((sdu_no == 0) ? (ss&1) == 0 : ((sdu_no == no_sdus-1) ? (ss&2) == 0 : TRUE));
+ return tvb_new_subset(tvb, offset, maclength, -1);
+ }
+ /* If clicking on a packet. */
+ } else {
+ /* If first SDU is last segment of previous. A tail. */
+ if (sdu_no == 0 && (ss & 1) == 1) {
+ return get_sdu(tvb, pinfo, tsn);
+ /* If last SDU is first segment of next. A head. */
+ } else if (sdu_no == no_sdus-1 && (ss & 2) == 2) {
+ return NULL; /* Do not give heads any data. */
+ } else {
+ return tvb_new_subset(tvb, offset, maclength, -1);
+ }
+ }
+ return NULL;
+}
+
static void dissect_mac_fdd_edch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
proto_tree *edch_tree = NULL;
@@ -700,6 +836,18 @@ static void dissect_mac_fdd_hsdsch(tvbuff_t *tvb, packet_info *pinfo, proto_tree
}
}
+static void mac_init(void)
+{
+ if (mac_is_sdus != NULL) {
+ g_hash_table_destroy(mac_is_sdus);
+ }
+ if (mac_is_fragments != NULL) {
+ g_hash_table_destroy(mac_is_fragments);
+ }
+ mac_is_sdus = g_hash_table_new(mac_is_sdu_hash, mac_is_sdu_equal);
+ mac_is_fragments = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
void
proto_register_umts_mac(void)
{
@@ -772,6 +920,8 @@ proto_register_umts_mac(void)
register_dissector("mac.fdd.dch", dissect_mac_fdd_dch, proto_umts_mac);
register_dissector("mac.fdd.edch", dissect_mac_fdd_edch, proto_umts_mac);
register_dissector("mac.fdd.hsdsch", dissect_mac_fdd_hsdsch, proto_umts_mac);
+
+ register_init_routine(mac_init);
}
void
diff --git a/epan/dissectors/packet-umts_mac.h b/epan/dissectors/packet-umts_mac.h
index ce610d2769..851a0777c9 100644
--- a/epan/dissectors/packet-umts_mac.h
+++ b/epan/dissectors/packet-umts_mac.h
@@ -64,10 +64,12 @@ typedef struct umts_mac_info
guint8 content[MAX_MAC_FRAMES];
guint8 lchid[MAX_MAC_FRAMES]; /*Makes displaying logical channel alot easier*/
guint8 macdflow_id[MAX_MAC_FRAMES]; /*Makes displaying logical channel alot easier*/
-
+
gboolean fake_chid[MAX_MAC_FRAMES]; /*Indicate if the child ID is faked or not*/
guint pdu_len; /*Length of MAC PDU, same for all PDUs in one FP frame*/
guint8 trchid[MAX_MAC_FRAMES]; /*Makes displaying logical channel alot easier*/
} umts_mac_info;
+tvbuff_t * mac_is_add_fragment(tvbuff_t * tvb, packet_info *pinfo, guint8 lchid, int offset, guint8 ss, guint16 tsn, int sdu_no, guint8 no_sdus, guint16 maclength);
+
#endif