aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authormartinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7>2009-01-26 12:18:32 +0000
committermartinm <martinm@f5534014-38df-0310-8fa8-9805f1628bb7>2009-01-26 12:18:32 +0000
commitbb433a69700b13132e5516f5b96381bee7109cc3 (patch)
treea4960eaaf8b0ffc1818f2be06c2514a645274434 /epan
parent859768adb5e2596815288963f18ff9bcea0ea392 (diff)
Add dissector for LTE PDCP.
This dissector has lots of TODOs, and hasn't really been worked on in a while, but since a couple of people had been asking about PDCP support I thought I'd check it in now. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@27293 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/Makefile.common1
-rw-r--r--epan/dissectors/packet-catapult-dct2000.c16
-rw-r--r--epan/dissectors/packet-pdcp-lte.c2336
3 files changed, 2337 insertions, 16 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 800526f487..92703b4bfc 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -656,6 +656,7 @@ DISSECTOR_SRC = \
packet-pagp.c \
packet-pcep.c \
packet-pcnfsd.c \
+ packet-pdcp-lte.c \
packet-per.c \
packet-pflog.c \
packet-pgm.c \
diff --git a/epan/dissectors/packet-catapult-dct2000.c b/epan/dissectors/packet-catapult-dct2000.c
index 6a3dd149f7..02cd1997e0 100644
--- a/epan/dissectors/packet-catapult-dct2000.c
+++ b/epan/dissectors/packet-catapult-dct2000.c
@@ -42,9 +42,7 @@
#include "packet-umts_fp.h"
#include "packet-mac-lte.h"
#include "packet-rlc-lte.h"
-#if 0
#include "packet-pdcp-lte.h"
-#endif
/* Protocol and registered fields. */
static int proto_catapult_dct2000 = -1;
@@ -185,9 +183,7 @@ static gint outhdr_values_found = 0;
extern int proto_fp;
extern int proto_mac_lte;
extern int proto_rlc_lte;
-#if 0
extern int proto_pdcp_lte;
-#endif
void proto_register_catapult_dct2000(void);
@@ -197,9 +193,7 @@ 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);
static void attach_rlc_lte_info(packet_info *pinfo);
-#if 0
static void attach_pdcp_lte_info(packet_info *pinfo);
-#endif
@@ -819,9 +813,7 @@ void dissect_pdcp_lte(tvbuff_t *tvb _U_, gint offset _U_,
guint8 tag;
LogicalChannelType logicalChannelType;
guint8 bcch_transport = 0;
-#if 0
struct pdcp_lte_info *p_pdcp_lte_info = NULL;
-#endif
dissector_handle_t protocol_handle = 0;
tvbuff_t *pdcp_lte_tvb;
@@ -964,14 +956,12 @@ void dissect_pdcp_lte(tvbuff_t *tvb _U_, gint offset _U_,
/********************************/
/* Should be at data tag now */
-#if 0
/* Look for packet info! */
p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
/* Can't dissect anything without it... */
if (p_pdcp_lte_info == NULL) {
return;
}
-#endif
/* Call PDCP LTE dissector */
protocol_handle = find_dissector("pdcp-lte");
@@ -1380,7 +1370,6 @@ static void attach_rlc_lte_info(packet_info *pinfo)
/* Fill in a PDCP LTE packet info struct and attach it to the packet for the PDCP LTE
dissector to use */
-#if 0
static void attach_pdcp_lte_info(packet_info *pinfo)
{
struct pdcp_lte_info *p_pdcp_lte_info;
@@ -1416,7 +1405,6 @@ static void attach_pdcp_lte_info(packet_info *pinfo)
/* Store info in packet */
p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
}
-#endif
/* Attempt to show tty (raw character messages) as text lines. */
@@ -1633,14 +1621,12 @@ 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)
{
parse_outhdr_string(tvb_get_ephemeral_string(tvb, outhdr_start, outhdr_length));
attach_pdcp_lte_info(pinfo);
}
-#endif
/* Note that the first item of pinfo->pseudo_header->dct2000 will contain
@@ -1747,7 +1733,6 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
protocol_handle = find_dissector("rlc-lte");
}
-#if 0
else
if (strcmp(protocol_name, "pdcp_r8_lte") == 0)
{
@@ -1755,7 +1740,6 @@ dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
dissect_pdcp_lte(tvb, offset, pinfo, tree);
return;
}
-#endif
else
if ((strcmp(protocol_name, "rrc_r8_lte") == 0) ||
diff --git a/epan/dissectors/packet-pdcp-lte.c b/epan/dissectors/packet-pdcp-lte.c
new file mode 100644
index 0000000000..4ac01aec7e
--- /dev/null
+++ b/epan/dissectors/packet-pdcp-lte.c
@@ -0,0 +1,2336 @@
+/* Routines for LTE PDCP/RoHC
+ *
+ * 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/prefs.h>
+#include <epan/expert.h>
+#include <epan/addr_resolv.h>
+
+#include "packet-pdcp-lte.h"
+
+/* Described in:
+ * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
+ * Packet Data Convergence Protocol (PDCP) specification
+ *
+ * RFC 3095 RObust Header Compression (ROHC):
+ * Framework and four profiles: RTP, UDP, ESP, and uncompressed
+ */
+
+
+/* TODO:
+ - Update to latest version of 36.323
+ - Complete ROHC support for RTP and extend to other profiles (including ROHCv2)
+ - Support for decryption
+ - Verify MAC authentication bytes
+ - Call LTE RRC dissector for uncompressed, signalling payloads
+*/
+
+
+/* Initialize the protocol and registered fields. */
+int proto_pdcp_lte = -1;
+
+static int hf_pdcp_lte_configuration = -1;
+
+static int hf_pdcp_lte_rohc = -1;
+static int hf_pdcp_lte_rohc_compression = -1;
+static int hf_pdcp_lte_rohc_mode = -1;
+static int hf_pdcp_lte_rohc_rnd = -1;
+static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
+static int hf_pdcp_lte_rohc_profile = -1;
+static int hf_pdcp_lte_no_header_pdu = -1;
+static int hf_pdcp_lte_plane = -1;
+static int hf_pdcp_lte_seqnum_length = -1;
+
+static int hf_pdcp_lte_cid_inclusion_info = -1;
+static int hf_pdcp_lte_large_cid_present = -1;
+
+static int hf_pdcp_lte_seq_num_5 = -1;
+static int hf_pdcp_lte_seq_num_7 = -1;
+static int hf_pdcp_lte_reserved3 = -1;
+static int hf_pdcp_lte_seq_num_12 = -1;
+static int hf_pdcp_lte_signalling_data = -1;
+static int hf_pdcp_lte_mac = -1;
+static int hf_pdcp_lte_data_control = -1;
+static int hf_pdcp_lte_user_plane_data = -1;
+static int hf_pdcp_lte_control_pdu_type = -1;
+static int hf_pdcp_lte_lis = -1;
+static int hf_pdcp_lte_bitmap = -1;
+static int hf_pdcp_lte_bitmap_not_received = -1;
+
+static int hf_pdcp_lte_rohc_padding = -1;
+static int hf_pdcp_lte_rohc_r_0_crc = -1;
+static int hf_pdcp_lte_rohc_feedback = -1;
+
+static int hf_pdcp_lte_rohc_type0_t = -1;
+static int hf_pdcp_lte_rohc_type1_t = -1;
+static int hf_pdcp_lte_rohc_type2_t = -1;
+
+static int hf_pdcp_lte_rohc_d = -1;
+static int hf_pdcp_lte_rohc_ir_crc = -1;
+
+static int hf_pdcp_lte_rohc_static_ipv4 = -1;
+static int hf_pdcp_lte_rohc_ip_version = -1;
+static int hf_pdcp_lte_rohc_ip_protocol = -1;
+static int hf_pdcp_lte_rohc_ip_src = -1;
+static int hf_pdcp_lte_rohc_ip_dst = -1;
+
+static int hf_pdcp_lte_rohc_static_udp = -1;
+static int hf_pdcp_lte_rohc_static_udp_src_port = -1;
+static int hf_pdcp_lte_rohc_static_udp_dst_port = -1;
+
+static int hf_pdcp_lte_rohc_static_rtp = -1;
+static int hf_pdcp_lte_rohc_static_rtp_ssrc = -1;
+
+static int hf_pdcp_lte_rohc_dynamic_ipv4 = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_tos = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_ttl = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_id = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_df = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_rnd = -1;
+static int hf_pdcp_lte_rohc_dynamic_ipv4_nbo = -1;
+
+static int hf_pdcp_lte_rohc_dynamic_udp = -1;
+static int hf_pdcp_lte_rohc_dynamic_udp_checksum = -1;
+static int hf_pdcp_lte_rohc_dynamic_udp_seqnum = -1;
+
+static int hf_pdcp_lte_rohc_dynamic_rtp = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_rx = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_cc = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_seqnum = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_timestamp = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_reserved3 = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_x = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_mode = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_tis = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_tss = -1;
+static int hf_pdcp_lte_rohc_dynamic_rtp_ts_stride = -1;
+
+static int hf_pdcp_lte_rohc_ts = -1;
+static int hf_pdcp_lte_rohc_m = -1;
+
+static int hf_pdcp_lte_add_cid = -1;
+static int hf_pdcp_lte_large_cid = -1;
+
+static int hf_pdcp_lte_uo0_sn = -1;
+
+static int hf_pdcp_lte_r0_sn = -1;
+static int hf_pdcp_lte_r0_crc_sn = -1;
+static int hf_pdcp_lte_r0_crc_crc = -1;
+
+static int hf_pdcp_lte_feedback_code = -1;
+static int hf_pdcp_lte_feedback_size = -1;
+static int hf_pdcp_lte_feedback_feedback1 = -1;
+static int hf_pdcp_lte_feedback_feedback2 = -1;
+static int hf_pdcp_lte_feedback_ack_type = -1;
+static int hf_pdcp_lte_feedback_mode = -1;
+static int hf_pdcp_lte_feedback_sn = -1;
+static int hf_pdcp_lte_feedback_option = -1;
+static int hf_pdcp_lte_feedback_length = -1;
+static int hf_pdcp_lte_feedback_crc = -1;
+static int hf_pdcp_lte_feedback_option_sn = -1;
+static int hf_pdcp_lte_feedback_option_clock = -1;
+
+static int hf_pdcp_lte_ip_id = -1;
+static int hf_pdcp_lte_udp_checksum = -1;
+static int hf_pdcp_lte_payload = -1;
+
+
+/* Protocol subtree. */
+static int ett_pdcp = -1;
+static int ett_pdcp_configuration = -1;
+static int ett_pdcp_packet = -1;
+static int ett_pdcp_rohc = -1;
+static int ett_pdcp_rohc_static_ipv4 = -1;
+static int ett_pdcp_rohc_static_udp = -1;
+static int ett_pdcp_rohc_static_rtp = -1;
+static int ett_pdcp_rohc_dynamic_ipv4 = -1;
+static int ett_pdcp_rohc_dynamic_udp = -1;
+static int ett_pdcp_rohc_dynamic_rtp = -1;
+
+
+static const value_string pdcp_plane_vals[] = {
+ { Signalling_Plane, "Signalling" },
+ { User_Plane, "User" },
+ { 0, NULL }
+};
+
+
+static const value_string rohc_mode_vals[] = {
+ { Unidirectional, "Unidirectional" },
+ { OptimisticBidirectional, "Optimistic Bidirectional" },
+ { ReliableBidirectional, "Reliable Bidirectional" },
+ { 0, NULL }
+};
+
+
+/* TODO: add more */
+static const value_string rohc_profile_vals[] = {
+ { 0, "Uncompressed" },
+ { 1, "RTP" },
+ { 2, "UDP" },
+ { 3, "ESP/IP" },
+ { 0, NULL }
+};
+
+static const value_string pdu_type_vals[] = {
+ { 0, "Control PDU" },
+ { 1, "Data PDU" },
+ { 0, NULL }
+};
+
+static const value_string feedback_ack_vals[] = {
+ { 0, "ACK" },
+ { 1, "NACK" },
+ { 2, "STATIC-NACK" },
+ { 0, NULL }
+};
+
+static const value_string feedback_option_vals[] = {
+ { 1, "CRC" },
+ { 2, "REJECT" },
+ { 3, "SN-Not-Valid" },
+ { 4, "SN" },
+ { 5, "Clock" },
+ { 6, "Jitter" },
+ { 7, "Loss" },
+ { 0, NULL }
+};
+
+static const value_string control_pdu_type_vals[] = {
+ { 0, "PDCP Status report" },
+ { 1, "Header Compression Feedback Information" },
+ { 0, NULL }
+};
+
+static const value_string t_vals[] = {
+ { 0, "ID message format" },
+ { 1, "TS message format" },
+ { 0, NULL }
+};
+
+static const value_string ip_protocol_vals[] = {
+ { 6, "TCP" },
+ { 17, "UDP" },
+ { 0, NULL }
+};
+
+
+dissector_handle_t ip_handle = 0;
+
+
+/* Preference variables */
+static gboolean global_pdcp_show_feedback_option_tag_length = FALSE;
+static gboolean global_pdcp_dissect_user_plane_as_ip = FALSE;
+static gboolean global_pdcp_dissect_signalling_plane_as_rrc = FALSE; /* Not currently used */
+static gboolean global_pdcp_dissect_rohc = FALSE;
+
+void proto_reg_handoff_pdcp_lte(void);
+static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/* Dissect a Large-CID field.
+ Return following offset */
+static int dissect_large_cid(proto_tree *tree,
+ tvbuff_t *tvb,
+ int offset)
+{
+ guint8 first_octet = tvb_get_guint8(tvb, offset);
+
+ if ((first_octet & 0x80) == 0) {
+ /* One byte */
+ proto_tree_add_uint(tree, hf_pdcp_lte_large_cid, tvb, offset, 1,
+ first_octet);
+ return offset+1;
+ }
+ else {
+ /* Two bytes */
+ guint16 bytes = tvb_get_ntohs(tvb, offset) & 0x7fff;
+ proto_tree_add_uint(tree, hf_pdcp_lte_large_cid, tvb, offset, 2,
+ bytes);
+ return offset+2;
+ }
+
+}
+
+static int dissect_pdcp_dynamic_chain(proto_tree *tree,
+ proto_item *root_item _U_,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ /* IPv4 dynamic */
+ if (p_pdcp_info->rohc_ip_version == 4) {
+ proto_tree *dynamic_ipv4_tree;
+ proto_item *root_ti;
+ int tree_start_offset = offset;
+ guint8 tos, ttl, id, rnd, nbo;
+
+ /* Create dynamic IPv4 subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_ipv4, tvb, offset, -1, FALSE);
+ dynamic_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_ipv4);
+
+ /* ToS */
+ tos = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_tos, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* TTL */
+ ttl = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_ttl, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* IP-ID */
+ id = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_id, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* IP flags */
+ rnd = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
+ nbo = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_df, tvb, offset, 1, FALSE);
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_rnd, tvb, offset, 1, FALSE);
+ proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_nbo, tvb, offset, 1, FALSE);
+
+ /* TODO: general extension header list... */
+ offset += 3;
+
+ /* Set proper length for subtree */
+ proto_item_set_len(root_ti, offset-tree_start_offset);
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (ToS=%u, TTL=%u, ID=%u, RND=%u, NBO=%u)",
+ tos, ttl, id, rnd, nbo);
+ }
+
+ /* UDP dynamic */
+ if ((p_pdcp_info->profile == 1) ||
+ (p_pdcp_info->profile == 2)) {
+
+ proto_tree *dynamic_udp_tree;
+ proto_item *root_ti;
+ unsigned short checksum;
+
+ /* Create dynamic UDP subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_udp, tvb, offset, 2, FALSE);
+ dynamic_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_udp);
+
+ /* 16-bit checksum */
+ checksum = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_checksum, tvb, offset, 2, FALSE);
+ offset +=2;
+
+ if (p_pdcp_info->profile == 2) {
+ guint16 seqnum;
+
+ seqnum = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_seqnum, tvb, offset, 2, FALSE);
+ offset +=2;
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (checksum = %04x, seqnum = %u)", checksum, seqnum);
+ }
+ else {
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (checksum = %04x)", checksum);
+ }
+ }
+
+ /* RTP dynamic */
+ if (p_pdcp_info->profile == 1) {
+ proto_tree *dynamic_rtp_tree;
+ proto_item *root_ti;
+ int tree_start_offset = offset;
+ guint8 rx;
+ guint8 contributing_csrcs;
+ guint16 sequence_number;
+ guint32 timestamp;
+ guint8 tis=0, tss=0;
+ guint64 ts_stride=0;
+
+ /* Create dynamic RTP subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_rtp, tvb, offset, -1, FALSE);
+ dynamic_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_rtp);
+
+ /* TODO: */
+ /* V | P | RX | CC */
+ rx = tvb_get_guint8(tvb, offset) & 0x10;
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_rx, tvb, offset, 1, FALSE);
+ contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_cc, tvb, offset, 1, FALSE);
+ offset += 1;
+
+ /* TODO: */
+ /* M | PT */
+ offset += 1;
+
+ /* Sequence number */
+ sequence_number = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_seqnum, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ /* Timestamp (4 octets) */
+ timestamp = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_timestamp, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ /* TODO: CSRC list */
+ //offset += (4 * contributing_csrcs);
+ offset++;
+
+ /* TODO: Reserved | X | Mode | TIS | TIS */
+ if (rx) {
+ guint8 this_byte = tvb_get_guint8(tvb, offset);
+ proto_item *reserved_ti = proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
+ tvb, offset, 1, FALSE);
+
+ /* Check reserved bits are 0 */
+ if ((this_byte & 0xe0) != 0) {
+ expert_add_info_format(pinfo, reserved_ti, PI_MALFORMED, PI_ERROR,
+ "Reserved bits have value 0x%x - should be 0x0",
+ (this_byte & 0xe0));
+ }
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_x, tvb, offset, 1, FALSE);
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_mode, tvb, offset, 1, FALSE);
+ tss = (this_byte & 0x02);
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tss, tvb, offset, 1, FALSE);
+ tis = (this_byte & 0x01);
+ proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tis, tvb, offset, 1, FALSE);
+ offset++;
+ }
+
+ /* TODO: the length of these fields can be learned by looked at the leading bits, see
+ RFC 3095, "4.5.6. Self-describing variable-length values" */
+ /* TODO: TS-Stride (1-4 bytes) */
+ if (tis) {
+ /* Assume encoded in two bytes for now... */
+ proto_tree_add_bits_ret_val(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
+ tvb, offset*8 + 2, 14, &ts_stride, FALSE);
+ offset += 2;
+ }
+
+ /* TODO: Time-stride (1-4 bytes) */
+ if (tss) {
+ }
+
+ /* Set proper length for subtree */
+ proto_item_set_len(root_ti, offset-tree_start_offset);
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (seqnum = %u, timestamp = %u)",
+ sequence_number, timestamp);
+ }
+
+ return offset;
+}
+
+
+
+static int dissect_pdcp_irdyn_packet(proto_tree *tree _U_,
+ proto_item *root_item,
+ tvbuff_t *tvb _U_,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info _U_,
+ packet_info *pinfo)
+{
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
+ }
+ proto_item_append_text(root_item, " (IRDYN)");
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Profile */
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* 8-bit CRC */
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Dissect dynamic chain */
+ offset = dissect_pdcp_dynamic_chain(tree,
+ root_item,
+ tvb,
+ offset,
+ p_pdcp_info,
+ pinfo);
+ return offset;
+}
+
+
+static int dissect_pdcp_ir_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ unsigned char dynamic_chain_present;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " IR");
+ }
+ proto_item_append_text(root_item, " (IR)");
+
+ /* Is dynamic chain present? */
+ dynamic_chain_present = tvb_get_guint8(tvb, offset) & 0x1;
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_d, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Profile */
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* 8-bit CRC */
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* IPv4 static part */
+ if (p_pdcp_info->rohc_ip_version == 4) {
+ proto_tree *static_ipv4_tree;
+ proto_item *root_ti;
+ int tree_start_offset = offset;
+ guint8 protocol;
+ guint32 source, dest;
+
+ /* Create static IPv4 subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_ipv4, tvb, offset, -1, FALSE);
+ static_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_ipv4);
+
+ /* IP version (must be 4) */
+ proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_version, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Protocol */
+ protocol = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_protocol, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Source address */
+ source = tvb_get_ipv4(tvb, offset);
+ proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_src, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ /* Dest address */
+ dest = tvb_get_ipv4(tvb, offset);
+ proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_dst, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ /* Set proper length for subtree */
+ proto_item_set_len(root_ti, offset-tree_start_offset);
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (prot=%s: %s -> %s)",
+ val_to_str(protocol, ip_protocol_vals, "Unknown"),
+ (char*)get_hostname(source),
+ (char*)get_hostname(dest));
+ }
+
+ /* UDP static part. TODO: also check protocol from last part!? */
+ if ((p_pdcp_info->profile == 1) ||
+ (p_pdcp_info->profile == 2)) {
+
+ proto_tree *static_udp_tree;
+ proto_item *root_ti;
+ int tree_start_offset = offset;
+ unsigned short source_port, dest_port;
+
+ /* Create static UDP subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_udp, tvb, offset, -1, FALSE);
+ static_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_udp);
+
+ /* Source port */
+ source_port = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ /* Dest port */
+ dest_port = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ /* Set proper length for subtree */
+ proto_item_set_len(root_ti, offset-tree_start_offset);
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (%u -> %u)", source_port, dest_port);
+ }
+
+ /* RTP static */
+ if (p_pdcp_info->profile == 1) {
+ proto_tree *static_rtp_tree;
+ proto_item *root_ti;
+ guint32 ssrc;
+
+ /* Create static RTP subtree */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_rtp, tvb, offset, 4, FALSE);
+ static_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_rtp);
+
+ /* SSRC */
+ ssrc = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_item(static_rtp_tree, hf_pdcp_lte_rohc_static_rtp_ssrc, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ /* Add summary to root item */
+ proto_item_append_text(root_ti, " (SSRC=%u)", ssrc);
+ }
+
+
+ /* Dynamic chain */
+ if (dynamic_chain_present) {
+ offset = dissect_pdcp_dynamic_chain(tree,
+ root_item,
+ tvb,
+ offset,
+ p_pdcp_info,
+ pinfo);
+ }
+
+ return offset;
+}
+
+
+
+static int dissect_pdcp_feedback_feedback1(proto_tree *tree,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info _U_,
+ packet_info *pinfo _U_)
+{
+ guint8 sn;
+
+ /* TODO: profile-specific */
+ sn = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_feedback1, tvb, offset, 1, FALSE);
+ offset++;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
+ }
+
+ return offset;
+}
+
+/* Includes Large-CID, if present */
+static int dissect_pdcp_feedback_feedback2(proto_tree *tree,
+ tvbuff_t *tvb,
+ int offset,
+ int size,
+ struct pdcp_lte_info *p_pdcp_info _U_,
+ packet_info *pinfo _U_)
+{
+ guint8 ack_type;
+ guint8 mode;
+ guint8 first_octet;
+ guint16 sn;
+ const char * full_mode_name;
+ int size_remaining;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Feeback-2 root. TODO: add as tree root */
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_feedback2, tvb, offset, -1, FALSE);
+
+ /* Ack-type */
+ first_octet = tvb_get_guint8(tvb, offset);
+ ack_type = (first_octet & 0xc0) >> 6;
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_ack_type, tvb, offset, 1, FALSE);
+
+ /* TODO: expert info on NACK? */
+
+ /* Mode */
+ mode = (first_octet & 0x30) >> 4;
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_mode, tvb, offset, 1, FALSE);
+
+ /* Show ACK-TYPE(Mode) in info column */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ full_mode_name = val_to_str(mode, rohc_mode_vals, "Error");
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
+ val_to_str(ack_type, feedback_ack_vals, "Unknown"),
+ full_mode_name[0]);
+ }
+
+ /* 11 bits of SN */
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_sn, tvb, offset, 2, FALSE);
+ sn = tvb_get_ntohs(tvb, offset) & 0x7ff;
+ offset += 2;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
+ }
+
+ /* Loop over any remaining feedback options */
+ size_remaining = size - 2;
+
+ while (tvb_length_remaining(tvb, offset) > 0) {
+ guint8 option = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
+ guint8 length = tvb_get_guint8(tvb, offset) & 0x0f;
+
+ /* Preference setting controls showing option and lengths */
+ if (global_pdcp_show_feedback_option_tag_length) {
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_option, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_length, tvb, offset, 1, FALSE);
+ }
+ offset++;
+ size_remaining--;
+
+ /* TODO: switch including missing option types */
+ switch (option) {
+ case 1:
+ /* CRC */
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_crc, tvb, offset, 1, FALSE);
+ break;
+ case 2:
+ /* REJECT: TODO */
+ break;
+ case 3:
+ /* SN-Not-Valid: TODO */
+ break;
+ case 4:
+ /* SN */
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_option_sn, tvb, offset, 1, FALSE);
+ break;
+ case 5:
+ /* Clock */
+ proto_tree_add_item(tree, hf_pdcp_lte_feedback_option_clock, tvb, offset, 1, FALSE);
+ break;
+ case 6:
+ /* Jitter: TODO */
+ break;
+ case 7:
+ /* Loss: TODO */
+ break;
+
+ default:
+ /* TODO: unhandled option */
+ break;
+ }
+
+ /* Skip length */
+ offset += length;
+ size_remaining -= length;
+ }
+
+ return offset;
+}
+
+
+/* Dissect a feedback packet.
+ Return following offset */
+static int dissect_pdcp_feedback_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ guint8 code;
+ guint8 size;
+ proto_item *ti;
+ proto_item *root_ti;
+ proto_tree *feedback_tree;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
+ }
+ proto_item_append_text(root_item, " (Feedback)");
+
+ /* Create feedback tree root */
+ root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback, tvb, offset, -1, FALSE);
+ feedback_tree = proto_item_add_subtree(root_ti, ett_pdcp_packet);
+
+ /* Code */
+ code = tvb_get_guint8(tvb, offset) & 0x07;
+ ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_feedback_code, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Optional length field */
+ if (code != 0) {
+ proto_item_append_text(ti, " (length of feedback data)");
+ size = code;
+ }
+ else {
+ proto_tree_add_item(feedback_tree, hf_pdcp_lte_feedback_size, tvb, offset, 1, FALSE);
+ size = tvb_get_guint8(tvb, offset);
+ offset++;
+ }
+
+ /* Work out feedback type */
+ if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
+ !p_pdcp_info->large_cid_present) {
+
+ /* Small CID */
+ if (size == 1) {
+ offset = dissect_pdcp_feedback_feedback1(feedback_tree, tvb, offset, p_pdcp_info, pinfo);
+ }
+ else if ((size > 1) && ((tvb_get_guint8(tvb, offset) & 0xc0) == 0xc0)) {
+ /* Add-CID here! */
+ proto_tree_add_item(feedback_tree, hf_pdcp_lte_add_cid, tvb, offset, 1, FALSE);
+ offset++;
+
+ if (size == 2) {
+ offset = dissect_pdcp_feedback_feedback1(feedback_tree, tvb, offset, p_pdcp_info, pinfo);
+ }
+ else {
+ offset = dissect_pdcp_feedback_feedback2(feedback_tree, tvb, offset, size, p_pdcp_info, pinfo);
+ }
+ }
+ else {
+ offset = dissect_pdcp_feedback_feedback2(feedback_tree, tvb, offset, size, p_pdcp_info, pinfo);
+ }
+ }
+ else {
+ offset = dissect_pdcp_feedback_feedback2(feedback_tree, tvb, offset, size, p_pdcp_info, pinfo);
+ }
+
+ return offset;
+}
+
+
+/* Dissect R-0 packet.
+ Return following offset */
+static int dissect_pdcp_r_0_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info _U_,
+ packet_info *pinfo)
+{
+ guint8 sn;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " R-0");
+ }
+ proto_item_append_text(root_item, " (R-0)");
+
+ /* 6 bits of sn */
+ sn = tvb_get_guint8(tvb, offset) & 0x3f;
+ proto_tree_add_item(tree, hf_pdcp_lte_r0_sn, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
+ }
+
+ return offset;
+}
+
+
+/* Dissect R-0-CRC packet.
+ Return following offset */
+static int dissect_pdcp_r_0_crc_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ guint8 sn;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
+ }
+ proto_item_append_text(root_item, " (R-0-CRC)");
+
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_r_0_crc, tvb, offset, -1, FALSE);
+
+ /* 7 bits of sn */
+ /* TODO: wrong! Large-cid may be in-between!!!! */
+ sn = tvb_get_guint8(tvb, offset) & 0x3f;
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Conclude SN */
+ sn = (sn << 1) + ((tvb_get_guint8(tvb, offset) & 0x80) >> 7);
+ proto_tree_add_uint(tree, hf_pdcp_lte_r0_crc_sn, tvb, offset, 1, sn);
+
+ /* 7 bit CRC */
+ proto_tree_add_item(tree, hf_pdcp_lte_r0_crc_crc, tvb, offset, 1, FALSE);
+ offset++;
+
+ /* Show SN in info column */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
+ }
+
+ return offset;
+}
+
+
+/* Dissect UO-0-CRC packet.
+ Return following offset */
+static int dissect_pdcp_uo_0_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ guint8 sn;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
+ }
+ proto_item_append_text(root_item, " (UO-0)");
+
+ /* SN */
+ sn = (tvb_get_guint8(tvb, offset) & 0x78) >> 3;
+ proto_tree_add_item(tree, hf_pdcp_lte_uo0_sn, tvb, offset, 1, FALSE);
+
+ /* TODO: CRC... */
+
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Show SN in info column */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
+ }
+
+ return offset;
+}
+
+
+/* Dissect R-1 packet.
+ Return following offset */
+static int dissect_pdcp_r_1_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1");
+ }
+ proto_item_append_text(root_item, " (R-1)");
+
+ /* TODO: octet before large-cid */
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ }
+
+ return offset;
+}
+
+
+/* Dissect R-1-TS or R-1-ID packet.
+ Return following offset */
+static int dissect_pdcp_r_1_ts_or_id_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ unsigned char T;
+
+ /* TODO: octet before large-cid */
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* T determines frame type */
+ T = tvb_get_guint8(tvb, ++offset) >> 7;
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_type1_t, tvb, offset, 1, FALSE);
+ if (T) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
+ }
+ proto_item_append_text(root_item, " (R-1-TS)");
+ }
+ else {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
+ }
+ proto_item_append_text(root_item, " (R-1-ID)");
+ }
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ }
+
+ return offset;
+}
+
+
+/* Dissect UO-1 packet.
+ Return following offset */
+static int dissect_pdcp_uo_1_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
+ }
+ proto_item_append_text(root_item, " (UO-1)");
+
+ /* TODO: octet before large-cid */
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ }
+
+ return offset;
+}
+
+
+/* Dissect UO-1-TS or UO-1-ID packet.
+ Return following offset */
+static int dissect_pdcp_uo_1_ts_or_id_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ unsigned char T;
+
+ /* TODO: octet before large-cid */
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* T determines frame type */
+ T = tvb_get_guint8(tvb, ++offset) >> 5;
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_type0_t, tvb, offset, 1, FALSE);
+ if (T) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
+ }
+ proto_item_append_text(root_item, " (UO-1-TS)");
+ }
+ else {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
+ }
+ proto_item_append_text(root_item, " (UO-1-ID)");
+ }
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ }
+
+ return offset;
+}
+
+
+
+
+
+/* Dissect UOR-2 packet.
+ Return following offset */
+static int dissect_pdcp_uor_2_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ guint8 ts;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
+ }
+ proto_item_append_text(root_item, " (UOR-2)");
+
+ /* TS straddles CID */
+ ts = tvb_get_guint8(tvb, offset) & 0x1f;
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* Last bit of TS is here */
+ ts = (ts << 1) & (tvb_get_guint8(tvb, offset) >> 7);
+ proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
+
+
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ offset++;
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ offset += 2;
+ }
+
+ return offset;
+}
+
+
+/* Dissect UOR-2-TS or UOR-2-ID packet.
+ Return following offset */
+static int dissect_pdcp_uor_2_ts_or_id_packet(proto_tree *tree,
+ proto_item *root_item,
+ tvbuff_t *tvb,
+ int offset,
+ struct pdcp_lte_info *p_pdcp_info,
+ packet_info *pinfo)
+{
+ unsigned char T;
+
+ /* TODO: octet before large-cid.
+ TODO: can't decode this until we know what T is,
+ but T is after large-cid... */
+ offset++;
+
+ /* T determines frame type */
+ T = tvb_get_guint8(tvb, offset) >> 7;
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_type2_t, tvb, offset, 1, FALSE);
+
+ if (T) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
+ }
+ proto_item_append_text(root_item, " (UOR-2-TS)");
+ }
+ else {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
+ }
+ proto_item_append_text(root_item, " (UOR-2-ID)");
+ }
+
+
+ if (T) {
+ /* UOR-2-TS format */
+
+ /* TS */
+ guint8 ts = tvb_get_guint8(tvb, offset) & 0x1f;
+ proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
+ offset++;
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* m */
+ proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, ts);
+
+ /* TODO: */
+ }
+ else {
+ /* TODO: UOR-2-ID format */
+
+ /* IP-ID */
+
+ /* Large CID */
+ if (p_pdcp_info->large_cid_present) {
+ offset = dissect_large_cid(tree, tvb, offset);
+ }
+
+ /* TODO: */
+ }
+
+ if (p_pdcp_info->profile == 1) {
+ /* TODO: */
+ }
+ else if (p_pdcp_info->profile == 2) {
+ /* TODO: */
+ }
+
+ return offset;
+}
+
+
+
+
+/* Show in the tree the config info attached to this frame, as generated fields */
+static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
+ pdcp_lte_info *p_pdcp_info)
+{
+ proto_item *ti;
+ proto_tree *configuration_tree;
+ proto_item *configuration_ti = proto_tree_add_item(tree,
+ hf_pdcp_lte_configuration,
+ tvb, 0, 0, FALSE);
+ configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
+
+ /* Plane */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
+ p_pdcp_info->plane);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* User-plane-specific fields */
+ if (p_pdcp_info->plane == User_Plane) {
+
+ /* No Header PDU */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
+ p_pdcp_info->no_header_pdu);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ if (!p_pdcp_info->no_header_pdu) {
+
+ /* Seqnum length */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
+ p_pdcp_info->seqnum_length);
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
+ }
+
+ /* RoHC compression */
+ ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
+ p_pdcp_info->rohc_compression);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* RoHC-specific settings */
+ if (p_pdcp_info->rohc_compression) {
+
+ /* Show RoHC mode */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
+ p_pdcp_info->mode);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Show RND */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
+ p_pdcp_info->rnd);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* UDP Checksum */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
+ p_pdcp_info->udp_checkum_present);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* RoHC profile */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
+ p_pdcp_info->profile);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* CID Inclusion Info */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
+ p_pdcp_info->cid_inclusion_info);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Large CID */
+ ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
+ p_pdcp_info->large_cid_present);
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
+
+ /* Append summary to configuration root */
+ proto_item_append_text(configuration_ti, "(plane=%s",
+ val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
+
+ if (p_pdcp_info->rohc_compression) {
+ const char *mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
+ proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
+ mode[0],
+ val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unknown"));
+ }
+ proto_item_append_text(configuration_ti, ")");
+ PROTO_ITEM_SET_GENERATED(configuration_ti);
+
+ /* Show plane in info column */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
+ val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
+ }
+
+}
+
+
+/******************************/
+/* Main dissection function. */
+static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ const char *mode;
+ proto_tree *pdcp_tree = NULL;
+ proto_item *root_ti = NULL;
+ proto_tree *rohc_tree = NULL;
+ proto_item *rohc_ti = NULL;
+ gint offset = 0;
+ gint rohc_offset;
+ struct pdcp_lte_info *p_pdcp_info;
+ guint8 base_header_byte;
+ guint8 udp_checksum_needed = TRUE;
+
+ /* Append this protocol name rather than replace. */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
+
+ /* Create pdcp tree. */
+ if (tree) {
+ root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, FALSE);
+ pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
+ }
+
+
+ /* Look for attached packet info! */
+ p_pdcp_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
+ /* Can't dissect anything without it... */
+ if (p_pdcp_info == NULL) {
+ return;
+ }
+
+
+ /* Set mode string */
+ mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
+
+ /* Show configuration (attached packet) info in tree */
+ if (pdcp_tree) {
+ show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
+ }
+
+ /* Show RoHC mode */
+ if (p_pdcp_info->rohc_compression &&
+ check_col(pinfo->cinfo, COL_INFO)) {
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
+ }
+
+
+ /* Handle PDCP header (if present) */
+ if (!p_pdcp_info->no_header_pdu) {
+
+ /*****************************/
+ /* Signalling plane messages */
+ if (p_pdcp_info->plane == Signalling_Plane) {
+ guint32 mac;
+ guint32 data_length;
+
+ /* 5-bit sequence number */
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, FALSE);
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u",
+ tvb_get_guint8(tvb, offset) & 0x1f);
+ }
+ offset++;
+
+
+ /* RRC data is all but last 4 bytes.
+ TODO: use lte-rrc dissector when available
+ (according to direction and channel type) */
+ if (global_pdcp_dissect_signalling_plane_as_rrc) {
+ /*
+ tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset, offset,
+ tvb_length_remaining(tvb, offset) - 4);
+ */
+ }
+ else {
+ /* Just show as unparsed data */
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
+ tvb_length_remaining(tvb, offset) - 4, FALSE);
+ }
+
+ data_length = tvb_length_remaining(tvb, offset) - 4;
+ offset += data_length;
+
+ /* Last 4 bytes are MAC */
+ mac = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
+ mac, data_length);
+ }
+
+ return;
+ }
+ else if (p_pdcp_info->plane == User_Plane) {
+
+ /**********************************/
+ /* User-plane messages */
+ guint16 seqnum;
+ gboolean pdu_type = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
+
+ /* Data/Control flag */
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, FALSE);
+
+ if (pdu_type == 1) {
+ /*****************************/
+ /* Use-plane Data */
+
+ /* Number of sequence number bits depends upon config */
+ if (p_pdcp_info->seqnum_length == 7) {
+ seqnum = tvb_get_guint8(tvb, offset) & 0x7f;
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, FALSE);
+ offset++;
+ }
+ else if (p_pdcp_info->seqnum_length == 12) {
+ proto_item *ti;
+ guint8 reserved_value;
+
+ /* 3 reserved bits */
+ ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, FALSE);
+ reserved_value = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
+
+ /* Complain if not 0 */
+ if (reserved_value != 0) {
+ expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
+ "Reserved bits have value 0x%x - should be 0x0",
+ reserved_value);
+ }
+
+ /* 12-bit sequence number */
+ seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+ else {
+ /* Not a recognised data format!!!!! */
+ return;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u", seqnum);
+ }
+ }
+ else {
+ /*******************************/
+ /* User-plane Control messages */
+ guint8 control_pdu_type = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, FALSE);
+
+ switch (control_pdu_type) {
+ case 0: /* PDCP status report */
+ {
+ guint16 lis;
+ guint not_received = 0;
+ guint sn;
+
+ /* Last-in-sequence SN */
+ lis = tvb_get_ntohs(tvb, offset) & 0x0fff;
+ sn = lis;
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_lis, tvb,
+ offset, 2, FALSE);
+ offset += 2;
+
+ /* Bitmap */
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
+ offset, -1, FALSE);
+
+ /* For each byte... */
+ for ( ; tvb_length_remaining(tvb, offset); offset++) {
+ guint bit_offset = 0;
+ /* .. look for error (0) in each bit */
+ for ( ; bit_offset < 8; bit_offset++) {
+ if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
+ proto_tree_add_boolean_format_value(pdcp_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
+ " (SN=%u)", sn);
+ not_received++;
+ }
+ sn = (sn + 1) % 4096;
+ }
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ " Status Report (lis=%u) not-received=%u",
+ lis, not_received);
+ }
+ }
+ return;
+
+ case 1: /* RoHC Feedback */
+ offset++;
+ break; /* Drop-through to dissect feedback */
+
+ default: /* Reserved */
+ return;
+ }
+ }
+ }
+ else {
+ /* Invalid plane setting...! */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " - INVALID PLANE (%u)",
+ p_pdcp_info->plane);
+ }
+ return;
+ }
+ }
+ else {
+ /* Show that its a no-header PDU */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_str(pinfo->cinfo, COL_INFO, " No-Header");
+ }
+ }
+
+
+ /* If not compressed with RoHC, show as user-plane data */
+ if (!p_pdcp_info->rohc_compression) {
+
+ if (global_pdcp_dissect_user_plane_as_ip && (ip_handle != 0)) {
+ tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
+ }
+ else {
+ if (tvb_length_remaining(tvb, offset) > 0) {
+ proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, FALSE);
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%u bytes data)",
+ tvb_length_remaining(tvb, offset));
+ }
+ }
+ }
+ return;
+ }
+
+
+ /***************************/
+ /* ROHC packets */
+ /***************************/
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+ col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
+ val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unkown"));
+ }
+
+ /* Only attempt ROHC if configured to */
+ if (!global_pdcp_dissect_rohc) {
+ return;
+ }
+
+ /* Create pdcp tree. */
+ if (pdcp_tree) {
+ rohc_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_rohc, tvb, offset, -1, FALSE);
+ rohc_tree = proto_item_add_subtree(rohc_ti, ett_pdcp_rohc);
+ }
+
+ rohc_offset = offset;
+
+ /* Skip any leading padding octets (11100000) */
+ while (tvb_get_guint8(tvb, offset) == 0xe0) {
+ offset++;
+ }
+ if (offset > rohc_offset) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_padding, tvb, rohc_offset,
+ offset-rohc_offset, FALSE);
+ }
+
+ /* Add-CID octet */
+ if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
+ !p_pdcp_info->large_cid_present)
+ {
+ if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_add_cid, tvb, offset, 1, FALSE);
+ offset++;
+ }
+ else {
+ /* Assume CID value of 0 if field absent */
+ proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_add_cid, tvb, offset, 0, 0);
+ PROTO_ITEM_SET_GENERATED(ti);
+ }
+ }
+
+ /* Now look at first octet of base header and identify packet type */
+ base_header_byte = tvb_get_guint8(tvb, offset);
+
+ /* IR (1111110) */
+ if ((base_header_byte & 0xfe) == 0xfc) {
+ offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ }
+
+ /* IRDYN (11111000) */
+ else if (base_header_byte == 0xf8) {
+ offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ udp_checksum_needed = FALSE;
+ }
+
+ /* Feedback (begins with 11110) */
+ else if (((base_header_byte & 0xf8) >> 3) == 0x1e) {
+ offset = dissect_pdcp_feedback_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+
+ /* Packet type 0 (0) */
+ else if ((base_header_byte & 0x80) == 0) {
+
+ /* TODO: decide type based upon:
+ - mode
+ - 2nd bit
+ - length remaining (taking into account large-cid) */
+
+ /* R-0 begins with 00 */
+ if (((base_header_byte & 0xc0) == 0) &&
+ (p_pdcp_info->mode == ReliableBidirectional)) {
+
+ offset = dissect_pdcp_r_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ }
+
+ /* R-0-CRC begins with 01 */
+ else if ((((base_header_byte & 0x40) >> 6) == 1) &&
+ (p_pdcp_info->mode == ReliableBidirectional)) {
+
+ offset = dissect_pdcp_r_0_crc_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ }
+
+ else {
+ offset = dissect_pdcp_uo_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ }
+ }
+
+ /* Packet type 1 (10) */
+ else if (((base_header_byte & 0xc0) >> 6) == 2) {
+
+ switch (p_pdcp_info->mode) {
+
+ case ReliableBidirectional:
+ /* R-1 if !(ipv4 && rand) */
+ if (!((p_pdcp_info->rohc_ip_version == 4) &&
+ (!p_pdcp_info->rnd))) {
+ offset = dissect_pdcp_r_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+ else {
+ /* Whether its R-1-ID or R-1-TS depends upon T bit */
+ dissect_pdcp_r_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+ break;
+
+ case Unidirectional:
+ case OptimisticBidirectional:
+ /* UO-1 if !(ipv4 && rand) */
+ if (!((p_pdcp_info->rohc_ip_version == 4) &&
+ (!p_pdcp_info->rnd))) {
+ offset = dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+ else {
+ /* Whether its UO-1-ID or UO-1-TS depends upon T bit */
+ dissect_pdcp_uo_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+
+ return;
+
+ }
+ }
+
+ /* Packet type 2 (110) */
+ else if (((base_header_byte & 0xe0) >> 5) == 6) {
+
+ /* UOR-2 if !(ipv4 && rand) */
+ if (!((p_pdcp_info->rohc_ip_version == 4) &&
+ (!p_pdcp_info->rnd))) {
+
+ offset = dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ }
+ else {
+ /* Whether its UOR-2-ID or UOR-2-TS depends upon T bit */
+ dissect_pdcp_uor_2_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
+ return;
+ }
+ }
+
+ /* Segment (1111111) */
+ else if ((base_header_byte & 0xfe) == 0xfe) {
+ /* TODO: */
+ return;
+ }
+
+
+ /* Fields beyond base header */
+
+ /* IP-ID */
+ if (p_pdcp_info->rnd) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_ip_id, tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+
+ /* UDP Checksum */
+ if (p_pdcp_info->udp_checkum_present && udp_checksum_needed) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_udp_checksum, tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+
+ /* Payload */
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ proto_tree_add_item(rohc_tree, hf_pdcp_lte_payload, tvb, offset, -1, FALSE);
+ }
+}
+
+void proto_register_pdcp(void)
+{
+ static hf_register_info hf[] =
+ {
+ { &hf_pdcp_lte_configuration,
+ { "Configuration",
+ "pdcp_configuration", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Configuation info passed into dissector", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_compression,
+ { "RoHC Compression",
+ "pdcp.rohc", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
+ "RoHC Mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_mode,
+ { "RoHC mode",
+ "pdcp.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
+ "RoHC Mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_rnd,
+ { "RND", /* TODO: true/false vals? */
+ "pdcp.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "RND of outer ip header", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_udp_checksum_present,
+ { "UDP Checksum", /* TODO: true/false vals? */
+ "pdcp.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "UDP Checksum_present", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_profile,
+ { "RoHC profile",
+ "pdcp.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
+ "RoHC Mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_no_header_pdu,
+ { "No Header PDU",
+ "pdcp.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "No Header PDU", HFILL
+ }
+ },
+ { &hf_pdcp_lte_plane,
+ { "Plane",
+ "pdcp.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
+ "No Header PDU", HFILL
+ }
+ },
+ { &hf_pdcp_lte_seqnum_length,
+ { "Seqnum length",
+ "pdcp.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Sequence Number Length", HFILL
+ }
+ },
+
+
+ { &hf_pdcp_lte_cid_inclusion_info,
+ { "CID Inclusion Info",
+ "pdcp.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "CID Inclusion Info", HFILL
+ }
+ },
+ { &hf_pdcp_lte_large_cid_present,
+ { "Large CID Present",
+ "pdcp.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Large CID Present", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_seq_num_5,
+ { "Seq Num",
+ "pdcp.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
+ "PDCP Seq num", HFILL
+ }
+ },
+ { &hf_pdcp_lte_seq_num_7,
+ { "Seq Num",
+ "pdcp.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
+ "PDCP Seq num", HFILL
+ }
+ },
+ { &hf_pdcp_lte_reserved3,
+ { "Reserved",
+ "pdcp.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
+ "3 reserved bits", HFILL
+ }
+ },
+ { &hf_pdcp_lte_seq_num_12,
+ { "Seq Num",
+ "pdcp.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
+ "PDCP Seq num", HFILL
+ }
+ },
+ { &hf_pdcp_lte_signalling_data,
+ { "Signalling Data",
+ "pdcp.signalling-data", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "Signalling Data", HFILL
+ }
+ },
+ { &hf_pdcp_lte_mac,
+ { "MAC",
+ "pdcp.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
+ "MAC", HFILL
+ }
+ },
+ { &hf_pdcp_lte_data_control,
+ { "PDU Type",
+ "pdcp.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
+ "PDU type", HFILL
+ }
+ },
+ { &hf_pdcp_lte_user_plane_data,
+ { "User-Plane Data",
+ "pdcp.user-data", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "User-Plane Data", HFILL
+ }
+ },
+ { &hf_pdcp_lte_control_pdu_type,
+ { "Control PDU Type",
+ "pdcp.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
+ "Control PDU type", HFILL
+ }
+ },
+ { &hf_pdcp_lte_lis,
+ { "Last in sequence SN",
+ "pdcp.lis", FT_UINT16, BASE_DEC, NULL, 0x0fff,
+ "Last in sequence PDCP Sequence Number", HFILL
+ }
+ },
+ { &hf_pdcp_lte_bitmap,
+ { "Bitmap",
+ "pdcp.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Status report bitmap (0=error, 1=OK)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_bitmap_not_received,
+ { "Not Received",
+ "pdcp.bitmap.error", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
+ "Status report PDU error", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc,
+ { "ROHC Message",
+ "pdcp.rohc", FT_NONE, BASE_NONE, NULL, 0,
+ "ROHC Message", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_padding,
+ { "Padding",
+ "pdcp.rohc.padding", FT_NONE, BASE_NONE, NULL, 0,
+ "RoHC Padding", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_r_0_crc,
+ { "R-0-CRC Packet",
+ "pdcp.r-0-crc", FT_NONE, BASE_NONE, NULL, 0,
+ "R-0-CRC Packet", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_feedback,
+ { "Feedback",
+ "pdcp.rohc.feedback", FT_NONE, BASE_NONE, NULL, 0,
+ "Feedback Packet", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_type0_t,
+ { "T",
+ "pdcp.rohc.t0.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x20,
+ "Indicates whether frame type is TS (1) or ID (0)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_type1_t,
+ { "T",
+ "pdcp.rohc.t1.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
+ "Indicates whether frame type is TS (1) or ID (0)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_type2_t,
+ { "T",
+ "pdcp.rohc.t2.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
+ "Indicates whether frame type is TS (1) or ID (0)", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_d,
+ { "D",
+ "pdcp.rohc.t2.t", FT_UINT8, BASE_HEX, NULL, 0x01,
+ "Indicates whether Dynamic chain is present", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_ir_crc,
+ { "CRC",
+ "pdcp.rohc.ir.crc", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "8-bit CRC", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_static_ipv4,
+ { "Static IPv4 chain",
+ "pdcp.rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Static IPv4 chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_ip_version,
+ { "IP Version",
+ "pdcp.rohc.ip-version", FT_UINT8, BASE_HEX, NULL, 0xf0,
+ "IP Version", HFILL
+ }
+ },
+ /* TODO: create/use value_string */
+ { &hf_pdcp_lte_rohc_ip_protocol,
+ { "IP Protocol",
+ "pdcp.rohc.ip-protocol", FT_UINT8, BASE_DEC, VALS(ip_protocol_vals), 0x0,
+ "IP Protocol", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_ip_src,
+ { "IP Source address",
+ "pdcp.rohc.ip-src", FT_IPv4, BASE_DEC, NULL, 0x0,
+ "IP Source address", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_ip_dst,
+ { "IP Destination address",
+ "pdcp.rohc.ip-dst", FT_IPv4, BASE_DEC, NULL, 0x0,
+ "IP Destination address", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_static_udp,
+ { "Static UDP chain",
+ "pdcp.rohc.static.udp", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Static UDP chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_static_udp_src_port,
+ { "Static UDP source port",
+ "pdcp.rohc.static.udp.src-port", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Static UDP source port", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_static_udp_dst_port,
+ { "Static UDP destination port",
+ "pdcp.rohc.static.udp.dst-port", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Static UDP destination port", HFILL
+ }
+ },
+
+
+ { &hf_pdcp_lte_rohc_static_rtp,
+ { "Static RTP chain",
+ "pdcp.rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Static RTP chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_static_rtp_ssrc,
+ { "SSRC",
+ "pdcp.rohc.static.rtp.ssrc", FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ "Static RTP chain SSRC", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_dynamic_ipv4,
+ { "Dynamic IPv4 chain",
+ "pdcp.rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Dynamic IPv4 chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_tos,
+ { "ToS",
+ "pdcp.rohc.ip.tos", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "IP Type of Service", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_ttl,
+ { "TTL",
+ "pdcp.rohc.ip.ttl", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "IP Time To Live", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_id,
+ { "IP-ID",
+ "pdcp.rohc.ip.id", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "IP ID", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_df,
+ { "Don't Fragment",
+ "pdcp.rohc.ip.df", FT_UINT8, BASE_HEX, NULL, 0x80,
+ "IP Don't Fragment flag", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_rnd,
+ { "Random IP-ID field",
+ "pdcp.rohc.ip.rnd", FT_UINT8, BASE_HEX, NULL, 0x40,
+ "Random IP-ID field", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_ipv4_nbo,
+ { "Network Byte Order IP-ID field",
+ "pdcp.rohc.ip.nbo", FT_UINT8, BASE_HEX, NULL, 0x20,
+ "Network Byte Order IP-ID field", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_dynamic_udp,
+ { "Dynamic UDP chain",
+ "pdcp.rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Dynamic UDP chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_udp_checksum,
+ { "UDP Checksum",
+ "pdcp.rohc.dynamic.udp.checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
+ "UDP Checksum", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_udp_seqnum,
+ { "UDP Sequence Number",
+ "pdcp.rohc.dynamic.udp.seqnum", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "UDP Sequence Number", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_dynamic_rtp,
+ { "Dynamic RTP chain",
+ "pdcp.rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Dynamic RTP chain", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_rx,
+ { "RX",
+ "pdcp.rohc.dynamic.rtp.rx", FT_UINT8, BASE_DEC, NULL, 0x10,
+ "RX", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_cc,
+ { "Contributing CSRCs",
+ "pdcp.rohc.dynamic.rtp.cc", FT_UINT8, BASE_DEC, NULL, 0x0f,
+ "Dynamic RTP chain CCs", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_seqnum,
+ { "RTP Sequence Number",
+ "pdcp.rohc.dynamic.rtp.seqnum", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Dynamic RTP chain Sequence Number", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_timestamp,
+ { "RTP Timestamp",
+ "pdcp.rohc.dynamic.rtp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Dynamic RTP chain Timestamp", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
+ { "Reserved",
+ "pdcp.rohc.dynamic.rtp.reserved3", FT_UINT8, BASE_HEX, NULL, 0xc0,
+ "Reserved bits", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_x,
+ { "X",
+ "pdcp.rohc.dynamic.rtp.x", FT_UINT8, BASE_DEC, NULL, 0x10,
+ "X", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_mode,
+ { "Mode",
+ "pdcp.rohc.dynamic.rtp.mode", FT_UINT8, BASE_HEX, VALS(rohc_mode_vals), 0x0c,
+ "Mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_tis,
+ { "TIS",
+ "pdcp.rohc.dynamic.rtp.tis", FT_UINT8, BASE_HEX, NULL, 0x02,
+ "Dynamic RTP chain TIS (indicates time_stride present)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_tss,
+ { "TSS",
+ "pdcp.rohc.dynamic.rtp.tss", FT_UINT8, BASE_HEX, NULL, 0x01,
+ "Dynamic RTP chain TSS (indicates TS_stride present)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
+ { "TS Stride",
+ "pdcp.rohc.dynamic.rtp.ts-stride", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Dynamic RTP chain TS Stride", HFILL
+ }
+ },
+ { &hf_pdcp_lte_rohc_ts,
+ { "TS",
+ "pdcp.rohc.ts", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "TS", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_add_cid,
+ { "Add-CID",
+ "pdcp.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
+ "Add-CID", HFILL
+ }
+ },
+ { &hf_pdcp_lte_large_cid,
+ { "Large-CID",
+ "pdcp.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
+ "Large-CID", HFILL
+ }
+ },
+ { &hf_pdcp_lte_uo0_sn,
+ { "SN",
+ "pdcp.rohc.uo0.sn", FT_UINT8, BASE_DEC, NULL, 0x78,
+ "SN", HFILL
+ }
+ },
+ { &hf_pdcp_lte_r0_sn,
+ { "SN",
+ "pdcp.rohc.r0.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
+ "SN", HFILL
+ }
+ },
+ { &hf_pdcp_lte_r0_crc_sn,
+ { "SN",
+ "pdcp.rohc.r0-crc.sn", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "SN", HFILL
+ }
+ },
+ { &hf_pdcp_lte_r0_crc_crc,
+ { "CRC7",
+ "pdcp.rohc.r0-crc.crc", FT_UINT8, BASE_DEC, NULL, 0x7f,
+ "CRC 7", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_feedback_code,
+ { "Code",
+ "pdcp.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
+ "Feedback options length (if > 0)", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_size,
+ { "Size",
+ "pdcp.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Feedback options length", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_feedback1,
+ { "FEEDBACK-1 (SN)",
+ "pdcp.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Feedback-1", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_feedback2,
+ { "FEEDBACK-2",
+ "pdcp.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
+ "Feedback-2", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_feedback_ack_type,
+ { "Acktype",
+ "pdcp.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
+ "Feedback-2 ack type", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_mode,
+ { "mode",
+ "pdcp.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
+ "Feedback mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_sn,
+ { "SN",
+ "pdcp.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
+ "Feedback mode", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_feedback_option,
+ { "Option",
+ "pdcp.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
+ "Feedback mode", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_length,
+ { "Length",
+ "pdcp.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
+ "Feedback length", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_crc,
+ { "CRC",
+ "pdcp.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
+ "Feedback CRC", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_option_sn,
+ { "SN",
+ "pdcp.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Feedback Option SN", HFILL
+ }
+ },
+ { &hf_pdcp_lte_feedback_option_clock,
+ { "Clock",
+ "pdcp.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Feedback Option Clock", HFILL
+ }
+ },
+
+ { &hf_pdcp_lte_ip_id,
+ { "IP-ID",
+ "pdcp.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
+ "IP-ID", HFILL
+ }
+ },
+ { &hf_pdcp_lte_udp_checksum,
+ { "UDP Checksum",
+ "pdcp.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
+ "UDP Checksum", HFILL
+ }
+ },
+ { &hf_pdcp_lte_payload,
+ { "Payload",
+ "pdcp.payload", FT_BYTES, BASE_HEX, NULL, 0x0,
+ "Payload", HFILL
+ }
+ },
+
+ };
+
+ static gint *ett[] =
+ {
+ &ett_pdcp,
+ &ett_pdcp_configuration,
+ &ett_pdcp_packet,
+ &ett_pdcp_rohc,
+ &ett_pdcp_rohc_static_ipv4,
+ &ett_pdcp_rohc_static_udp,
+ &ett_pdcp_rohc_static_rtp,
+ &ett_pdcp_rohc_dynamic_ipv4,
+ &ett_pdcp_rohc_dynamic_udp,
+ &ett_pdcp_rohc_dynamic_rtp
+ };
+
+ module_t *pdcp_lte_module;
+
+ /* Register protocol. */
+ proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
+ proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ /* Allow other dissectors to find this one by name. */
+ register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
+
+ pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, proto_reg_handoff_pdcp_lte);
+
+ /* Dissect uncompressed user-plane data as IP */
+ prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
+ "Show uncompressed User-Plane data as IP",
+ "Show uncompressed User-Plane data as IP",
+ &global_pdcp_dissect_user_plane_as_ip);
+
+#if 0
+ /* Dissect unciphered signalling data as RRC */
+ prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
+ "Show unciphered Signalling-Plane data as RRC",
+ "Show unciphered Signalling-Plane data as RRC",
+ &global_pdcp_dissect_signalling_plane_as_rrc);
+#endif
+
+ /* Attempt to dissect ROHC headers */
+ prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
+ "Attempt to decode ROHC data",
+ "Attempt to decode ROHC data",
+ &global_pdcp_dissect_rohc);
+
+ prefs_register_bool_preference(pdcp_lte_module, "show_feedback_option_tag_length",
+ "Show RoHC feedback option tag & length",
+ "Show RoHC feedback option tag & length",
+ &global_pdcp_show_feedback_option_tag_length);
+}
+
+void proto_reg_handoff_pdcp_lte(void)
+{
+ static gboolean handlesSet = FALSE;
+ if (!handlesSet) {
+ ip_handle = find_dissector("ip");
+ handlesSet = TRUE;
+ }
+}
+