diff options
author | martinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-01-05 23:18:00 +0000 |
---|---|---|
committer | martinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-01-05 23:18:00 +0000 |
commit | 3ff88dd9537da8a06242a1993a002a649930637c (patch) | |
tree | 128c172fee4d8842917337114a3658da1e164772 /epan/dissectors | |
parent | 6ed741e9ca9d34923bef391c9ce4050429100530 (diff) |
Add RLC LTE dissector.
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@27161 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/Makefile.common | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-catapult-dct2000.c | 12 | ||||
-rw-r--r-- | epan/dissectors/packet-rlc-lte.c | 1014 | ||||
-rw-r--r-- | epan/dissectors/packet-rlc-lte.h | 38 |
4 files changed, 1059 insertions, 7 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 3738ee97fc..2ddb2041cb 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -691,6 +691,7 @@ DISSECTOR_SRC = \ packet-rgmp.c \ packet-rip.c \ packet-ripng.c \ + packet-rlc-lte.c \ packet-rlogin.c \ packet-rmcp.c \ packet-rmi.c \ @@ -1091,6 +1092,7 @@ DISSECTOR_INCLUDES = \ packet-rdt.h \ packet-rgmp.h \ packet-ripng.h \ + packet-rlc-lte.h \ packet-rmi.h \ packet-rmt-alc.h \ packet-rmt-common.h \ diff --git a/epan/dissectors/packet-catapult-dct2000.c b/epan/dissectors/packet-catapult-dct2000.c index 184746a344..5660f525f5 100644 --- a/epan/dissectors/packet-catapult-dct2000.c +++ b/epan/dissectors/packet-catapult-dct2000.c @@ -41,8 +41,8 @@ #include <wiretap/catapult_dct2000.h> #include "packet-umts_fp.h" #include "packet-mac-lte.h" -#if 0 #include "packet-rlc-lte.h" +#if 0 #include "packet-pdcp.h" #endif @@ -137,8 +137,8 @@ static gint outhdr_values_found = 0; extern int proto_fp; extern int proto_mac_lte; -#if 0 extern int proto_rlc_lte; +#if 0 extern int proto_pdcp; #endif @@ -149,8 +149,8 @@ static void parse_outhdr_string(guchar *outhdr_string); static void attach_fp_info(packet_info *pinfo, gboolean received, const char *protocol_name, int variant); static void attach_mac_lte_info(packet_info *pinfo); -#if 0 static void attach_rlc_lte_info(packet_info *pinfo); +#if 0 static void attach_pdcp_info(packet_info *pinfo); #endif @@ -1118,7 +1118,6 @@ static void attach_mac_lte_info(packet_info *pinfo) /* Fill in a RLC LTE packet info struct and attach it to the packet for that dissector to use */ -#if 0 static void attach_rlc_lte_info(packet_info *pinfo) { struct rlc_lte_info *p_rlc_lte_info; @@ -1151,7 +1150,6 @@ static void attach_rlc_lte_info(packet_info *pinfo) /* Store info in packet */ p_add_proto_data(pinfo->fd, proto_rlc_lte, p_rlc_lte_info); } -#endif /* Fill in a PDCP packet info struct and attach it to the packet for the PDCP dissector to use */ @@ -1402,7 +1400,6 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) attach_mac_lte_info(pinfo); } -#if 0 /* LTE RLC needs info attached */ else if (strcmp(protocol_name, "rlc_r8_lte") == 0) { @@ -1410,6 +1407,7 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) attach_rlc_lte_info(pinfo); } +#if 0 /* LTE PDCP needs info attached */ else if (strcmp(protocol_name, "pdcp_r8_lte") == 0) { @@ -1517,13 +1515,13 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) protocol_handle = find_dissector("mac-lte"); } -#if 0 else if (strcmp(protocol_name, "rlc_r8_lte") == 0) { protocol_handle = find_dissector("rlc-lte"); } +#if 0 else if (strcmp(protocol_name, "pdcp_r8_lte") == 0) { diff --git a/epan/dissectors/packet-rlc-lte.c b/epan/dissectors/packet-rlc-lte.c new file mode 100644 index 0000000000..d9771e91d7 --- /dev/null +++ b/epan/dissectors/packet-rlc-lte.c @@ -0,0 +1,1014 @@ +/* Routines for LTE RLC disassembly + * + * Martin Mathieson + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <epan/packet.h> +#include <epan/expert.h> + +#include "packet-rlc-lte.h" + + +/* Described in: + * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA) + * Radio Link Control (RLC) Protocol specification + */ + +/* Initialize the protocol and registered fields. */ +int proto_rlc_lte = -1; + +/* Decoding context */ +static int hf_rlc_lte_context_mode = -1; +static int hf_rlc_lte_context_direction = -1; +static int hf_rlc_lte_context_priority = -1; +static int hf_rlc_lte_context_ueid = -1; +static int hf_rlc_lte_context_channel_type = -1; +static int hf_rlc_lte_context_channel_id = -1; +static int hf_rlc_lte_context_pdu_length = -1; +static int hf_rlc_lte_context_um_sn_length = -1; + +/* Transparent mode fields */ +static int hf_rlc_lte_tm_data = -1; + +/* Unacknowledged mode fields */ +static int hf_rlc_lte_um_header = -1; +static int hf_rlc_lte_um_fi = -1; +static int hf_rlc_lte_um_fixed_e = -1; +static int hf_rlc_lte_um_sn = -1; +static int hf_rlc_lte_um_fixed_reserved = -1; +static int hf_rlc_lte_um_data = -1; +static int hf_rlc_lte_extension_part = -1; + +/* Extended header (common to UM and AM) */ +static int hf_rlc_lte_extension_e = -1; +static int hf_rlc_lte_extension_li = -1; +static int hf_rlc_lte_extension_padding = -1; + + +/* Acknowledged mode fields */ +static int hf_rlc_lte_am_header = -1; +static int hf_rlc_lte_am_data_control = -1; +static int hf_rlc_lte_am_rf = -1; +static int hf_rlc_lte_am_p = -1; +static int hf_rlc_lte_am_fi = -1; +static int hf_rlc_lte_am_fixed_e = -1; +static int hf_rlc_lte_am_fixed_sn = -1; +static int hf_rlc_lte_am_segment_lsf = -1; +static int hf_rlc_lte_am_segment_so = -1; +static int hf_rlc_lte_am_data = -1; + +/* Control fields */ +static int hf_rlc_lte_am_cpt = -1; +static int hf_rlc_lte_am_ack_sn = -1; +static int hf_rlc_lte_am_e1 = -1; +static int hf_rlc_lte_am_e2 = -1; +static int hf_rlc_lte_am_nack_sn = -1; +static int hf_rlc_lte_am_so_start = -1; +static int hf_rlc_lte_am_so_end = -1; + +/* Subtrees. */ +static int ett_rlc_lte = -1; +static int ett_rlc_lte_um_header = -1; +static int ett_rlc_lte_am_header = -1; +static int ett_rlc_lte_extension_part = -1; + + +static const value_string direction_vals[] = +{ + { 0, "Uplink"}, + { 1, "Downlink"}, + { 0, NULL } +}; + + +#define RLC_TM_MODE 1 +#define RLC_UM_MODE 2 +#define RLC_AM_MODE 3 + + +static const value_string rlc_mode_short_vals[] = +{ + { RLC_TM_MODE, "TM"}, + { RLC_UM_MODE, "UM"}, + { RLC_AM_MODE, "AM"}, + { 0, NULL } +}; + +static const value_string rlc_mode_vals[] = +{ + { RLC_TM_MODE, "Transparent Mode"}, + { RLC_UM_MODE, "Unacknowledged Mode"}, + { RLC_AM_MODE, "Acknowledged Mode"}, + { 0, NULL } +}; + + +static const value_string rlc_channel_type_vals[] = +{ + { 1, "CCCH"}, + { 2, "BCCH"}, + { 3, "PCCH"}, + { 4, "SRB"}, + { 5, "DRB"}, + { 0, NULL } +}; + + +static const value_string framing_info_vals[] = +{ + { 0, "First byte begins an RLC SDU and last byte ends an RLC SDU"}, + { 1, "First byte begins an RLC SDU and last byte does not end an RLC SDU"}, + { 2, "First byte does not begin an RLC SDU and last byte ends an RLC SDU"}, + { 3, "First byte does not begin an RLC SDU and last byte does not end an RLC SDU"}, + { 0, NULL } +}; + +static const value_string fixed_extension_vals[] = +{ + { 0, "Data field follows from the octet following the fixed part of the header"}, + { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"}, + { 0, NULL } +}; + +static const value_string extension_extension_vals[] = +{ + { 0, "Data field follows from the octet following the LI field following this E field"}, + { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"}, + { 0, NULL } +}; + +static const value_string data_or_control_vals[] = +{ + { 0, "Control PDU"}, + { 1, "Data PDU"}, + { 0, NULL } +}; + +static const value_string resegmentation_flag_vals[] = +{ + { 0, "AMD PDU"}, + { 1, "AND PDU segment"}, + { 0, NULL } +}; + +static const value_string polling_bit_vals[] = +{ + { 0, "Status report not requested"}, + { 1, "Status report is requested"}, + { 0, NULL } +}; + + +static const value_string lsf_vals[] = +{ + { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"}, + { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AND PDU"}, + { 0, NULL } +}; + + +static const value_string control_pdu_type_vals[] = +{ + { 0, "STATUS PDU"}, + { 0, NULL } +}; + +static const value_string am_e1_vals[] = +{ + { 0, "A set of NACK_SN, E1 and E2 does not follow"}, + { 1, "A set of NACK_SN, E1 and E2 follows"}, + { 0, NULL } +}; + +static const value_string am_e2_vals[] = +{ + { 0, "A set of SOstart and SOend does not follow for this NACK_SN"}, + { 1, "A set of SOstart and SOend follows for this NACK_SN"}, + { 0, NULL } +}; + +/* These are for keeping track of UM/AM extension headers, and the lengths found + in them */ +guint8 s_number_of_extensions = 0; +#define MAX_RLC_SDUS 64 +guint16 s_lengths[MAX_RLC_SDUS]; + + +/* Dissect extension headers (common to both UM and AM) */ +static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, + int offset) +{ + guint8 isOdd; + guint64 extension = 1; + guint64 length; + + /* Reset this count */ + s_number_of_extensions = 0; + + while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) { + proto_tree *extension_part_tree; + proto_item *extension_part_ti; + + isOdd = (s_number_of_extensions % 2); + + /* Extension part subtree */ + extension_part_ti = proto_tree_add_string_format(tree, + hf_rlc_lte_extension_part, + tvb, offset, 2, + "", + "Extension Part"); + extension_part_tree = proto_item_add_subtree(extension_part_ti, + ett_rlc_lte_extension_part); + + /* Read next extension */ + proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb, + (offset*8) + ((isOdd) ? 4 : 0), + 1, + &extension, FALSE); + + /* Read length field */ + proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb, + (offset*8) + ((isOdd) ? 5 : 1), + 11, + &length, FALSE); + + proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length); + + /* Move on to byte of next extension */ + if (isOdd) { + offset += 2; + } else { + offset++; + } + + s_lengths[s_number_of_extensions++] = (guint16)length; + } + + /* May need to skip padding after last extension part */ + isOdd = (s_number_of_extensions % 2); + if (isOdd) { + guint8 padding; + proto_item *ti; + + padding = tvb_get_guint8(tvb, offset) & 0x0f; + ti = proto_tree_add_item(tree, hf_rlc_lte_extension_padding, + tvb, offset, 1, FALSE); + if (padding != 0) { + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, + "Extension Header padding not zero (found 0x%x)", padding); + } + offset++; + } + + return offset; +} + + +/* Show in the info column how many bytes are in the UM/AM PDU, and indicate + whether or not the beginning and end are included in this packet */ +static void show_PDU_in_info(packet_info *pinfo, + guint16 length, + guint8 first_includes_start, + guint8 last_includes_end) +{ + /* Reflect this PDU in the info column */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, " %s%u-bytes%s", + (first_includes_start) ? "[" : "..", + length, + (last_includes_end) ? "]" : ".."); + } +} + + +/***************************************************/ +/* Unacknowledged mode PDU */ +static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, + int offset, + rlc_lte_info *p_rlc_lte_info) +{ + guint64 framing_info; + guint8 first_includes_start; + guint8 last_includes_end; + guint64 fixed_extension; + guint64 sn; + gint start_offset = offset; + proto_tree *um_header_tree; + proto_item *um_header_ti; + + /* Add UM header subtree */ + um_header_ti = proto_tree_add_string_format(tree, + hf_rlc_lte_um_header, + tvb, offset, 0, + "", + "UM header"); + um_header_tree = proto_item_add_subtree(um_header_ti, + ett_rlc_lte_um_header); + + + /*******************************/ + /* Fixed UM header */ + if (p_rlc_lte_info->UMSequenceNumberLength == 5) { + /* Framing info (2 bits) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi, + tvb, offset*8, 2, + &framing_info, FALSE); + + /* Extension (1 bit) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb, + (offset*8) + 2, 1, + &fixed_extension, FALSE); + + /* Sequence Number (5 bit) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb, + (offset*8) + 3, 5, + &sn, FALSE); + offset++; + } + else if (p_rlc_lte_info->UMSequenceNumberLength == 10) { + guint8 reserved; + proto_item *ti; + + /* Check 3 Reserved bits */ + reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5; + ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, FALSE); + if (reserved != 0) { + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, + "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved); + } + + /* Framing info (2 bits) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi, + tvb, (offset*8)+3, 2, + &framing_info, FALSE); + + /* Extension (1 bit) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb, + (offset*8) + 5, 1, + &fixed_extension, FALSE); + + /* Sequence Number (10 bits) */ + proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb, + (offset*8) + 6, 10, + &sn, FALSE); + offset += 2; + } + else { + /* Invalid length of sequence number */ + proto_item *ti; + ti = proto_tree_add_text(um_header_tree, tvb, 0, 0, "Invalid sequence number length (%u bits)", + p_rlc_lte_info->UMSequenceNumberLength); + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, + "Invalid sequence number length (%u bits)", + p_rlc_lte_info->UMSequenceNumberLength); + return; + } + + /* Show SN in info column */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%04u", + (guint16)sn); + } + + /* Show SN in UM header root */ + proto_item_append_text(um_header_ti, " (SN=%u)", (guint16)sn); + proto_item_set_len(um_header_ti, offset-start_offset); + + + /*************************************/ + /* UM header extension */ + if (fixed_extension) { + offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset); + } + + + /* Extract these 2 flags from framing_info */ + first_includes_start = ((guint8)framing_info & 0x02) == 0; + last_includes_end = ((guint8)framing_info & 0x01) == 0; + + + /*************************************/ + /* Data */ + if (s_number_of_extensions > 0) { + /* Show each data segment separately */ + int n; + for (n=0; n < s_number_of_extensions; n++) { + proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, s_lengths[n], FALSE); + show_PDU_in_info(pinfo, s_lengths[n], + (n==0) ? first_includes_start : TRUE, + TRUE); + offset += s_lengths[n]; + } + } + + /* Final data element */ + proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, -1, FALSE); + show_PDU_in_info(pinfo, tvb_length_remaining(tvb, offset), + (s_number_of_extensions == 0) ? first_includes_start : TRUE, + last_includes_end); +} + + + + +/* Dissect an AM STATUS PDU */ +static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, + int offset) +{ + guint8 cpt; + guint64 ack_sn, nack_sn; + guint64 e1 = 0, e2 = 0; + guint64 so_start, so_end; + int bit_offset = offset * 8; + proto_item *ti; + + /****************************************************************/ + /* Part of RLC control PDU header */ + + /* Control PDU Type (CPT) */ + cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4; + ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, FALSE); + if (cpt != 0) { + /* Protest and stop - only know about STATUS PDUs */ + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, + "RLC Control frame type %u not handled", cpt); + return; + } + + + /*****************************************************************/ + /* STATUS PDU */ + + /* The PDU itself starts 4 bits into the byte */ + bit_offset += 4; + + /* ACK SN */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb, + bit_offset, 10, &ack_sn, FALSE); + bit_offset += 10; + + /* E1 */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb, + bit_offset, 1, &e1, FALSE); + + /* Skip another bit to byte-align the next bit... */ + bit_offset++; + + /* Optional, extra fields */ + do { + if (e1) { + /****************************/ + /* Read NACK_SN, E1, E2 */ + + /* ACK_SN */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb, + bit_offset, 10, &nack_sn, FALSE); + bit_offset += 10; + + /* E1 */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb, + bit_offset, 1, &e1, FALSE); + bit_offset++; + + /* E2 */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb, + bit_offset, 1, &e2, FALSE); + bit_offset++; + + /* Reset this flag here */ + e1 = 0; + } + if (e2) { + /* Read SOstart, SOend */ + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb, + bit_offset, 15, &so_start, FALSE); + bit_offset += 15; + + proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb, + bit_offset, 15, &so_end, FALSE); + bit_offset += 15; + + /* Reset this flag here */ + e2 = 0; + } + } while (e1 || e2); + +} + + +/***************************************************/ +/* Acknowledged mode PDU */ +static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, + int offset) +{ + guint8 is_data; + guint8 is_segment; + guint8 fixed_extension; + guint8 framing_info; + guint8 first_includes_start; + guint8 last_includes_end; + proto_tree *am_header_tree; + proto_item *am_header_ti; + gint start_offset = offset; + guint16 sn; + + /* Add UM header subtree */ + am_header_ti = proto_tree_add_string_format(tree, + hf_rlc_lte_am_header, + tvb, offset, 0, + "", + "AM header"); + am_header_tree = proto_item_add_subtree(am_header_ti, + ett_rlc_lte_am_header); + + + /*******************************************/ + /* First bit is Data/Control flag */ + is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7; + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, FALSE); + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_str(pinfo->cinfo, COL_INFO, (is_data) ? " [DATA]" : " [CONTROL]"); + } + + + /**************************************************/ + /* Control PDUs are a completely separate format */ + if (!is_data) { + dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, offset); + return; + } + + + /******************************/ + /* Data PDU fixed header */ + + /* Re-segmentation Flag (RF) field */ + is_segment = (tvb_get_guint8(tvb, offset) & 0x40) >> 6; + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, FALSE); + + /* Polling bit */ + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, FALSE); + + /* Framing Info */ + framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3; + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, FALSE); + + /* Extension bit */ + fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2; + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, FALSE); + + /* Sequence Number */ + sn = tvb_get_ntohs(tvb, offset) & 0x03ff; + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, FALSE); + + offset += 2; + + /* Show SN in AM header root */ + proto_item_append_text(am_header_ti, " (SN=%u)", sn); + proto_item_set_len(am_header_ti, offset-start_offset); + + /***************************************/ + /* Dissect extra segment header fields */ + if (is_segment) { + /* Last Segment Field (LSF) */ + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, FALSE); + + /* SO */ + proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, FALSE); + + offset += 2; + } + + /*************************************/ + /* AM header extension */ + if (fixed_extension) { + offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset); + } + + + /* Extract these 2 flags from framing_info */ + first_includes_start = (framing_info & 0x02) == 0; + last_includes_end = (framing_info & 0x01) == 0; + + + /*************************************/ + /* Data */ + if (s_number_of_extensions > 0) { + /* Show each data segment separately */ + int n; + for (n=0; n < s_number_of_extensions; n++) { + proto_tree_add_item(tree, hf_rlc_lte_am_data, tvb, offset, s_lengths[n], FALSE); + show_PDU_in_info(pinfo, s_lengths[n], + (n==0) ? first_includes_start : TRUE, + TRUE); + offset += s_lengths[n]; + } + } + + /* Final data element */ + proto_tree_add_item(tree, hf_rlc_lte_am_data, tvb, offset, -1, FALSE); + show_PDU_in_info(pinfo, tvb_length_remaining(tvb, offset), + (s_number_of_extensions == 0) ? first_includes_start : TRUE, + last_includes_end); +} + + + +/*****************************/ +/* Main dissection function. */ +/*****************************/ + +void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_tree *rlc_lte_tree; + proto_item *ti; + proto_item *mode_ti; + gint offset = 0; + struct rlc_lte_info *p_rlc_lte_info = NULL; + + /* Set protocol name */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE"); + } + + /* Create protocol tree. */ + ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, FALSE); + rlc_lte_tree = proto_item_add_subtree(ti, ett_rlc_lte); + + + /* Look for packet info! */ + p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte); + + /* Can't dissect anything without it... */ + if (p_rlc_lte_info == NULL) { + proto_item *ti = + proto_tree_add_text(rlc_lte_tree, tvb, offset, -1, + "Can't dissect LTE RLC frame because no per-frame info was attached!"); + PROTO_ITEM_SET_GENERATED(ti); + return; + } + + /*****************************************/ + /* Show context information */ + /* TODO: hide inside own tree? */ + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_direction, + tvb, 0, 0, p_rlc_lte_info->direction); + PROTO_ITEM_SET_GENERATED(ti); + + mode_ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_mode, + tvb, 0, 0, p_rlc_lte_info->rlcMode); + PROTO_ITEM_SET_GENERATED(mode_ti); + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_ueid, + tvb, 0, 0, p_rlc_lte_info->ueid); + PROTO_ITEM_SET_GENERATED(ti); + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_priority, + tvb, 0, 0, p_rlc_lte_info->priority); + PROTO_ITEM_SET_GENERATED(ti); + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_type, + tvb, 0, 0, p_rlc_lte_info->channelType); + PROTO_ITEM_SET_GENERATED(ti); + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_id, + tvb, 0, 0, p_rlc_lte_info->channelId); + PROTO_ITEM_SET_GENERATED(ti); + + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_pdu_length, + tvb, 0, 0, p_rlc_lte_info->pduLength); + PROTO_ITEM_SET_GENERATED(ti); + + if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) { + ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_um_sn_length, + tvb, 0, 0, p_rlc_lte_info->UMSequenceNumberLength); + PROTO_ITEM_SET_GENERATED(ti); + } + + + /* Append context highlights to info column */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, + "[%s] [%s] UEId=%u %s:%u", + (p_rlc_lte_info->direction == 0) ? "UL" : "DL", + val_to_str(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"), + p_rlc_lte_info->ueid, + val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"), + p_rlc_lte_info->channelId); + } + + /* Reset this count */ + s_number_of_extensions = 0; + + /* Dissect the RLC PDU itself. Format depends upon mode... */ + switch (p_rlc_lte_info->rlcMode) { + + case RLC_TM_MODE: + /* Remaining bytes are all data */ + proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_tm_data, tvb, offset, -1, FALSE); + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, " [%u-bytes]", + tvb_length_remaining(tvb, offset)); + } + break; + + case RLC_UM_MODE: + dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info); + break; + + case RLC_AM_MODE: + dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset); + break; + + default: + /* Error - unrecognised mode */ + expert_add_info_format(pinfo, mode_ti, PI_MALFORMED, PI_ERROR, + "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode); + break; + } +} + + +void proto_register_rlc_lte(void) +{ + static hf_register_info hf[] = + { + /**********************************/ + /* Items for decoding context */ + { &hf_rlc_lte_context_mode, + { "RLC Mode", + "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0, + "RLC Mode", HFILL + } + }, + { &hf_rlc_lte_context_direction, + { "Direction", + "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0, + "Direction of message", HFILL + } + }, + { &hf_rlc_lte_context_priority, + { "Priority", + "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0, + "Priority", HFILL + } + }, + { &hf_rlc_lte_context_ueid, + { "UEId", + "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0, + "User Equipment Identifier associated with message", HFILL + } + }, + { &hf_rlc_lte_context_channel_type, + { "Channel Type", + "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0, + "Channel Type associated with message", HFILL + } + }, + { &hf_rlc_lte_context_channel_id, + { "Channel ID", + "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0, + "Channel ID associated with message", HFILL + } + }, + { &hf_rlc_lte_context_pdu_length, + { "PDU Length", + "rlc-lte.pdu_length", FT_UINT16, BASE_DEC, 0, 0x0, + "Length of PDU (in bytes)", HFILL + } + }, + { &hf_rlc_lte_context_um_sn_length, + { "UM Sequence number length", + "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0, + "Length of UM sequence number in bits", HFILL + } + }, + + + /* Transparent mode fields */ + { &hf_rlc_lte_tm_data, + { "TM Data", + "rlc-lte.tm.data", FT_BYTES, BASE_HEX, 0, 0x0, + "Transparent Mode Data", HFILL + } + }, + + /* Unacknowledged mode fields */ + { &hf_rlc_lte_um_header, + { "UM Header", + "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0, + "Unackowledged Mode Header", HFILL + } + }, + { &hf_rlc_lte_um_fi, + { "Framing Info", + "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0, + "Framing Info", HFILL + } + }, + { &hf_rlc_lte_um_fixed_e, + { "Extension", + "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0, + "Extension in fixed part of UM header", HFILL + } + }, + { &hf_rlc_lte_um_sn, + { "Sequence number", + "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0, + "Unacknowledged Mode Sequence Number", HFILL + } + }, + { &hf_rlc_lte_um_fixed_reserved, + { "Reserved", + "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0, + "Unacknowledged Mode Fixed header reserved bits", HFILL + } + }, + { &hf_rlc_lte_um_data, + { "UM Data", + "rlc-lte.um.data", FT_BYTES, BASE_HEX, 0, 0x0, + "Unacknowledged Mode Data", HFILL + } + }, + { &hf_rlc_lte_extension_part, + { "Extension Part", + "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0, + "Extension Part", HFILL + } + }, + + + { &hf_rlc_lte_extension_e, + { "Extension", + "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0, + "Extension in extended part of the header", HFILL + } + }, + { &hf_rlc_lte_extension_li, + { "Length Indicator", + "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0, + "Length Indicator", HFILL + } + }, + { &hf_rlc_lte_extension_padding, + { "Padding", + "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f, + "Extension header padding", HFILL + } + }, + + + { &hf_rlc_lte_am_header, + { "UM Header", + "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0, + "Ackowledged Mode Header", HFILL + } + }, + { &hf_rlc_lte_am_data_control, + { "Frame type", + "rlc-lte.am.frame_type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80, + "AM Frame Type (Control or Data)", HFILL + } + }, + { &hf_rlc_lte_am_rf, + { "Re-segmentation Flag", + "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40, + "AM Re-segmentation Flag", HFILL + } + }, + { &hf_rlc_lte_am_p, + { "Polling Bit", + "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20, + "Polling Bit", HFILL + } + }, + { &hf_rlc_lte_am_fi, + { "Framing Info", + "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18, + "AM Framing Info", HFILL + } + }, + { &hf_rlc_lte_am_fixed_e, + { "Extension", + "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04, + "Fixed Extension Bit", HFILL + } + }, + { &hf_rlc_lte_am_fixed_sn, + { "Sequence Number", + "rlc-lte.am.fixed.sn", FT_UINT16, BASE_HEX, 0, 0x03ff, + "AM Fixed Sequence Number", HFILL + } + }, + { &hf_rlc_lte_am_segment_lsf, + { "Last Segment Flag", + "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80, + "Last Segment Flag", HFILL + } + }, + { &hf_rlc_lte_am_segment_so, + { "Segment Offset", + "rlc-lte.am.segment.so", FT_UINT16, BASE_HEX, 0, 0x7fff, + "Segment Offset", HFILL + } + }, + { &hf_rlc_lte_am_data, + { "AM Data", + "rlc-lte.am.data", FT_BYTES, BASE_HEX, 0, 0x0, + "Acknowledged Mode Data", HFILL + } + }, + + + { &hf_rlc_lte_am_cpt, + { "Control PDU Type", + "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70, + "AM Control PDU Type", HFILL + } + }, + { &hf_rlc_lte_am_ack_sn, + { "ACK Sequence Number", + "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0ffc, + "Sequence Number we're next expecting to receive", HFILL + } + }, + { &hf_rlc_lte_am_e1, + { "Extension bit 1", + "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0, + "Extension bit 1", HFILL + } + }, + { &hf_rlc_lte_am_e2, + { "Extension bit 2", + "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0, + "Extension bit 2", HFILL + } + }, + { &hf_rlc_lte_am_nack_sn, + { "NACK Sequence Number", + "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0, + "Negative Acknowledgement Sequence Number", HFILL + } + }, + { &hf_rlc_lte_am_so_start, + { "SO Start", + "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0, + "SO Start", HFILL + } + }, + { &hf_rlc_lte_am_so_end, + { "SO End", + "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0, + "SO End", HFILL + } + }, + + }; + + static gint *ett[] = + { + &ett_rlc_lte, + &ett_rlc_lte_um_header, + &ett_rlc_lte_am_header, + &ett_rlc_lte_extension_part, + }; + + /* Register protocol. */ + proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte"); + proto_register_field_array(proto_rlc_lte, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Allow other dissectors to find this one by name. */ + register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte); +} + + diff --git a/epan/dissectors/packet-rlc-lte.h b/epan/dissectors/packet-rlc-lte.h new file mode 100644 index 0000000000..82fc444718 --- /dev/null +++ b/epan/dissectors/packet-rlc-lte.h @@ -0,0 +1,38 @@ +/* packet-rlc-lte.h + * + * Martin Mathieson + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* Info attached to each LTE RLC frame */ +typedef struct rlc_lte_info +{ + guint8 rlcMode; + guint8 direction; + guint8 priority; + guint16 ueid; + guint16 channelType; + guint16 channelId; + guint16 pduLength; + guint8 UMSequenceNumberLength; +} rlc_lte_info; + |