From Jacob Nordgren and Rishie Sharma:

NBAP: fixed segfault, FP: aesthetic fix, RLC: added channel info to GUI, MAC-is: fixed case with reassembly when a middle segment arrives 

 MAC, RLC, added preferences for LI-size and TSN-size

svn path=/trunk/; revision=44205
This commit is contained in:
Anders Broman 2012-08-02 14:03:17 +00:00
parent 9b2d2a2433
commit 704e2f524e
5 changed files with 320 additions and 157 deletions

View File

@ -397,10 +397,10 @@ static gint nbap_key_cmp(gconstpointer a_ptr, gconstpointer b_ptr, gpointer igno
}
return GPOINTER_TO_INT(a_ptr) < GPOINTER_TO_INT(b_ptr);
}
static void nbap_free_key(gpointer key ){
/*static void nbap_free_key(gpointer key ){
g_free(key);
}
}*/
static void nbap_free_value(gpointer value ){
g_free(value);
}
@ -414,7 +414,7 @@ static void nbap_init(void){
/*Initialize*/
com_context_map = g_tree_new_full(nbap_key_cmp,
NULL, /* data pointer, optional */
nbap_free_key,
NULL,
nbap_free_value);
for (i = 0; i < 15; i++) {
lchId_type_table[i+1] = *lch_contents[i];

View File

@ -54776,10 +54776,10 @@ static gint nbap_key_cmp(gconstpointer a_ptr, gconstpointer b_ptr, gpointer igno
}
return GPOINTER_TO_INT(a_ptr) < GPOINTER_TO_INT(b_ptr);
}
static void nbap_free_key(gpointer key ){
/*static void nbap_free_key(gpointer key ){
g_free(key);
}
}*/
static void nbap_free_value(gpointer value ){
g_free(value);
}
@ -54793,7 +54793,7 @@ static void nbap_init(void){
/*Initialize*/
com_context_map = g_tree_new_full(nbap_key_cmp,
NULL, /* data pointer, optional */
nbap_free_key,
NULL,
nbap_free_value);
for (i = 0; i < 15; i++) {
lchId_type_table[i+1] = *lch_contents[i];

View File

@ -68,8 +68,6 @@ static gboolean global_rlc_ciphered = FALSE;
/* Stop trying to do reassembly if this is true. */
static gboolean fail = FALSE;
/* fields */
static int hf_rlc_seq = -1;
static int hf_rlc_ext = -1;
@ -105,6 +103,7 @@ static int hf_rlc_sufi_sn_ack = -1;
static int hf_rlc_sufi_sn_mrw = -1;
static int hf_rlc_sufi_poll_sn = -1;
static int hf_rlc_header_only = -1;
static int hf_rlc_channel = -1;
/* subtrees */
static int ett_rlc = -1;
@ -114,6 +113,7 @@ static int ett_rlc_sdu = -1;
static int ett_rlc_sufi = -1;
static int ett_rlc_bitmap = -1;
static int ett_rlc_rlist = -1;
static int ett_rlc_channel = -1;
static dissector_handle_t ip_handle;
static dissector_handle_t rrc_handle;
@ -1828,6 +1828,17 @@ rlc_am_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo,
seq, poll_set ? "(P)" : "");
}
static void add_channel_info(packet_info * pinfo, proto_tree * tree, fp_info * fpinf, rlc_info * rlcinf)
{
proto_item * item;
proto_tree * channel_tree;
item = proto_tree_add_item(tree, hf_rlc_channel, NULL, 0, 0, ENC_NA);
channel_tree = proto_item_add_subtree(item, ett_rlc_channel);
proto_item_append_text(item, " (lchid: %u, dir: %u, uid: %u)", rlcinf->rbid[fpinf->cur_tb], pinfo->p2p_dir, rlcinf->urnti[fpinf->cur_tb]);
PROTO_ITEM_SET_GENERATED(item);
}
static void
dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *top_level, proto_tree *tree)
@ -1883,10 +1894,12 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
"Cannot dissect RLC frame because per-frame info is missing");
return;
}
/* Add "channel" information, very useful for debugging. */
add_channel_info(pinfo, tree, fpinf, rlcinf);
pos = fpinf->cur_tb;
if (global_rlc_ciphered) {
proto_tree_add_text(tree, tvb, 0, -1,
"Cannot dissect RLC frame because it is ciphered");
@ -2444,6 +2457,10 @@ proto_register_rlc(void)
{ "RLC PDU header only", "rlc.header_only",
FT_BOOLEAN, BASE_NONE, TFS(&rlc_header_only_val), 0 ,NULL, HFILL }
},
{ &hf_rlc_channel,
{ "Channel", "rlc.channel",
FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
}
};
static gint *ett[] = {
&ett_rlc,
@ -2452,7 +2469,8 @@ proto_register_rlc(void)
&ett_rlc_sdu,
&ett_rlc_sufi,
&ett_rlc_bitmap,
&ett_rlc_rlist
&ett_rlc_rlist,
&ett_rlc_channel
};
proto_rlc = proto_register_protocol("Radio Link Control", "RLC", "rlc");
register_dissector("rlc.pcch", dissect_rlc_pcch, proto_rlc);

View File

@ -2658,7 +2658,7 @@ dissect_e_dch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
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 */
/* Set U-RNTI to ComuncationContext signaled from nbap*/
rlcinf->urnti[macd_idx] = p_fp_info->com_context_id;
rlcinf->rbid[macd_idx] = lchid; /*subframes[n].ddi[i];*/ /*Save the DDI value for RLC*/
@ -2734,7 +2734,7 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
guint64 total_macis_sdus;
guint16 macis_sdus_found = 0;
guint16 macis_pdus = 0;
guint32 total_bytes = 0;
/*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;
@ -2907,8 +2907,8 @@ dissect_e_dch_t2_or_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto
}
/* Add data summary to info column */
col_append_fstr(pinfo->cinfo, COL_INFO, " (%u bytes in %u SDUs in %u MAC-is PDUs in %u subframes)",
total_bytes, macis_sdus_found, macis_pdus, number_of_subframes);
/*col_append_fstr(pinfo->cinfo, COL_INFO, " (%u bytes in %u SDUs in %u MAC-is PDUs in %u subframes)",
total_bytes, macis_sdus_found, macis_pdus, number_of_subframes);*/
/* Spare extension and payload CRC (optional) */
dissect_spare_extension_and_crc(tvb, pinfo, tree,
@ -3632,7 +3632,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
fpi->srcport = pinfo->srcport;
fpi->destport = pinfo->destport;
fpi->com_context_id = p_conv_data->com_context_id;
if (pinfo->link_dir==P2P_DIR_UL) {
fpi->is_uplink = TRUE;
} else {
@ -3891,7 +3891,7 @@ fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
rlcinf->urnti[chan] = fpi->com_context_id; /*Note that MAC probably will change this*/
}
p_add_proto_data(pinfo->fd, proto_umts_mac, macinf);
p_add_proto_data(pinfo->fd, proto_rlc, rlcinf);

View File

@ -66,8 +66,8 @@ static int hf_mac_edch_type2_tsn = -1;
static int hf_mac_edch_type2_ss = -1;
static int hf_mac_edch_type2_sdu = -1;
static int hf_mac_edch_type2_sdu_data = -1;
static int hf_mac_is_2head_link = -1;
static int hf_mac_is_2tail_link = -1;
static int hf_mac_is_fraglink = -1;
static int hf_mac_is_reasmin = -1;
/* subtrees */
static int ett_mac = -1;
@ -88,30 +88,57 @@ static dissector_handle_t rlc_ps_dtch_handle;
static dissector_handle_t rrc_handle;
/* MAC-is reassembly */
typedef struct {
enum mac_is_fragment_type {
MAC_IS_HEAD,
MAC_IS_MIDDLE,
MAC_IS_TAIL
};
typedef struct _mac_is_fragment {
guint8 * data;
guint32 length;
guint32 frame_num;
guint16 tsn;
guint8 type;
struct _mac_is_fragment * next;
} mac_is_fragment;
typedef struct {
guint32 frame_num; /* Where reassembly was done (depends on order of arrival). */
guint16 tsn; /* TSN for the tail fragment. */
guint8 * data;
guint32 length;
tvbuff_t * tvb;
guint counterpart;
mac_is_fragment * fragments;
} 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)
mac_is_fragment * head;
mac_is_fragment * middle;
mac_is_fragment * tail;
} body_parts;
typedef struct {
guint8 lchid; /* Logical Channel Identifier. */
guint ueid; /* User Equipment Identifier. */
} mac_is_channel;
static GHashTable * mac_is_sdus = NULL; /* channel -> (frag -> sdu) */
static GHashTable * mac_is_fragments = NULL; /* channel -> body_parts[] */
static gboolean mac_is_channel_equal(gconstpointer a, gconstpointer b)
{
const mac_is_sdu *x = a, *y = b;
return x->frame_num == y->frame_num && x->tsn == y->tsn;
const mac_is_channel *x = a, *y = b;
return x->lchid == y->lchid && x->ueid == y->ueid;
}
static guint mac_is_sdu_hash(gconstpointer key)
static guint mac_is_channel_hash(gconstpointer key)
{
const mac_is_sdu *sdu = key;
return (sdu->frame_num << 6) | sdu->tsn; /* Not so good for TSN 14 bits */
const mac_is_channel * ch = key;
return (ch->ueid << 4) | ch->lchid;
}
static gboolean mac_is_fragment_equal(gconstpointer a, gconstpointer b)
{
const mac_is_fragment *x = a, *y = b;
return x->frame_num == y->frame_num && x->tsn == y->tsn && x->type == y->type;
}
static guint mac_is_fragment_hash(gconstpointer key)
{
const mac_is_fragment *frag = key;
return (frag->frame_num << 2) | frag->type;
}
static const value_string rach_fdd_tctf_vals[] = {
@ -187,7 +214,7 @@ static guint16 tree_add_common_dcch_dtch_fields(tvbuff_t *tvb, packet_info *pinf
proto_tree *tree, guint16 bitoffs, fp_info *fpinf, umts_mac_info *macinf, rlc_info *rlcinf)
{
guint8 ueid_type;
ueid_type = tvb_get_bits8(tvb, bitoffs, 2);
proto_tree_add_bits_item(tree, hf_mac_ueid_type, tvb, bitoffs, 2, ENC_BIG_ENDIAN);
bitoffs += 2;
@ -202,11 +229,14 @@ static guint16 tree_add_common_dcch_dtch_fields(tvbuff_t *tvb, packet_info *pinf
}
if (macinf->ctmux[fpinf->cur_tb]) {
proto_item * temp;
if(rlcinf){
rlcinf->rbid[fpinf->cur_tb] = tvb_get_bits8(tvb, bitoffs, 4)+1;
}
proto_tree_add_bits_item(tree, hf_mac_ct, tvb, bitoffs, 4, ENC_BIG_ENDIAN);
bitoffs += 4;
temp = proto_tree_add_uint(tree, hf_mac_lch_id, tvb, 0, 0, rlcinf->rbid[fpinf->cur_tb]);
PROTO_ITEM_SET_GENERATED(temp);
}
return bitoffs;
}
@ -568,130 +598,241 @@ 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)
static void init_frag(tvbuff_t * tvb, body_parts * bp, guint length, guint offset, guint32 frame_num, guint16 tsn, guint8 type)
{
*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);
mac_is_fragment * frag = se_new(mac_is_fragment);
frag->type = type;
frag->length = length;
frag->data = g_malloc(length);
frag->frame_num = frame_num;
frag->tsn = tsn;
frag->next = NULL;
switch (type) {
case MAC_IS_HEAD:
DISSECTOR_ASSERT(bp->head == NULL);
bp->head = frag;
break;
case MAC_IS_MIDDLE:
DISSECTOR_ASSERT(bp->middle == NULL);
bp->middle = frag;
break;
case MAC_IS_TAIL:
DISSECTOR_ASSERT(bp->tail == NULL);
bp->tail = frag;
break;
}
tvb_memcpy(tvb, frag->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)
static void mac_is_copy(mac_is_sdu * sdu, mac_is_fragment * frag, guint total_length, gboolean reverse)
{
mac_is_sdu * head_sdu, * tail_sdu;
mac_is_fragment * mif = *mifref;
head_sdu = se_new(mac_is_sdu); /* SDU with head TSN and frame number. */
tail_sdu = se_new(mac_is_sdu); /* SDU with tail TSN and frame number. */
/* If reverse then we are sending in a head TSN and frame number. */
DISSECTOR_ASSERT(sdu->length+frag->length <= total_length);
if (reverse) {
mac_is_sdu * temp = head_sdu;
/* A tail comes in the TSN after a head. */
head_sdu->tsn = tail_sdu->tsn = (tsn+1)%64;
/* Swap. Head is tail, ehehehe. */
head_sdu = tail_sdu;
tail_sdu = temp;
} else { /* Else we are sending in a tail TSN and frame number. */
head_sdu->tsn = tail_sdu->tsn = tsn;
}
tail_sdu->frame_num = head_sdu->counterpart = frame_num;
head_sdu->frame_num = tail_sdu->counterpart = mif->frame_num;
tail_sdu->length = mif->length + maclength;
tail_sdu->data = se_alloc(tail_sdu->length);
head_sdu->length = 0;
head_sdu->data = NULL;
head_sdu->tvb = NULL;
if (reverse == FALSE) {
memcpy(tail_sdu->data, mif->data, mif->length);
tvb_memcpy(tvb, tail_sdu->data+mif->length, offset, maclength);
memcpy(sdu->data+total_length-frag->length-sdu->length, frag->data, frag->length);
} else {
tvb_memcpy(tvb, tail_sdu->data, offset, maclength);
memcpy(tail_sdu->data+maclength, mif->data, mif->length);
memcpy(sdu->data+sdu->length, frag->data, frag->length);
}
g_free(mif->data);
g_free(mif);
tail_sdu->tvb = tvb_new_child_real_data(tvb, tail_sdu->data, tail_sdu->length, tail_sdu->length);
g_hash_table_insert(mac_is_sdus, head_sdu, NULL);
g_hash_table_insert(mac_is_sdus, tail_sdu, NULL);
*mifref = NULL; /* Reset the pointer. */
return tail_sdu->tvb;
sdu->length += frag->length;
//g_free(frag->data);
}
static mac_is_sdu * get_sdu(tvbuff_t * tvb, packet_info * pinfo, guint16 tsn)
/*
* @param length Length of whole SDU, it will be verified.
*/
static tvbuff_t * reassemble(tvbuff_t * tvb, body_parts ** body_parts_array, guint16 head_tsn, guint length, mac_is_channel * ch, guint frame_num)
{
gpointer orig_key = NULL;
mac_is_sdu sdu_lookup_key;
sdu_lookup_key.frame_num = pinfo->fd->num;
sdu_lookup_key.tsn = tsn;
mac_is_sdu * sdu;
mac_is_fragment * f;
guint16 i;
GHashTable * sdus;
if (g_hash_table_lookup_extended(mac_is_sdus, &sdu_lookup_key, &orig_key, NULL)) {
mac_is_sdu * sdu = orig_key;
if (sdu->length > 0) {
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");
}
/* Find frag->sdu hash table for this channel. */
sdus = g_hash_table_lookup(mac_is_sdus, ch);
/* If this is the first time we see this channel. */
if (sdus == NULL) {
mac_is_channel * channel;
sdus = g_hash_table_new(mac_is_fragment_hash, mac_is_fragment_equal);
channel = se_new(mac_is_channel);
*channel = *ch;
g_hash_table_insert(mac_is_sdus, channel, sdus);
}
sdu = se_new(mac_is_sdu);
sdu->length = 0;
sdu->data = se_alloc(length);
f = body_parts_array[head_tsn]->head; /* Start from head. */
g_hash_table_insert(sdus, f, sdu); /* Insert head->sdu mapping. */
body_parts_array[head_tsn]->head = NULL; /* Reset head. */
mac_is_copy(sdu, f, length, FALSE); /* Copy head data into SDU. */
sdu->fragments = f; /* Set up fragments list to point at head. */
sdu->frame_num = frame_num; /* Frame number where reassembly is being done. */
for (i = (head_tsn+1)%64; body_parts_array[i]->middle != NULL; i = (i+1)%64)
{
f = f->next = body_parts_array[i]->middle; /* Iterate through. */
g_hash_table_insert(sdus, f, sdu); /* Insert middle->sdu mapping. */
body_parts_array[i]->middle = NULL; /* Reset. */
mac_is_copy(sdu, f, length, FALSE); /* Copy middle data into SDU. */
}
DISSECTOR_ASSERT(body_parts_array[i]->tail != NULL);
f->next = body_parts_array[i]->tail;
g_hash_table_insert(sdus, f->next, sdu); /* Insert tail->sdu mapping. */
body_parts_array[i]->tail = NULL; /* Reset tail. */
sdu->tsn = i; /* Use TSN of tail as key for the SDU. */
mac_is_copy(sdu, f->next, length, FALSE); /* Copy tail data into SDU. */
return tvb_new_child_real_data(tvb, sdu->data, sdu->length, sdu->length);
}
static mac_is_sdu * get_sdu(guint frame_num, guint16 tsn, guint8 type, mac_is_channel * ch)
{
mac_is_sdu * sdu = NULL;
GHashTable * sdus = NULL;
mac_is_fragment frag_lookup_key;
sdus = g_hash_table_lookup(mac_is_sdus, ch);
if (sdus) {
frag_lookup_key.frame_num = frame_num;
frag_lookup_key.tsn = tsn;
frag_lookup_key.type = type;
sdu = g_hash_table_lookup(sdus, &frag_lookup_key);
return sdu;
}
return NULL;
}
static tvbuff_t * add_to_tree(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, int id, guint16 tsn, guint offset, guint16 maclength)
static tvbuff_t * add_to_tree(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, mac_is_sdu * sdu, guint offset, guint16 maclength, guint8 type)
{
mac_is_sdu * sdu = get_sdu(tvb, pinfo, tsn);
tvbuff_t * new_tvb = NULL;
DISSECTOR_ASSERT(sdu != NULL);
if (sdu->length > 0) {
new_tvb = sdu->tvb;
if (sdu->frame_num == pinfo->fd->num) {
mac_is_fragment * f = sdu->fragments;
guint counter = 0;
new_tvb = tvb_new_child_real_data(tvb, sdu->data, sdu->length, sdu->length);
add_new_data_source(pinfo, new_tvb, "Reassembled MAC-is SDU");
proto_tree_add_text(tree, new_tvb, 0, -1, "[Reassembled MAC-is SDU]");
proto_tree_add_uint_format(tree, id, tvb, 0, 0, sdu->counterpart, "Reassembled with fragment in frame: %u", sdu->counterpart);
proto_tree_add_item(tree, hf_mac_edch_type2_sdu_data, new_tvb, 0, -1, ENC_NA);
while (f) {
proto_tree_add_uint_format(tree, hf_mac_is_fraglink, new_tvb,
counter, f->length, f->frame_num,
"Frame: %u, payload: %u-%u (%u bytes) (TSN: %u)",
f->frame_num, counter, counter+f->length-1, f->length,
f->tsn);
counter += f->length;
f = f->next;
}
return new_tvb;
} else {
new_tvb = tvb_new_subset(tvb, offset, maclength, -1);
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is the last segment of a MAC-d PDU or MAC-c PDU.]");
proto_tree_add_item(tree, hf_mac_edch_type2_sdu_data, new_tvb, 0, -1, ENC_NA);
proto_tree_add_uint(tree, id, tvb, 0, 0, sdu->counterpart);
switch (type) {
case MAC_IS_HEAD:
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is the first segment of a MAC-d PDU or MAC-c PDU.]");
break;
case MAC_IS_MIDDLE:
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is a middle segment of a MAC-d PDU or MAC-c PDU.]");
break;
case MAC_IS_TAIL:
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is the last segment of a MAC-d PDU or MAC-c PDU.]");
break;
}
proto_tree_add_uint(tree, hf_mac_is_reasmin, new_tvb, 0, 0, sdu->frame_num);
return NULL; /* No data here. */
}
}
tvbuff_t * mac_is_add_fragment(tvbuff_t * tvb, packet_info *pinfo, proto_tree * tree, guint8 lchid, int offset, guint8 ss, guint16 tsn, int sdu_no, guint8 no_sdus, guint16 maclength)
/*
* If return value > 0 then tsn is changed to be tsn of head.
* @return return length of sequence tsn-1 to head.
*/
static guint find_head(body_parts ** body_parts_array, guint16 * tsn)
{
/* 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);
guint length = 0;
for (*tsn = (*tsn==0)?63:(*tsn)-1; body_parts_array[*tsn]->middle != NULL; *tsn = (*tsn==0)?63:(*tsn)-1)
length += body_parts_array[*tsn]->middle->length;
if (body_parts_array[*tsn]->head != NULL)
return length+body_parts_array[*tsn]->head->length;
return 0;
}
/*
* @return return length of sequence tsn+1 to tail.
*/
static guint find_tail(body_parts ** body_parts_array, guint16 tsn)
{
guint length = 0;
for (tsn = (tsn+1)%64; body_parts_array[tsn]->middle != NULL; tsn = (tsn+1)%64)
length += body_parts_array[tsn]->middle->length;
if (body_parts_array[tsn]->tail != NULL)
return length+body_parts_array[tsn]->tail->length;
return 0;
}
/*
* @param ch Channel for which body parts are to be fetched.
* @return Array of body_part* for channel 'ch'.
*/
static body_parts ** get_body_parts(mac_is_channel * ch)
{
body_parts ** bpa = g_hash_table_lookup(mac_is_fragments, ch);
/* If there was no body_part* array for this channel, create one. */
if (bpa == NULL) {
mac_is_channel * channel;
int i;
bpa = se_alloc_array(body_parts*, 64); /* Create new body_parts-pointer array */
for (i = 0; i < 64; i++) {
bpa[i] = se_new0(body_parts); /* Fill it with body_parts. */
}
channel = se_new(mac_is_channel); /* Alloc new channel for use in hash table. */
*channel = *ch;
g_hash_table_insert(mac_is_fragments, channel, bpa);
}
return bpa;
}
tvbuff_t * mac_is_add_fragment(tvbuff_t * tvb _U_, packet_info *pinfo, proto_tree * tree _U_, guint8 lchid, guint ueid, int offset, guint8 ss, guint16 tsn, int sdu_no, guint8 no_sdus, guint16 maclength)
{
mac_is_channel ch; /* Channel for looking up in hash tables. */
ch.lchid = lchid;
ch.ueid = ueid;
/* If in first scan-through. */
if (pinfo->fd->flags.visited == FALSE) {
/* Get body parts array for this channel. */
body_parts ** body_parts_array = get_body_parts(&ch);
/* Middle segment */
if (no_sdus == 1 && ss == 3) {
guint head_length, tail_length;
init_frag(tvb, body_parts_array[tsn], maclength, offset, pinfo->fd->num, tsn, MAC_IS_MIDDLE);
tail_length = find_tail(body_parts_array, tsn);
if (tail_length > 0) {
head_length = find_head(body_parts_array, &tsn);
if (head_length > 0) {
/* tsn is now TSN of head */
return reassemble(tvb, body_parts_array, tsn, tail_length+head_length+maclength, &ch, pinfo->fd->num);
}
}
/* XXX: haven't confirmed if case when middle segment comes last
* actually works or not. */
}
/* 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);
else if (sdu_no == 0 && (ss & 1) == 1) {
guint length = maclength;
init_frag(tvb, body_parts_array[tsn], maclength, offset, pinfo->fd->num, tsn, MAC_IS_TAIL);
length += find_head(body_parts_array, &tsn);
if (length > maclength) {
/* tsn is now TSN of head */
return reassemble(tvb, body_parts_array, tsn, length, &ch, pinfo->fd->num);
}
}
/* 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);
guint length = maclength;
init_frag(tvb, body_parts_array[tsn], maclength, offset, pinfo->fd->num, tsn, MAC_IS_HEAD);
length += find_tail(body_parts_array, tsn);
if (length > maclength) {
return reassemble(tvb, body_parts_array, tsn, length, &ch, pinfo->fd->num);
}
/* If our SDU is not fragmented. */
} else {
@ -700,32 +841,29 @@ tvbuff_t * mac_is_add_fragment(tvbuff_t * tvb, packet_info *pinfo, proto_tree *
}
/* If clicking on a packet. */
} else if (tree) {
tvbuff_t * new_tvb = NULL;
/* Middle segment */
if (no_sdus == 1 && ss == 3) {
mac_is_sdu * sdu = get_sdu(pinfo->fd->num, tsn, MAC_IS_MIDDLE, &ch);
if (sdu) {
return add_to_tree(tvb, pinfo, tree, sdu, offset, maclength, MAC_IS_MIDDLE);
}
}
/* If first SDU is last segment of previous. A tail. */
if (sdu_no == 0 && (ss & 1) == 1) {
return add_to_tree(tvb, pinfo, tree, hf_mac_is_2head_link, tsn, offset, maclength);
else if (sdu_no == 0 && (ss & 1) == 1) {
mac_is_sdu * sdu = get_sdu(pinfo->fd->num, tsn, MAC_IS_TAIL, &ch);
if (sdu) {
return add_to_tree(tvb, pinfo, tree, sdu, offset, maclength, MAC_IS_TAIL);
}
}
/* If last SDU is first segment of next. A head. */
} else if (sdu_no == no_sdus-1 && (ss & 2) == 2) {
/* tsn+1 because reassembly is done in the tail which comes in the
* TSN after the head. */
mac_is_sdu * sdu = get_sdu(tvb, pinfo, (tsn+1)%64);
tvbuff_t * new_tvb = NULL;
DISSECTOR_ASSERT(sdu != NULL);
if (sdu->length > 0) {
new_tvb = sdu->tvb;
proto_tree_add_text(tree, new_tvb, 0, -1, "[Reassembled MAC-is SDU]");
proto_tree_add_uint_format(tree, hf_mac_is_2tail_link, tvb, 0, 0, sdu->counterpart, "Reassembled with fragment in frame: %u", sdu->counterpart);
proto_tree_add_item(tree, hf_mac_edch_type2_sdu_data, new_tvb, 0, -1, ENC_NA);
return new_tvb;
} else {
new_tvb = tvb_new_subset(tvb, offset, maclength, -1);
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is the first segment of a MAC-d PDU or MAC-c PDU.]");
proto_tree_add_item(tree, hf_mac_edch_type2_sdu_data, new_tvb, 0, -1, ENC_NA);
proto_tree_add_uint(tree, hf_mac_is_2tail_link, tvb, 0, 0, sdu->counterpart);
return NULL; /* No data here. */
else if (sdu_no == no_sdus-1 && (ss & 2) == 2) {
mac_is_sdu * sdu = get_sdu(pinfo->fd->num, tsn, MAC_IS_HEAD, &ch);
if (sdu) {
return add_to_tree(tvb, pinfo, tree, sdu, offset, maclength, MAC_IS_HEAD);
}
} else {
tvbuff_t * new_tvb = tvb_new_subset(tvb, offset, maclength, -1);
new_tvb = tvb_new_subset(tvb, offset, maclength, -1);
proto_tree_add_text(tree, new_tvb, 0, -1, "[This MAC-is SDU is a complete MAC-d PDU or MAC-c PDU]");
proto_tree_add_item(tree, hf_mac_edch_type2_sdu_data, new_tvb, 0, -1, ENC_NA);
return new_tvb;
@ -798,13 +936,13 @@ static void dissect_mac_fdd_edch_type2(tvbuff_t *tvb, packet_info *pinfo, proto_
guint sdu_no, subframe_bytes = 0, offset = 0;
guint8 ss;
guint16 tsn;
proto_item *pi;
proto_item *pi, *temp;
proto_tree *macis_pdu_tree, *macis_sdu_tree;
umts_mac_is_info * mac_is_info = (umts_mac_is_info *)p_get_proto_data(pinfo->fd, proto_umts_mac);
rlc_info * rlcinf = (rlc_info *)p_get_proto_data(pinfo->fd, proto_rlc);
struct fp_info *p_fp_info = (struct fp_info *)p_get_proto_data(pinfo->fd, proto_fp);
DISSECTOR_ASSERT(mac_is_info != NULL);
DISSECTOR_ASSERT(rlcinf != NULL);
DISSECTOR_ASSERT(mac_is_info != NULL && rlcinf != NULL && p_fp_info != NULL);
pi = proto_tree_add_item(tree, proto_umts_mac, tvb, 0, -1, ENC_NA);
macis_pdu_tree = proto_item_add_subtree(pi, ett_mac_edch_type2);
@ -831,15 +969,17 @@ static void dissect_mac_fdd_edch_type2(tvbuff_t *tvb, packet_info *pinfo, proto_
ti = proto_tree_add_item(tree, hf_mac_edch_type2_sdu, tvb, offset, sdulength, ENC_NA);
macis_sdu_tree = proto_item_add_subtree(ti, ett_mac_edch_type2_sdu);
proto_item_append_text(ti, " (Logical channel=%u, Len=%u)", lchid, sdulength);
temp = proto_tree_add_uint(ti, hf_mac_lch_id, tvb, 0, 0, lchid);
PROTO_ITEM_SET_GENERATED(temp);
/*Set up information needed for MAC and lower layers*/
rlcinf->mode[sdu_no] = lchId_rlc_map[lchid]; /* Set RLC mode by lchid to RLC_MODE map in nbap.h */
rlcinf->urnti[sdu_no] = 1; /* TODO set proper value here */
rlcinf->urnti[sdu_no] = p_fp_info->com_context_id;
rlcinf->rbid[sdu_no] = lchid;
rlcinf->li_size[sdu_no] = RLC_LI_7BITS;
rlcinf->ciphered[sdu_no] = FALSE;
rlcinf->deciphered[sdu_no] = FALSE;
asm_tvb = mac_is_add_fragment(tvb, pinfo, macis_sdu_tree, lchid, offset, ss, tsn, sdu_no, mac_is_info->number_of_mac_is_sdus, sdulength);
asm_tvb = mac_is_add_fragment(tvb, pinfo, macis_sdu_tree, lchid, p_fp_info->com_context_id, offset, ss, tsn, sdu_no, mac_is_info->number_of_mac_is_sdus, sdulength);
if (asm_tvb != NULL) {
call_rlc(asm_tvb, pinfo, tree, ti, lchid);
}
@ -1140,6 +1280,11 @@ static void dissect_mac_fdd_hsdsch(tvbuff_t *tvb, packet_info *pinfo, proto_tree
}
}
static void mac_is_sdus_hash_destroy(gpointer data)
{
g_hash_table_destroy((GHashTable *)data);
}
static void mac_init(void)
{
if (mac_is_sdus != NULL) {
@ -1148,8 +1293,8 @@ static void mac_init(void)
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);
mac_is_sdus = g_hash_table_new_full(mac_is_channel_hash, mac_is_channel_equal, NULL, mac_is_sdus_hash_destroy);
mac_is_fragments = g_hash_table_new_full(mac_is_channel_hash, mac_is_channel_equal, NULL, NULL);
}
void
@ -1241,7 +1386,7 @@ proto_register_umts_mac(void)
{ &hf_mac_edch_type2_ss,
{ "SS",
/* TODO: VALS */
"mac.edch.type2.tsn", FT_UINT8, BASE_HEX, NULL, 0xc0,
"mac.edch.type2.ss", FT_UINT8, BASE_HEX, NULL, 0xc0,
"Segmentation Status", HFILL
}
},
@ -1269,12 +1414,12 @@ proto_register_umts_mac(void)
"EDCH Subframe header", HFILL
}
},
{ &hf_mac_is_2tail_link,
{ "Reassembled in frame", "mac.is.taillink",
{ &hf_mac_is_reasmin,
{ "Reassembled in frame", "mac.is.reasmin",
FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }
},
{ &hf_mac_is_2head_link,
{ "Reassembled in frame", "mac.is.headlink",
{ &hf_mac_is_fraglink,
{ "Frame", "mac.is.fraglink",
FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }
}
};