From a75a21fb31207ec724554363e2251b935380cd17 Mon Sep 17 00:00:00 2001 From: "S. Shapira" Date: Tue, 7 Mar 2017 23:23:52 +0200 Subject: [PATCH] Added Heuristic dissectors for the following UMTS FP channels: DCH (Downlink and Uplink), FACH, RACH and PCH Note that the existing heuristic dissection function does not correctly dissect any of the above and, frankly, I'm not sure which cases it covers. Change-Id: I832bfdccc9ae760a42a4c6537052ee2fee9262b4 Reviewed-on: https://code.wireshark.org/review/20439 Petri-Dish: Michael Mann Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- AUTHORS.src | 4 + epan/dissectors/packet-umts_fp.c | 679 ++++++++++++++++++++++++++++++- epan/dissectors/packet-umts_fp.h | 3 +- 3 files changed, 667 insertions(+), 19 deletions(-) diff --git a/AUTHORS.src b/AUTHORS.src index 076fce214d..c9dfea721f 100644 --- a/AUTHORS.src +++ b/AUTHORS.src @@ -3699,6 +3699,10 @@ Kim Kempf { 802.1BR E-Tag dissector } +S. Shapira { + UMTS FP heuristic dissectors +} + and by: Georgi Guninski diff --git a/epan/dissectors/packet-umts_fp.c b/epan/dissectors/packet-umts_fp.c index e384ebcac2..f1e024018a 100644 --- a/epan/dissectors/packet-umts_fp.c +++ b/epan/dissectors/packet-umts_fp.c @@ -480,30 +480,30 @@ static const value_string common_control_frame_type_vals[] = { /* 0 to 7*/ static const guint8 hsdsch_macdflow_id_rlc_map[] = { - RLC_UM, /*0 SRB */ - RLC_AM, /*1 Interactive PS*/ - RLC_AM, /*2 Interatcive PS*/ - RLC_UNKNOWN_MODE, /*3 ???*/ - RLC_AM, /*4 Streaming PS*/ - RLC_UNKNOWN_MODE, - RLC_UNKNOWN_MODE, - RLC_UNKNOWN_MODE + RLC_UM, /*0 SRB */ + RLC_AM, /*1 Interactive PS*/ + RLC_AM, /*2 Interatcive PS*/ + RLC_UNKNOWN_MODE, /*3 ???*/ + RLC_AM, /*4 Streaming PS*/ + RLC_UNKNOWN_MODE, + RLC_UNKNOWN_MODE, + RLC_UNKNOWN_MODE }; /* Mapping hsdsch MACd-FlowId to MAC_CONTENT, basically flowid = 1 (0) => SRB*/ /* 1 to 8*/ static const guint8 hsdsch_macdflow_id_mac_content_map[] = { - MAC_CONTENT_DCCH, /*1 SRB */ - MAC_CONTENT_PS_DTCH, /*2 Interactive PS*/ - MAC_CONTENT_PS_DTCH, /*3 Interatcive PS*/ - RLC_UNKNOWN_MODE, /*4 ???*/ - MAC_CONTENT_PS_DTCH, /*5 Streaming PS*/ - RLC_UNKNOWN_MODE, - RLC_UNKNOWN_MODE, - RLC_UNKNOWN_MODE - }; + MAC_CONTENT_DCCH, /*1 SRB */ + MAC_CONTENT_PS_DTCH, /*2 Interactive PS*/ + MAC_CONTENT_PS_DTCH, /*3 Interatcive PS*/ + RLC_UNKNOWN_MODE, /*4 ???*/ + MAC_CONTENT_PS_DTCH, /*5 Streaming PS*/ + RLC_UNKNOWN_MODE, + RLC_UNKNOWN_MODE, + RLC_UNKNOWN_MODE +}; -/* Make fake logical channel id's based on MACdFlow-ID's, +/* Make fake logical channel id's based on MACdFlow-ID's, * XXXX Bug 12121 expanded the number of entries to 8(+2), * not at all sure what the proper value should be 0xfF? */ @@ -3828,6 +3828,645 @@ void dissect_hsdsch_common_channel_info(tvbuff_t *tvb, packet_info *pinfo, proto dissect_spare_extension_and_crc(tvb, pinfo, tree, 1, offset, header_length); } } +/* Validates the header CRC in a Control FP frame */ +/* Should only be used in heuristic dissectors! */ +static gboolean +check_control_frame_crc_for_heur(tvbuff_t * tvb) +{ + guint8 crc = 0; + guint8 calc_crc = 0; + guint8 * data = NULL; + + crc = tvb_get_guint8(tvb, 0) >> 1; + /* Get data. */ + data = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_reported_length(tvb)); + /* Include only FT flag bit in CRC calculation. */ + data[0] = data[0] & 1; + calc_crc = crc7update(0, data, tvb_reported_length(tvb)); + calc_crc = crc7finalize(calc_crc); + + return calc_crc == crc; +} +/* Validates the header CRC in a Data FP frame */ +/* Should only be used in heuristic dissectors! */ +static gboolean +check_header_crc_for_heur(tvbuff_t *tvb, guint16 header_length) +{ + guint8 crc = 0; + guint8 calc_crc = 0; + guint8 * data = NULL; + + crc = tvb_get_guint8(tvb, 0) >> 1; + /* Get data of header excluding the first byte */ + data = (guint8 *)tvb_get_ptr(tvb, 1, header_length - 1); + + calc_crc = crc7update(0, data, header_length - 1); + calc_crc = crc7finalize(calc_crc); + + return calc_crc == crc; +} +/* Validates the payload CRC in a Data FP frame */ +/* Should only be used in heuristic dissectors! */ +static gboolean +check_payload_crc_for_heur(tvbuff_t *tvb, guint16 header_length) +{ + guint16 frame_length; + guint16 crc_index; + guint16 crc = 0; + guint16 calc_crc = 0; + guint16 payload_index; + guint16 payload_length; + guint8 *data = NULL; + + frame_length = tvb_reported_length(tvb); + if (frame_length < 2) { + return FALSE; + } + /* Payload CRC is in the last 2 bytes of the packet */ + crc_index = frame_length - 2; + crc = tvb_get_bits16(tvb, crc_index * 8, 16, ENC_BIG_ENDIAN); + + payload_index = header_length; /* payload first index is the same as the header length */ + payload_length = (frame_length - payload_index) - 2; + data = (guint8 *)tvb_get_ptr(tvb, payload_index, payload_length); + calc_crc = crc16_8005_noreflect_noxor(data, payload_length); + + return calc_crc == crc; +} +/* Generates a unique 32bit identifier based on the frame's meta data */ +/* This ID is used in the RLC dissector for reassembly */ +/* Should only be used in heuristic dissectors! */ +static guint32 +generate_ue_id_for_heur(packet_info *pinfo) +{ + if (pinfo->ptype != PT_UDP && pinfo->src.type == AT_IPv4 && pinfo->dst.type == AT_IPv4) { + /* This logic assumes FP is delivered over IP/UDP*/ + /* Will return the same ID even if the address and ports are reversed */ + + /* srcXor: [ ------- Source Address ------- ] (4 bytes)*/ + /* XOR */ + /* [ Source Port ][ Source Port ] (4 bytes)*/ + int srcXor = *((guint32*)pinfo->src.data) ^ ((pinfo->srcport << 16) | (pinfo->srcport)); + + /* dstXor: [ ---- Destination Address ---- ] (4 bytes)*/ + /* XOR */ + /* [ - Dest Port - ][ - Dest Port - ] (4 bytes)*/ + int dstXor = *((guint32*)pinfo->dst.data) ^ ((pinfo->destport << 16) | (pinfo->destport)); + return srcXor ^ dstXor; + } + else { + /* Fallback - When IP and/or UDP are missing for whatever reason */ + /* Using the frame number of the first heuristicly dissected frame as the UE ID should be unique enough */ + /* The bitwise NOT operator is used to prevent low UE ID values which are likely to collide with legitimate UE IDs derived from C-RNTIs in FACH/RACH */ + return ~(pinfo->num); + } +} +/* +* Attaches conversation info to both the downlink and uplink 'conversations' (streams) +* (Required since only one of them is checked in every dissected FP packet) +*/ +static void +fill_pch_coversation_info_for_heur(umts_fp_conversation_info_t* umts_fp_conversation_info ,packet_info *pinfo) +{ + umts_fp_conversation_info->iface_type = IuB_Interface; + umts_fp_conversation_info->division = Division_FDD; + umts_fp_conversation_info->dl_frame_number = pinfo->num; + umts_fp_conversation_info->ul_frame_number = pinfo->num; + umts_fp_conversation_info->dch_crc_present = 1; + umts_fp_conversation_info->com_context_id = generate_ue_id_for_heur(pinfo); + umts_fp_conversation_info->rlc_mode = FP_RLC_AM; + copy_address_wmem(wmem_file_scope(), &(umts_fp_conversation_info->crnc_address), &pinfo->src); + umts_fp_conversation_info->crnc_port = pinfo->srcport; + umts_fp_conversation_info->channel = CHANNEL_PCH; + umts_fp_conversation_info->num_dch_in_flow = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].num_dl_chans = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_num_tbs[1] = 1; +} +static void +set_both_sides_umts_fp_conv_data(packet_info *pinfo, umts_fp_conversation_info_t *umts_fp_conversation_info) +{ + conversation_t *packet_direction_conv; + conversation_t *other_direction_conv; + + if (pinfo == NULL) { + return; + } + + /* Finding or creating conversation for the way the packet is heading */ + packet_direction_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + + if (packet_direction_conv == NULL) { + /* Conversation does not exist yet, creating one now. */ + packet_direction_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + conversation_add_proto_data(packet_direction_conv, proto_fp, umts_fp_conversation_info); + + /* Finding or creating conversation for the other side */ + other_direction_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_src, &pinfo->net_dst, + pinfo->ptype, + pinfo->srcport, pinfo->destport, NO_ADDR_B); + + if (other_direction_conv == NULL) { + /* Conversation does not exist yet, creating one now. */ + other_direction_conv = conversation_new(pinfo->num, &pinfo->net_src, &pinfo->net_dst, + pinfo->ptype, + pinfo->srcport, pinfo->destport, NO_ADDR_B); + } + conversation_add_proto_data(other_direction_conv, proto_fp, umts_fp_conversation_info); + +} +static gboolean +heur_dissect_fp_dcch_over_dch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + conversation_t *p_conv; + umts_fp_conversation_info_t* umts_fp_conversation_info; + struct fp_info *p_fp_info; + int length; + guint8 frame_type; + guint8 tfi; + + /* Trying to find existing conversation */ + p_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + + if (p_conv != NULL) { + /* Checking if the conversation was already framed */ + umts_fp_conversation_info = (umts_fp_conversation_info_t *)conversation_get_proto_data(p_conv, proto_fp); + if (umts_fp_conversation_info) { + if (umts_fp_conversation_info->channel == CHANNEL_DCH) { + conversation_set_dissector(p_conv, fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; + } + else { + return FALSE; + } + } + } + + /* Making sure FP info isn't already attached */ + p_fp_info = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0); + if (p_fp_info) { + return FALSE; + } + + frame_type = tvb_get_guint8(tvb, 0) & 0x01; + if (frame_type == 1) { /* is 'control' frame type*/ + /* Asserting that the Header CRC is correct */ + if (!check_control_frame_crc_for_heur(tvb)) { + return FALSE; + } + /* All checks passed - This is an unknown FP frame. */ + /* To allow dissection of this frame after umts_fp_conversation_info will be added in a later frame */ + /* the conversation must be created here if it doesn't exist yet*/ + if (p_conv == NULL) { + p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + return FALSE; + } + + length = tvb_reported_length(tvb); + tfi = tvb_get_guint8(tvb, 2) & 0x1f; + + /* Checking if this is a DCH frame with 0 TBs*/ + if (tfi == 0x00) + { + if (length != 5 /* DL */ && length != 7 /* UL */) { + return FALSE; + } + if (!check_header_crc_for_heur(tvb, 3)) { + return FALSE; + } + if (!check_payload_crc_for_heur(tvb, 3)) { + return FALSE; + } + /* All checks passed - This is an unknown DCH FP frame. */ + /* To allow dissection of this frame after umts_fp_conversation_info will be added in a later frame */ + /* the conversation must be created here if it doesn't exist yet*/ + if (p_conv == NULL) { + p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + return FALSE; + } + + /* Checking this is a DCH frame with 1 TB */ + if (tfi != 0x01) { + return FALSE; + } + + /* Expecting specific lengths: 24 for downlink frames, 26 for uplink frames */ + length = tvb_reported_length(tvb); + if (length != 24 /* DL */ && length != 26 /* UL */) { + return FALSE; + } + + if (!check_header_crc_for_heur(tvb, 3)) { + return FALSE; + } + if (!check_payload_crc_for_heur(tvb, 3)) { + return FALSE; + } + + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + umts_fp_conversation_info->iface_type = IuB_Interface; + umts_fp_conversation_info->division = Division_FDD; + umts_fp_conversation_info->dl_frame_number = pinfo->num; + umts_fp_conversation_info->ul_frame_number = pinfo->num; + umts_fp_conversation_info->dch_crc_present = 1; + umts_fp_conversation_info->com_context_id = generate_ue_id_for_heur(pinfo); + umts_fp_conversation_info->rlc_mode = FP_RLC_AM; + if (length == 24 || length == 5) { /* Downlink */ + copy_address_wmem(wmem_file_scope(), &(umts_fp_conversation_info->crnc_address), &pinfo->src); + umts_fp_conversation_info->crnc_port = pinfo->srcport; + } + else { /* Uplink*/ + copy_address_wmem(wmem_file_scope(), &(umts_fp_conversation_info->crnc_address), &pinfo->dst); + umts_fp_conversation_info->crnc_port = pinfo->destport; + } + umts_fp_conversation_info->channel = CHANNEL_DCH; + umts_fp_conversation_info->num_dch_in_flow = 1; + umts_fp_conversation_info->dchs_in_flow_list[0] = 31; + umts_fp_conversation_info->fp_dch_channel_info[0].num_dl_chans = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_num_tbs[1] = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[1] = 148; + umts_fp_conversation_info->fp_dch_channel_info[0].num_ul_chans = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].ul_chan_num_tbs[1] = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].ul_chan_tf_size[1] = 148; + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + conversation_set_dissector(find_or_create_conversation(pinfo), fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; +} +static gboolean +heur_dissect_fp_fach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + conversation_t *p_conv; + umts_fp_conversation_info_t* umts_fp_conversation_info; + struct fp_info *p_fp_info; + int length; + guint8 frame_type; + guint8 tfi; + guint8 tctf; + + /* Finding or creating conversation */ + p_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + + if (p_conv != NULL) { + /* Checking if the conversation was already framed */ + umts_fp_conversation_info = (umts_fp_conversation_info_t *)conversation_get_proto_data(p_conv, proto_fp); + if (umts_fp_conversation_info) { + if (umts_fp_conversation_info->channel == CHANNEL_FACH_FDD) { + conversation_set_dissector(p_conv, fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; + } + else { + return FALSE; + } + } + } + + /* Expecting specific lengths: 27 for frames with 1 TB, 48 for frames with 2 TBs */ + length = tvb_reported_length(tvb); + if (length != 27 && length != 48) { + return FALSE; + } + + p_fp_info = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0); + + /* Making sure FP info isn't already attached */ + if (p_fp_info) { + return FALSE; + } + + frame_type = tvb_get_guint8(tvb, 0) & 0x01; + if (frame_type == 1) { /* is 'control' frame type*/ + /* We can't tell the FP type and content of control frames */ + return FALSE; + } + + tfi = tvb_get_guint8(tvb, 2) & 0x1f; + if (length == 27 && tfi != 0x01) { + return FALSE; + } + if (length == 48 && tfi != 0x02) { + return FALSE; + } + + tctf = tvb_get_guint8(tvb, 4); + /* Asserting the TCTF field contains a valid (non reserved) value according to TS 25.321 Table 9.2.1-2 */ + if (tctf != 0x40 && /* CCCH */ + tctf != 0x50 && /* MCCH */ + tctf != 0x5F && /* MSCH */ + tctf != 0x80 && /* CTCH */ + (tctf >> 4) != 0x06 && /* MTCH */ + (tctf >> 6) != 0x00 && /* BCCH */ + (tctf >> 6) != 0x03) { /* DCCH or DTCH over FACH */ + return FALSE; + } + + if (!check_header_crc_for_heur(tvb, 4)) { + return FALSE; + } + if (!check_payload_crc_for_heur(tvb, 4)) { + return FALSE; + } + + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + umts_fp_conversation_info->iface_type = IuB_Interface; + umts_fp_conversation_info->division = Division_FDD; + umts_fp_conversation_info->dl_frame_number = pinfo->num; + umts_fp_conversation_info->ul_frame_number = pinfo->num; + umts_fp_conversation_info->dch_crc_present = 1; + umts_fp_conversation_info->com_context_id = generate_ue_id_for_heur(pinfo); + umts_fp_conversation_info->rlc_mode = FP_RLC_AM; + copy_address_wmem(wmem_file_scope(), &(umts_fp_conversation_info->crnc_address), &pinfo->src); + umts_fp_conversation_info->crnc_port = pinfo->srcport; + umts_fp_conversation_info->channel = CHANNEL_FACH_FDD; + umts_fp_conversation_info->num_dch_in_flow = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].num_dl_chans = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_num_tbs[1] = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[1] = 168; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_num_tbs[2] = 2; + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[2] = 168; + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + conversation_set_dissector(find_or_create_conversation(pinfo), fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; +} +static gboolean +heur_dissect_fp_rach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + conversation_t *p_conv; + umts_fp_conversation_info_t* umts_fp_conversation_info; + struct fp_info *p_fp_info; + int length; + guint8 frame_type; + guint8 tfi; + guint8 tctf; + + /* Finding or creating conversation */ + p_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + + if (p_conv != NULL) { + /* Checking if the conversation was already framed */ + umts_fp_conversation_info = (umts_fp_conversation_info_t *)conversation_get_proto_data(p_conv, proto_fp); + if (umts_fp_conversation_info) { + if (umts_fp_conversation_info->channel == CHANNEL_RACH_FDD) { + conversation_set_dissector(p_conv, fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; + } + else { + return FALSE; + } + } + } + + /* Expecting specific lengths: all rach frames are 28 bytes long */ + length = tvb_reported_length(tvb); + if (length != 28) { + return FALSE; + } + + p_fp_info = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0); + + /* Making sure FP info isn't already attached */ + if (p_fp_info) { + return FALSE; + } + + frame_type = tvb_get_guint8(tvb, 0) & 0x01; + if (frame_type == 1) { /* is 'control' frame type*/ + /* We can't tell the FP type and content of control frames */ + return FALSE; + } + + tfi = tvb_get_guint8(tvb, 2) & 0x1f; + if (tfi != 0x00) { + return FALSE; + } + + tctf = tvb_get_guint8(tvb, 4) >> 6; + /* Asserting the TCTF field contains a valid (non reserved) value according to TS 25.321 Table 9.2.1-4 */ + if (tctf != 0x00 && /* CCCH */ + tctf != 0x01) /* DCCH over RACH */ + { + return FALSE; + } + + if (!check_header_crc_for_heur(tvb, 4)) { + return FALSE; + } + if (!check_payload_crc_for_heur(tvb, 4)) { + return FALSE; + } + + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + umts_fp_conversation_info->iface_type = IuB_Interface; + umts_fp_conversation_info->division = Division_FDD; + umts_fp_conversation_info->dl_frame_number = pinfo->num; + umts_fp_conversation_info->ul_frame_number = pinfo->num; + umts_fp_conversation_info->dch_crc_present = 1; + umts_fp_conversation_info->com_context_id = generate_ue_id_for_heur(pinfo); + umts_fp_conversation_info->rlc_mode = FP_RLC_AM; + copy_address_wmem(wmem_file_scope(), &(umts_fp_conversation_info->crnc_address), &pinfo->dst); + umts_fp_conversation_info->crnc_port = pinfo->destport; + umts_fp_conversation_info->channel = CHANNEL_RACH_FDD; + umts_fp_conversation_info->num_dch_in_flow = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].num_ul_chans = 0; + umts_fp_conversation_info->fp_dch_channel_info[0].ul_chan_num_tbs[0] = 1; + umts_fp_conversation_info->fp_dch_channel_info[0].ul_chan_tf_size[0] = 168; + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + conversation_set_dissector(find_or_create_conversation(pinfo), fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; +} +static gboolean +heur_dissect_fp_pch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + conversation_t *p_conv; + umts_fp_conversation_info_t* umts_fp_conversation_info = NULL; + struct fp_info *p_fp_info; + int length; + guint8 frame_type; + guint8 reserved_bits; + guint8 tfi; + guint8 pi_byte_length; + gboolean pi_present; + gboolean tb_size_found; + gboolean pi_length_found; + + /* To correctly dissect a PCH stream 2 parameters are required: PI Bitmap length & TB length */ + /* Unfortunately, both are optional in each packet and in some cases no packet will contain both */ + /* Hence gathering the info from 2 different frames is sometimes required. */ + + length = tvb_reported_length(tvb); + + /* Finding or creating conversation */ + p_conv = (conversation_t *)find_conversation(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + + if (p_conv != NULL) { + /* Checking if the conversation was already framed */ + umts_fp_conversation_info = (umts_fp_conversation_info_t *)conversation_get_proto_data(p_conv, proto_fp); + if (umts_fp_conversation_info) { + if (umts_fp_conversation_info->channel == CHANNEL_PCH) { + pi_length_found = umts_fp_conversation_info->paging_indications != 0; + tb_size_found = umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[1] != 0; + if (pi_length_found && tb_size_found) { + /* Stream already framed - contains both PI length and TB size */ + dissect_fp(tvb, pinfo, tree, data); + return TRUE; + } + } + else { + return FALSE; + } + } + else { + /* FP conversatio info not attached - no PCH info is known */ + tb_size_found = FALSE; + pi_length_found = FALSE; + } + } + else { + /* A conversatio does not exist yet - no PCH info is known */ + tb_size_found = FALSE; + pi_length_found = FALSE; + } + + p_fp_info = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0); + /* Making sure FP info isn't already attached */ + if (p_fp_info) { + return FALSE; + } + + frame_type = tvb_get_guint8(tvb, 0) & 0x01; + if (frame_type == 1) { /* is 'control' frame type*/ + /* We can't tell the FP type and content of control frames */ + return FALSE; + } + + /* Checking bits after CFN and before PI indicator are zeroed */ + reserved_bits = tvb_get_guint8(tvb, 2) & 0x0E; + if (reserved_bits != 0x00) { + return FALSE; + } + + tfi = tvb_get_guint8(tvb, 3) & 0x1f; + if (tfi != 0x00 && tfi != 0x01) { + return FALSE; + } + + if (!check_header_crc_for_heur(tvb, 4)) { + return FALSE; + } + if (!check_payload_crc_for_heur(tvb, 4)) { + return FALSE; + } + + pi_present = tvb_get_guint8(tvb, 2) & 0x01; /* Rightmost bit in the 3rd byte */ + if (pi_present) { + if (tfi == 0x00 && !pi_length_found) { + /* PI Bitmap present and No TB. Can calculate PI bitmap length */ + guint8 pi_bit_length; + pi_byte_length = length - 6; /* Removing header length (4) and footer length (2)*/ + switch (pi_byte_length) + { + case 3: /* 18 bits bitmap + padding */ + pi_bit_length = 18; + break; + case 5: /* 36 bits bitmap + padding */ + pi_bit_length = 36; + break; + case 9: /* 72 bits bitmap */ + pi_bit_length = 72; + break; + case 18: /* 144 bits bitmap */ + pi_bit_length = 144; + break; + default: + return FALSE; + } + if (p_conv == NULL) { + /* Conversation does not exist yet, creating one now. */ + p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + if (!umts_fp_conversation_info) { + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + fill_pch_coversation_info_for_heur(umts_fp_conversation_info, pinfo); + } + umts_fp_conversation_info->paging_indications = pi_bit_length; + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + pi_length_found = TRUE; + } + else if (tfi == 0x01 && !tb_size_found && pi_present) { + /* TB present and PI bitmap length is known. Can calculate TB length.*/ + pi_byte_length = (umts_fp_conversation_info->paging_indications + 7) / 8; + if (p_conv == NULL) { + /* Conversation does not exist yet, creating one now. */ + p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + if (!umts_fp_conversation_info) { + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + fill_pch_coversation_info_for_heur(umts_fp_conversation_info, pinfo); + } + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[1] = (length - (pi_byte_length + 6)) * 8; /* Removing header length (4), footer length (2) and PI bitmap length*/ + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + tb_size_found = TRUE; + } + } + else { + if (tfi == 0x01 && !tb_size_found) { + /* TB present and PI bitmap is missing. Can calculate TB length.*/ + if (p_conv == NULL) { + /* Conversation does not exist yet, creating one now. */ + p_conv = conversation_new(pinfo->num, &pinfo->net_dst, &pinfo->net_src, + pinfo->ptype, + pinfo->destport, pinfo->srcport, NO_ADDR_B); + } + if (!umts_fp_conversation_info) { + umts_fp_conversation_info = wmem_new0(wmem_file_scope(), umts_fp_conversation_info_t); + fill_pch_coversation_info_for_heur(umts_fp_conversation_info, pinfo); + } + umts_fp_conversation_info->fp_dch_channel_info[0].dl_chan_tf_size[1] = (length - 6) * 8; /* Removing header length (4), footer length (2) */ + set_both_sides_umts_fp_conv_data(pinfo, umts_fp_conversation_info); + tb_size_found = TRUE; + } + } + + if (pi_length_found && tb_size_found) { + /* Stream completely framed! */ + conversation_set_dissector(find_or_create_conversation(pinfo), fp_handle); + dissect_fp(tvb, pinfo, tree, data); + return TRUE; + } + else { + /* Some data still missing */ + return FALSE; + } +} +/* This method can frame UDP streams containing FP packets but dissection of those packets will */ +/* fail since the FP conversation info is never attached */ static gboolean heur_dissect_fp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { @@ -5744,6 +6383,10 @@ void proto_reg_handoff_fp(void) mac_fdd_hsdsch_handle = find_dissector_add_dependency("mac.fdd.hsdsch", proto_fp); heur_dissector_add("udp", heur_dissect_fp, "FP over UDP", "fp_udp", proto_fp, HEURISTIC_DISABLE); + heur_dissector_add("udp", heur_dissect_fp_dcch_over_dch, "FP over UDP (DCCH over DCH)", "fp_udp_dcch_dch", proto_fp, HEURISTIC_DISABLE); + heur_dissector_add("udp", heur_dissect_fp_fach, "FP over UDP (FACH)", "fp_udp_fach", proto_fp, HEURISTIC_DISABLE); + heur_dissector_add("udp", heur_dissect_fp_rach, "FP over UDP (RACH)", "fp_udp_rach", proto_fp, HEURISTIC_DISABLE); + heur_dissector_add("udp", heur_dissect_fp_pch, "FP over UDP (PCH)", "fp_udp_pch", proto_fp, HEURISTIC_DISABLE); fp_aal2_handle = create_dissector_handle(dissect_fp_aal2, proto_fp); dissector_add_uint("atm.aal2.type", TRAF_UMTS_FP, fp_aal2_handle); diff --git a/epan/dissectors/packet-umts_fp.h b/epan/dissectors/packet-umts_fp.h index 9a1365df7f..3d7ac5107c 100644 --- a/epan/dissectors/packet-umts_fp.h +++ b/epan/dissectors/packet-umts_fp.h @@ -146,7 +146,8 @@ typedef struct guint32 dl_frame_number; /* the frame where this conversation is started from CRNC */ guint32 ul_frame_number; /* the frame where this conversation is started from Node B */ address crnc_address; - guint16 crnc_port; + guint16 /* Expecting specific lengths: 27 for frames with 1 TB, 48 for frames with 2 TBs */ + crnc_port; gint com_context_id; /*Identifies a single UE in the network*/ /* For PCH channel */