diff options
author | Anders Broman <anders.broman@ericsson.com> | 2012-07-18 07:45:19 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2012-07-18 07:45:19 +0000 |
commit | fccbea67023e20b02a526856698d507b77e160ae (patch) | |
tree | f0b61bf08487bdfc5943bf3f63313f899d3854fc | |
parent | 9d470cceb9a34fa4c5a90169a075e10c576c4e65 (diff) |
Merge the rest of Jacob Nordgren and Rishie Sharmas work on
Updateing conversation handling to dissect FP/MAC/RLC
(Work in progress).
svn path=/trunk/; revision=43781
-rw-r--r-- | asn1/nbap/nbap.cnf | 89 | ||||
-rw-r--r-- | asn1/nbap/packet-nbap-template.c | 75 | ||||
-rw-r--r-- | asn1/rrc/packet-rrc-template.c | 2 | ||||
-rw-r--r-- | asn1/rrc/rrc.cnf | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-rlc.c | 359 | ||||
-rw-r--r-- | epan/dissectors/packet-umts_fp.c | 25 | ||||
-rw-r--r-- | epan/dissectors/packet-umts_fp.h | 4 |
7 files changed, 456 insertions, 100 deletions
diff --git a/asn1/nbap/nbap.cnf b/asn1/nbap/nbap.cnf index d1362ae09e..b3361b69da 100644 --- a/asn1/nbap/nbap.cnf +++ b/asn1/nbap/nbap.cnf @@ -4,8 +4,8 @@ # Modified 2012 by Jacob Nordgren <jacob.nordgren@ericsson.com> and # Rishie Sharma <rishie.sharma@ericsson.com> # $Id$ - #.OPT + PER ALIGNED #.END @@ -1073,6 +1073,12 @@ dch_id = 0xFFFFFFFF; { return offset; } + + /*RBS might sometimes send a nonses bind, to indicate that no DCH is present*/ + if(BindingID_port == NBAP_IGNORE_PORT){ + return offset; + } + SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); dst_addr.type=AT_IPv4; @@ -1093,7 +1099,7 @@ dch_id = 0xFFFFFFFF; conversation_set_dissector(conversation, fp_handle); if(actx->pinfo->link_dir==P2P_DIR_DL){ umts_fp_conversation_info = se_new0(umts_fp_conversation_info_t); - + /* Fill in the data */ umts_fp_conversation_info->iface_type = IuB_Interface; umts_fp_conversation_info->division = Division_FDD; @@ -1146,6 +1152,7 @@ dch_id = 0xFFFFFFFF; umts_fp_conversation_info->fp_dch_channel_info[umts_fp_conversation_info->num_dch_in_flow].dl_chan_tf_size[j] = nbap_dch_chnl_info[i].dl_chan_tf_size[j]; umts_fp_conversation_info->fp_dch_channel_info[umts_fp_conversation_info->num_dch_in_flow].dl_chan_num_tbs[j] = nbap_dch_chnl_info[i].dl_chan_num_tbs[j]; } + } umts_fp_conversation_info->num_dch_in_flow++; umts_fp_conversation_info->dchs_in_flow_list[umts_fp_conversation_info->num_dch_in_flow] = i; @@ -1181,7 +1188,13 @@ BindingID_port = 0; &null_addr, PT_UDP, BindingID_port, 0, NO_ADDR_B|NO_PORT_B); - if (conversation == NULL) { + /* We must also check if this port is about to be overriden, if thats the case we + * might already have a DCH entry on this port which should be overwritten + */ + if (conversation == NULL || ((umts_fp_conversation_info_t*)conversation_get_proto_data(conversation, proto_fp))->channel == CHANNEL_DCH) { + + + /* It's not part of any conversation - create a new one. */ conversation = conversation_new(actx->pinfo->fd->num, &dst_addr, &null_addr, PT_UDP,BindingID_port , @@ -1206,10 +1219,12 @@ BindingID_port = 0; COPY_ADDRESS(&(nbap_edch_channel_info[e_dch_macdflow_id].crnc_address),&dst_addr); nbap_edch_channel_info[e_dch_macdflow_id].crnc_port = BindingID_port; + /*Figure out if this is a reconfiguration. then we must steal DDI entries from previous*/ + /* Can we always use old entries? they will be overwritten later? */ set_umts_fp_conv_data(conversation, umts_fp_conversation_info); } - - } + } + #.FN_BODY E-DCH-MACdFlow-Specific-InfoItem umts_fp_conversation_info_t *p_conv_data = NULL; @@ -1218,12 +1233,11 @@ conversation_t *p_conv; guint32 no_ddi_entries, i; %(DEFAULT_BODY)s - if (actx->pinfo->fd->flags.visited) { return offset; } - /* Check if we have converstaion info */ + /* Check if we have conversation info */ SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); p_conv = find_conversation(actx->pinfo->fd->num, &nbap_edch_channel_info[e_dch_macdflow_id].crnc_address, &null_addr, PT_UDP, @@ -1326,23 +1340,48 @@ guint32 no_ddi_entries, i; nbap_hsdsch_channel_info[hsdsch_macdflow_id].hsdsch_physical_layer_category = hsdsch_physical_layer_category; #.FN_BODY HSDSCH-MACdFlows-Information + + int protocol_ie_id; + guint32 i; num_items = 0; - + protocol_ie_id = ProtocolIE_ID; + + + /*Handle special cases, when the tree is weird, ie. no useful message appears in the tree, like HSDHSCH-Information-FDD */ + switch(protocol_ie_id){ + /*This flow must also be added*/ + case id_HSDSCH_MACdFlows_to_Add: + if (!actx->pinfo->fd->flags.visited){ + /* Set port to zero use that as an indication of wether we have data or not */ + for (i = 0; i < maxNrOfMACdFlows; i++) { + nbap_hsdsch_channel_info[i].crnc_port = 0; + nbap_hsdsch_channel_info[i].rlc_mode = FP_RLC_MODE_UNKNOWN; + /*XXX: Added 29 jun*/ + nbap_hsdsch_channel_info[i].entity = entity_not_specified; /* Maybe this should default to entity = hs*/ + } + } %(DEFAULT_BODY)s - + add_hsdsch_bind(actx->pinfo,tree); + + break; + default: +%(DEFAULT_BODY)s + break; + } #.FN_BODY HSDSCH-MACdFlow-Specific-InfoItem + address dst_addr; transportLayerAddress_ipv4 = 0; BindingID_port = 0; num_items++; %(DEFAULT_BODY)s + if (actx->pinfo->fd->flags.visited||transportLayerAddress_ipv4==0||BindingID_port == 0) { return offset; } - dst_addr.type=AT_IPv4; dst_addr.len=4; dst_addr.data=(guint8 *)&transportLayerAddress_ipv4; @@ -1350,22 +1389,30 @@ guint32 no_ddi_entries, i; /* Set address for collection of HSDSCH entries */ COPY_ADDRESS(&(nbap_hsdsch_channel_info[hsdsch_macdflow_id].crnc_address),&dst_addr); nbap_hsdsch_channel_info[hsdsch_macdflow_id].crnc_port = BindingID_port; + + +#.FN_BODY MAC-PDU-SizeExtended + +%(DEFAULT_BODY)s + if(nbap_hsdsch_channel_info[hsdsch_macdflow_id].crnc_port != 0){ + nbap_hsdsch_channel_info[hsdsch_macdflow_id].entity = ehs; + } #.FN_BODY HSDSCH-MACdPDUSizeFormat /* - * Set the channel entity i.e the type of the hsdch channels (if this is present entity = ehs) + * Set the channel entity i.e the type of the hsdsch channels (if this is present entity = ehs) */ int i; %(DEFAULT_BODY)s - /* */ for (i = 0; i < maxNrOfMACdFlows; i++) { if (nbap_hsdsch_channel_info[i].crnc_port != 0){ nbap_hsdsch_channel_info[i].entity = ehs; - nbap_debug1("Setting entity = ehs for HSDSCH channel: %%d\n",i); } + } + #.FN_BODY HSDSCH-FDD-Information @@ -1392,6 +1439,7 @@ int i; if (actx->pinfo->fd->flags.visited){ return offset; } + /* Set port to zero use that as an indication of wether we have data or not */ SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); for (i = 0; i < maxNrOfMACdFlows; i++) { @@ -1404,7 +1452,7 @@ int i; PT_UDP, nbap_hsdsch_channel_info[i].crnc_port, 0, NO_ADDR_B); - + if (conversation == NULL) { /* It's not part of any conversation - create a new one. */ nbap_debug1("HSDSCH-MACdFlows-Information:Set up conv on Port %%u",nbap_hsdsch_channel_info[i].crnc_port); @@ -1414,7 +1462,7 @@ int i; /* Set dissector */ conversation_set_dissector(conversation, fp_handle); - + if(actx->pinfo->link_dir==P2P_DIR_DL){ umts_fp_conversation_info = se_new0(umts_fp_conversation_info_t); /* Fill in the HSDSCH relevant data */ @@ -1520,6 +1568,7 @@ int i; umts_fp_conversation_info = se_new0(umts_fp_conversation_info_t); umts_fp_conversation_info->channel = CHANNEL_HSDSCH_COMMON; + umts_fp_conversation_info->division = Division_FDD; set_umts_fp_conv_data(conversation, umts_fp_conversation_info); } @@ -1530,7 +1579,15 @@ int i; } } - +# +#Routines for figuring out a unique UE identification number (to track flows over changing channels) +# + +#.FN_BODY NodeB-CommunicationContextID VAL_PTR = &com_context_id +%(DEFAULT_BODY)s +#.FN_BODY CRNC-CommunicationContextID VAL_PTR = &com_context_id + +%(DEFAULT_BODY)s #.REGISTER_NEW diff --git a/asn1/nbap/packet-nbap-template.c b/asn1/nbap/packet-nbap-template.c index ead17f1468..53aea37aa7 100644 --- a/asn1/nbap/packet-nbap-template.c +++ b/asn1/nbap/packet-nbap-template.c @@ -35,6 +35,7 @@ #include <epan/sctpppids.h> #include <epan/asn1.h> #include <epan/conversation.h> +#include <epan/expert.h> #include "packet-per.h" #include "packet-isup.h" @@ -53,6 +54,9 @@ #define PSNAME "NBAP" #define PFNAME "nbap" + +#define NBAP_IGNORE_PORT 255 + /* Debug */ #if 0 #define nbap_debug0(str) g_warning(str) @@ -70,6 +74,7 @@ dissector_handle_t fp_handle; static guint32 transportLayerAddress_ipv4; static guint16 BindingID_port; +static guint32 com_context_id; #include "packet-nbap-val.h" @@ -211,6 +216,8 @@ static int dissect_InitiatingMessageValue(tvbuff_t *tvb, packet_info *pinfo, pro static int dissect_SuccessfulOutcomeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); static int dissect_UnsuccessfulOutcomeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +/*Easy way to add hsdhsch binds for corner cases*/ +static void add_hsdsch_bind(packet_info * pinfo, proto_tree * tree); #include "packet-nbap-fn.c" @@ -241,13 +248,74 @@ static int dissect_UnsuccessfulOutcomeValue(tvbuff_t *tvb, packet_info *pinfo, p if (!ProcedureID) return 0; return (dissector_try_string(nbap_proc_uout_dissector_table, ProcedureID, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; } +static void add_hsdsch_bind(packet_info *pinfo, proto_tree * tree){ + address null_addr; + conversation_t *conversation = NULL; + umts_fp_conversation_info_t *umts_fp_conversation_info; + guint32 i; + + if (pinfo->fd->flags.visited){ + return; + } + + /* Set port to zero use that as an indication of wether we have data or not */ + SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); + for (i = 0; i < maxNrOfMACdFlows; i++) { + if (nbap_hsdsch_channel_info[i].crnc_port != 0){ + conversation = find_conversation(pinfo->fd->num, &(nbap_hsdsch_channel_info[i].crnc_address), &null_addr, + PT_UDP, + nbap_hsdsch_channel_info[i].crnc_port, 0, NO_ADDR_B); + + + if (conversation == NULL) { + /* It's not part of any conversation - create a new one. */ + conversation = conversation_new(pinfo->fd->num, &(nbap_hsdsch_channel_info[i].crnc_address), + &null_addr, PT_UDP, nbap_hsdsch_channel_info[i].crnc_port, + 0, NO_ADDR2|NO_PORT2); + + /* Set dissector */ + conversation_set_dissector(conversation, fp_handle); + + if(pinfo->link_dir==P2P_DIR_DL){ + umts_fp_conversation_info = se_new0(umts_fp_conversation_info_t); + /* Fill in the HSDSCH relevant data */ + + umts_fp_conversation_info->iface_type = IuB_Interface; + umts_fp_conversation_info->division = Division_FDD; + umts_fp_conversation_info->channel = CHANNEL_HSDSCH; + umts_fp_conversation_info->dl_frame_number = 0; + umts_fp_conversation_info->ul_frame_number = pinfo->fd->num; + SE_COPY_ADDRESS(&(umts_fp_conversation_info->crnc_address), &nbap_hsdsch_channel_info[i].crnc_address); + umts_fp_conversation_info->crnc_port = nbap_hsdsch_channel_info[i].crnc_port; + + /*Added june 3, normally just the iterator variable*/ + umts_fp_conversation_info->hsdsch_macdflow_id = i ; /*hsdsch_macdflow_ids[i];*/ /* hsdsch_macdflow_id;*/ + + /* Cheat and use the DCH entries */ + umts_fp_conversation_info->num_dch_in_flow++; + umts_fp_conversation_info->dchs_in_flow_list[umts_fp_conversation_info->num_dch_in_flow -1] = i; + + /*XXX: Is this craziness, what is physical_layer? */ + if(nbap_hsdsch_channel_info[i].entity == entity_not_specified ){ + /*Error*/ + expert_add_info_format(pinfo, tree, PI_MALFORMED,PI_ERROR, "HSDSCH Entity not specified!"); + }else{ + umts_fp_conversation_info->hsdsch_entity = nbap_hsdsch_channel_info[i].entity; + } + umts_fp_conversation_info->rlc_mode = nbap_hsdsch_channel_info[i].rlc_mode; + set_umts_fp_conv_data(conversation, umts_fp_conversation_info); + } + } + } + } +} static void dissect_nbap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *nbap_item = NULL; proto_tree *nbap_tree = NULL; - + int i; /* make entry in the Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBAP"); @@ -255,6 +323,11 @@ dissect_nbap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) nbap_item = proto_tree_add_item(tree, proto_nbap, tvb, 0, -1, ENC_NA); nbap_tree = proto_item_add_subtree(nbap_item, ett_nbap); + /*Do a little cleanup just as a precaution*/ + for (i = 0; i < maxNrOfMACdFlows; i++) { + nbap_hsdsch_channel_info[i].entity = hs; + } + dissect_NBAP_PDU_PDU(tvb, pinfo, nbap_tree); } diff --git a/asn1/rrc/packet-rrc-template.c b/asn1/rrc/packet-rrc-template.c index def3d07e97..8dcf26724c 100644 --- a/asn1/rrc/packet-rrc-template.c +++ b/asn1/rrc/packet-rrc-template.c @@ -68,7 +68,7 @@ enum nas_sys_info_gsm_map { RRC_NAS_SYS_INFO_CN_COMMON }; -static guint32 rrc_nas_sys_info_gsm_map_type = RRC_NAS_SYS_INFO_CN_COMMON; +static enum nas_sys_info_gsm_map rrc_nas_sys_info_gsm_map_type = RRC_NAS_SYS_INFO_CN_COMMON; /* Forward declarations */ static int dissect_UE_RadioAccessCapabilityInfo_PDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); diff --git a/asn1/rrc/rrc.cnf b/asn1/rrc/rrc.cnf index 4ab1f1111a..96f6593482 100644 --- a/asn1/rrc/rrc.cnf +++ b/asn1/rrc/rrc.cnf @@ -606,7 +606,7 @@ HNBName TYPE=FT_STRING DISPLAY=BASE_NONE proto_tree_add_unicode_string(tree, hf_index, hnbname_tvb, 0, -1, tvb_get_ephemeral_string_enc(hnbname_tvb, 0, tvb_length(hnbname_tvb), ENC_UTF_8 | ENC_NA)); -#.FN_BODY CN-DomainIdentity VAL_PTR = &rrc_nas_sys_info_gsm_map_type +#.FN_BODY CN-DomainIdentity VAL_PTR = (guint32*)(&rrc_nas_sys_info_gsm_map_type) %(DEFAULT_BODY)s #.FN_BODY CN-InformationInfo/cn-CommonGSM-MAP-NAS-SysInfo diff --git a/epan/dissectors/packet-rlc.c b/epan/dissectors/packet-rlc.c index aef946430e..b77d70a81c 100644 --- a/epan/dissectors/packet-rlc.c +++ b/epan/dissectors/packet-rlc.c @@ -41,9 +41,8 @@ #include "packet-rrc.h" /* TODO: - * - AM SEQ wrap case - * - UM/AM 'real' reordering (final packet must appear in-order right now) - * - use sub_num in fragment identification? + * - distinguish between startpoints and endpoints? + * - use sub_num in fragment identification? */ #define DEBUG_FRAME(number, msg) {if (pinfo->fd->num == number) printf("%u: %s\n", number, msg);} @@ -62,6 +61,9 @@ static gboolean global_rlc_headers_expected = FALSE; /* Heuristic dissection */ static gboolean global_rlc_heur = 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; @@ -126,7 +128,6 @@ static const true_false_string rlc_header_only_val = { "RLC PDU header only", "RLC PDU header and body present" }; - static const true_false_string rlc_ext_val = { "Next field is Length Indicator and E Bit", "Next field is data, piggybacked STATUS PDU or padding" }; @@ -179,9 +180,11 @@ static const value_string rlc_sufi_vals[] = { }; /* reassembly related data */ -static GHashTable *fragment_table = NULL; /* maps rlc_channel -> fragmented sdu */ +static GHashTable *fragment_table = NULL; /* table of not yet assembled fragments */ +static GHashTable *endpoints = NULL; /* List of SDU-endpoints */ static GHashTable *reassembled_table = NULL; /* maps fragment -> complete sdu */ static GHashTable *sequence_table = NULL; /* channel -> seq */ +static GHashTable *duplicate_table = NULL; /* duplicates */ /* identify an RLC channel, using one of two options: * - via Radio Bearer ID and U-RNTI @@ -293,7 +296,7 @@ rlc_channel_assign(struct rlc_channel *ch, enum rlc_mode mode, packet_info *pinf ch->urnti = rlcinf->urnti[fpinf->cur_tb]; ch->vpi = ch->vci = ch->link = ch->cid = 0; } else { - ch->urnti = 0; + ch->urnti = 1; ch->vpi = atm->vpi; ch->vci = atm->vci; ch->cid = atm->aal2_cid; @@ -337,7 +340,7 @@ static guint rlc_frag_hash(gconstpointer key) { const struct rlc_frag *frag = key; - return rlc_channel_hash(&frag->ch) | frag->li | frag->seq; + return (frag->frame_num << 12) | frag->seq; } static gboolean @@ -351,7 +354,6 @@ rlc_frag_equal(gconstpointer a, gconstpointer b) x->li == y->li ? TRUE : FALSE; } - static struct rlc_sdu * rlc_sdu_create(void) { @@ -435,6 +437,21 @@ rlc_cmp_seq(gconstpointer a, gconstpointer b) 0; } +static int special_cmp(gconstpointer a, gconstpointer b) +{ + const gint16 p = GPOINTER_TO_INT(a), q = GPOINTER_TO_INT(b); + if (ABS(p-q) < 2048) { + return (p < q)? -1 : (p > q)? 1 : 0; + } else { + if (p+2048 < q) { + return 1; + } else { + return -1; + } + } + return (p < q)? -1 : (p > q)? 1 : 0; +} + /* callback function to use for g_hash_table_foreach_remove() * always return TRUE (=always delete the entry) * this is required for backwards compatibility @@ -467,9 +484,11 @@ static void fragment_table_init(void) { if (fragment_table) { - g_hash_table_foreach_remove(fragment_table, free_table_entry, NULL); g_hash_table_destroy(fragment_table); } + if (endpoints) { + g_hash_table_destroy(endpoints); + } if (reassembled_table) { g_hash_table_foreach_remove(reassembled_table, free_table_entry, NULL); g_hash_table_destroy(reassembled_table); @@ -479,12 +498,17 @@ fragment_table_init(void) g_hash_table_foreach_remove(sequence_table, free_table_entry, NULL); g_hash_table_destroy(sequence_table); } - fragment_table = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, - rlc_channel_delete, rlc_sdu_frags_delete); + if (duplicate_table) { + g_hash_table_destroy(duplicate_table); + } + fragment_table = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, rlc_channel_delete, NULL); + endpoints = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, rlc_channel_delete, NULL); reassembled_table = g_hash_table_new_full(rlc_frag_hash, rlc_frag_equal, rlc_frag_delete, rlc_sdu_frags_delete); sequence_table = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, NULL, free_sequence_table_entry_data); + duplicate_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); + fail = FALSE; /* Reset fail flag. */ } /* add the list of fragments for this sdu to 'tree' */ @@ -690,16 +714,33 @@ 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 (frag->seq < tmp->seq) { - /* insert as first element */ - frag->next = tmp; - sdu->frags = frag; - } else { - while (tmp->next && tmp->next->seq < frag->seq) + + /* 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) tmp = tmp->next; - frag->next = tmp->next; - tmp->next = frag; - if (frag->next == NULL) sdu->last = frag; + if (tmp->next == NULL) { + tmp->next = frag; + sdu->last = frag; + } else { + while (tmp->next && tmp->next->seq < frag->seq) + tmp = tmp->next; + frag->next = tmp->next; + tmp->next = frag; + if (frag->next == NULL) sdu->last = frag; + } + } else { /* Receiving ordinary sequence */ + if (frag->seq < tmp->seq) { + /* insert as first element */ + frag->next = tmp; + sdu->frags = frag; + } else { + while (tmp->next && tmp->next->seq < frag->seq) + tmp = tmp->next; + frag->next = tmp->next; + tmp->next = frag; + if (frag->next == NULL) sdu->last = frag; + } } sdu->len += frag->len; break; @@ -724,21 +765,35 @@ 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; } - g_hash_table_remove(fragment_table, ch); } +#define RLC_ADD_FRAGMENT_DEBUG_PRINT 0 +#if RLC_ADD_FRAGMENT_DEBUG_PRINT +static void printends(GList * list) +{ + if (list == NULL) + return; + g_print("-> length: %d\n[", g_list_length(list)); + while (list) + { + g_print("%d ", GPOINTER_TO_INT(list->data)); + list = list->next; + } + g_print("]\n"); +} +#endif + /* add a new fragment to an SDU * if length == 0, just finalize the specified SDU */ @@ -748,19 +803,23 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo, guint16 len, gboolean final) { struct rlc_channel ch_lookup; - struct rlc_frag frag_lookup, *frag = NULL, *tmp; - gpointer orig_frag, orig_sdu; - struct rlc_sdu *sdu; + struct rlc_frag frag_lookup, *frag = NULL; + gpointer orig_key = NULL, value = NULL; + struct rlc_sdu *sdu = NULL; + struct rlc_frag ** frags = NULL; + struct rlc_seqlist * endlist = NULL; + GList * element = NULL; rlc_channel_assign(&ch_lookup, mode, pinfo); rlc_frag_assign(&frag_lookup, mode, pinfo, seq, num_li); - + #if RLC_ADD_FRAGMENT_DEBUG_PRINT + g_print("paket: %d, kanal (%d %d %d %d %d %d %d %d %d) seq: %u, num_li: %u, offset: %u, \n", pinfo->fd->num, ch_lookup.cid, ch_lookup.dir, ch_lookup.li_size, ch_lookup.link, ch_lookup.mode, ch_lookup.rbid, ch_lookup.urnti, ch_lookup.vci, ch_lookup.vpi, seq, num_li, offset); + #endif /* look for an already assembled SDU */ - if (g_hash_table_lookup_extended(reassembled_table, &frag_lookup, - &orig_frag, &orig_sdu)) { + if (g_hash_table_lookup_extended(reassembled_table, &frag_lookup, &orig_key, &value)) { /* this fragment is already reassembled somewhere */ - frag = orig_frag; - sdu = orig_sdu; + frag = orig_key; + sdu = value; if (tree) { /* mark the fragment, if reassembly happened somewhere else */ if (frag->seq != sdu->reassembled_in->seq || @@ -771,39 +830,178 @@ add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo, return frag; } - /* if not already reassembled, search for a fragment entry */ - sdu = g_hash_table_lookup(fragment_table, &ch_lookup); - - if (final && len == 0) { - /* just finish this SDU */ - if (sdu) { - frag = rlc_frag_create(tvb, mode, pinfo, offset, len, seq, num_li); - rlc_sdu_add_fragment(mode, sdu, frag); - reassemble_message(&ch_lookup, sdu, frag); - } - return NULL; + /* 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); } - /* create the SDU entry, if it does not already exist */ - if (!sdu) { - /* this the first observed fragment of an SDU */ + + /* 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); - sdu = rlc_sdu_create(); - g_hash_table_insert(fragment_table, ch, sdu); + if (ch == NULL) { /* DEBUG */ + g_print("failed to assign channel\n"); + exit(0); + } + + endlist->list = NULL; + endlist->list = g_list_prepend(endlist->list, GINT_TO_POINTER(-1)); + g_hash_table_insert(endpoints, ch, endlist); } - /* check whether we have seen this fragment already */ - tmp = sdu->frags; - while (tmp) { - if (rlc_frag_equal(&frag_lookup, tmp) == TRUE) - return tmp; - tmp = tmp->next; + /* If already done reassembly */ + if (pinfo->fd->flags.visited) { + if (tree) { + if (endlist->list && endlist->list->next) { + 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++) + { + if (frags[missing] == NULL) { + 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); + } else { + g_warning("Unfinished sequence (%u->%u [could not determine packet]) could not find %u.", start, end, missing); + } + } else if (endlist->list) { + /*gint16 end = *((gint16*)endlist->list->data); + g_warning("Gave up at seq %d", end);*/ + } + } + 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); - rlc_sdu_add_fragment(mode, sdu, frag); + + /* 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. */ + if (frags[seq] != NULL) { + if (num_li > 0) { + struct rlc_frag * tempfrag = frags[seq]; + while (tempfrag->next != NULL) + 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); + } + 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) { + endlist->list->data = GINT_TO_POINTER(first-1); + } + } + + /* If this is an endpoint */ if (final) { - reassemble_message(&ch_lookup, sdu, frag); + 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; + gint16 end = GPOINTER_TO_INT(endlist->list->next->data); + if (frags[end] == NULL) { + g_warning("frag[end] is null, this is probably because end was a startpoint but because of some error ended up being treated as an endpoint, setting fail flag, start %d, end %d, packet %u\n", start, end, pinfo->fd->num); + fail = TRUE; + 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); + 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_message(&ch_lookup, sdu, NULL); } + return frag; } @@ -879,6 +1077,17 @@ rlc_is_duplicate(enum rlc_mode mode, packet_info *pinfo, guint16 seq, seq_item.seq = seq; seq_item.frame_num = pinfo->fd->num; + /* seq is 12 bit (in RLC protocol) so it will wrap around after 4096. */ + /* Window size is at most 4095 so we remove packets further away than that */ + element = g_list_first(list->list); + if (element) { + seq_new = element->data; + /* Add 4096 because %-operation for negative values in C is not equal to mathematical modulus */ + if (MIN((seq_new->seq-seq+4096)%4096, (seq-seq_new->seq+4096)%4096) >= 1028) { + list->list = g_list_remove_link(list->list, element); + } + } + element = g_list_find_custom(list->list, &seq_item, rlc_cmp_seq); if (element) { seq_new = element->data; @@ -897,7 +1106,7 @@ rlc_is_duplicate(enum rlc_mode mode, packet_info *pinfo, guint16 seq, seq_new = se_alloc0(sizeof(struct rlc_seq)); *seq_new = seq_item; seq_new->arrival = pinfo->fd->abs_ts; - list->list = g_list_insert_sorted(list->list, seq_new, rlc_cmp_seq); + list->list = g_list_append(list->list, seq_new); /* insert in order of arrival */ return FALSE; } @@ -931,6 +1140,8 @@ rlc_call_subdissector(enum rlc_channel_type channel, tvbuff_t *tvb, msgtype = RRC_MESSAGE_TYPE_INVALID; /* assume transparent PDCP for now */ call_dissector(ip_handle, tvb, pinfo, tree); + /* once the packet has been dissected, protect it from further changes */ + col_set_writable(pinfo->cinfo, FALSE); break; default: return; /* abort */ @@ -1031,10 +1242,10 @@ rlc_um_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo, proto_tree *tr } } if (dissected == FALSE) - col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Fragment] SN=%u", seq); + col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Fragment] SN=%u", seq); else if (channel == RLC_UNKNOWN_CH) - col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Data] SN=%u", seq); + col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Data] SN=%u", seq); } static gint16 @@ -1537,7 +1748,7 @@ rlc_am_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo, } if (global_rlc_perform_reassemby) { add_fragment(RLC_AM, tvb, pinfo, li[i].tree, offs, seq, i, li[i].len, TRUE); - next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, li[i].tree, seq, i); + next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, tree, seq, i); } } if (next_tvb) { @@ -1560,7 +1771,7 @@ rlc_am_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo, add_fragment(RLC_AM, tvb, pinfo, tree, offs, seq, i, tvb_length_remaining(tvb,offs), final); if (final) { - next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, NULL, seq, i); + next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, tree, seq, i); } } } @@ -1571,11 +1782,11 @@ rlc_am_reassemble(tvbuff_t *tvb, guint8 offs, packet_info *pinfo, } } if (dissected == FALSE) - col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] SN=%u %s", + col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] SN=%u %s", seq, poll_set ? "(P)" : ""); else if (channel == RLC_UNKNOWN_CH) - col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Data] SN=%u %s", + col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Data] SN=%u %s", seq, poll_set ? "(P)" : ""); } @@ -1609,7 +1820,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); @@ -1626,7 +1837,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) { @@ -1641,7 +1852,6 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo, col_append_str(pinfo->cinfo, COL_INFO, "[Ciphered Data]"); return; } - if (rlcinf->li_size[pos] == RLC_LI_VARIABLE) { li_is_on_2_bytes = (tvb_length(tvb) > 126) ? TRUE : FALSE; } else { @@ -1651,7 +1861,6 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo, num_li = rlc_decode_li(RLC_AM, tvb, pinfo, tree, li, MAX_LI, li_is_on_2_bytes); if (num_li == -1) return; /* something went wrong */ offs += ((li_is_on_2_bytes) ? 2 : 1) * num_li; - if (global_rlc_headers_expected) { /* There might not be any data, if only header was logged */ is_truncated = (tvb_length_remaining(tvb, offs) == 0); @@ -1669,13 +1878,19 @@ dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo, /* do not detect duplicates or reassemble, if prefiltering is done */ if (pinfo->fd->num == 0) return; - /* check for duplicates */ - if (rlc_is_duplicate(RLC_AM, pinfo, seq, &orig_num) == TRUE) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] [Duplicate] SN=%u %s", - seq, (polling != 0) ? "(P)" : ""); - proto_tree_add_uint(tree, hf_rlc_duplicate_of, tvb, 0, 0, orig_num); + /* check for duplicates, but not if already visited */ + if (pinfo->fd->flags.visited == FALSE && rlc_is_duplicate(RLC_AM, pinfo, seq, &orig_num) == TRUE) { + g_hash_table_insert(duplicate_table, GUINT_TO_POINTER(pinfo->fd->num), GUINT_TO_POINTER(orig_num)); return; + } else if (pinfo->fd->flags.visited == TRUE && tree) { + gpointer value = g_hash_table_lookup(duplicate_table, GUINT_TO_POINTER(pinfo->fd->num)); + if (value != NULL) { + col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] [Duplicate] SN=%u %s", seq, (polling != 0) ? "(P)" : ""); + proto_tree_add_uint(tree, hf_rlc_duplicate_of, tvb, 0, 0, GPOINTER_TO_UINT(value)); + return; + } } + rlc_am_reassemble(tvb, offs, pinfo, tree, top_level, channel, seq, polling != 0, li, num_li, ext == 2, li_is_on_2_bytes); } diff --git a/epan/dissectors/packet-umts_fp.c b/epan/dissectors/packet-umts_fp.c index 7bb574b15e..264084a4e5 100644 --- a/epan/dissectors/packet-umts_fp.c +++ b/epan/dissectors/packet-umts_fp.c @@ -2992,9 +2992,13 @@ dissect_hsdsch_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, } macinf->fake_chid[i] = TRUE; /**/ macinf->macdflow_id[i] = p_fp_info->hsdsch_macflowd_id; /*Save the flow ID (+1 to make it human readable (its zero indexed!))*/ - /*Figure out RLC_MODE based on MACd-flow-ID, basically MACd-flow-ID = 0 then its SRB0 == UM else AM*/ - rlcinf->mode[i] = hsdsch_macdflow_id_rlc_map[p_fp_info->hsdsch_macflowd_id]; - /*macinf->ctmux[i] = TRUE;*/ + /*Figure out RLC_MODE based on MACd-flow-ID, basically MACd-flow-ID = 0 then its SRB0 == UM else AM*/ + if(p_fp_info->hsdsch_macflowd_id > 15 || i > 64){ + g_warning("paket nr: %d id:%d i:%d", pinfo->fd->num,p_fp_info->hsdsch_macflowd_id,i); + /*exit(0);*/ + } + rlcinf->mode[i] = hsdsch_macdflow_id_rlc_map[p_fp_info->hsdsch_macflowd_id]; + /*macinf->ctmux[i] = TRUE;*/ rlcinf->urnti[i] = p_fp_info->channel; rlcinf->li_size[i] = RLC_LI_7BITS; rlcinf->ciphered[i] = FALSE; @@ -3673,23 +3677,26 @@ dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* Look for packet info! */ p_fp_info = (struct fp_info *)p_get_proto_data(pinfo->fd, proto_fp); - /* Check if we have converstaion info */ + /* Check if we have conversation info */ 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){ + p_conv = p_conv->next; + } p_conv_data = (umts_fp_conversation_info_t *)conversation_get_proto_data(p_conv, proto_fp); - if (p_conv_data) { - + + if (p_conv_data) { /*Figure out the direction of the link*/ if (ADDRESSES_EQUAL(&(pinfo->net_dst), (&p_conv_data->crnc_address))) { - - + proto_item* item= proto_tree_add_uint(fp_tree, hf_fp_ul_setup_frame, tvb, 0, 0, p_conv_data->ul_frame_number); - + PROTO_ITEM_SET_GENERATED(item); /* CRNC -> Node B */ pinfo->link_dir=P2P_DIR_UL; diff --git a/epan/dissectors/packet-umts_fp.h b/epan/dissectors/packet-umts_fp.h index 427a74c613..d1e59ac4db 100644 --- a/epan/dissectors/packet-umts_fp.h +++ b/epan/dissectors/packet-umts_fp.h @@ -22,6 +22,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include <glib.h> + /* Channel types */ #define CHANNEL_RACH_FDD 1 #define CHANNEL_RACH_TDD 2 @@ -165,6 +168,7 @@ typedef struct /* HSDSCH Related data */ enum fp_hsdsch_entity hsdsch_entity; guint8 hsdsch_macdflow_id; + GSequence * ports; } umts_fp_conversation_info_t; void set_umts_fp_conv_data(conversation_t *conversation, umts_fp_conversation_info_t *umts_fp_conversation_info); |