aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
authormartinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7>2009-01-05 23:18:00 +0000
committermartinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7>2009-01-05 23:18:00 +0000
commit3ff88dd9537da8a06242a1993a002a649930637c (patch)
tree128c172fee4d8842917337114a3658da1e164772 /epan/dissectors
parent6ed741e9ca9d34923bef391c9ce4050429100530 (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.common2
-rw-r--r--epan/dissectors/packet-catapult-dct2000.c12
-rw-r--r--epan/dissectors/packet-rlc-lte.c1014
-rw-r--r--epan/dissectors/packet-rlc-lte.h38
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;
+