1 /* Routines for LTE PDCP/ROHC
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <epan/packet.h>
31 #include <epan/prefs.h>
32 #include <epan/expert.h>
33 #include <epan/addr_resolv.h>
35 #include "packet-pdcp-lte.h"
38 * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
39 * Packet Data Convergence Protocol (PDCP) specification
41 * RFC 3095 RObust Header Compression (ROHC):
42 * Framework and four profiles: RTP, UDP, ESP, and uncompressed
47 - Update to latest version of 36.323
48 - Complete ROHC support for RTP and extend to other profiles (including ROHCv2)
49 - Support for decryption
50 - Verify MAC authentication bytes
51 - Call LTE RRC dissector for uncompressed, signalling payloads
55 /* Initialize the protocol and registered fields. */
56 int proto_pdcp_lte = -1;
58 /* Configuration (info known outside of PDU) */
59 static int hf_pdcp_lte_configuration = -1;
60 static int hf_pdcp_lte_direction = -1;
61 static int hf_pdcp_lte_rohc = -1;
62 static int hf_pdcp_lte_rohc_compression = -1;
63 static int hf_pdcp_lte_rohc_mode = -1;
64 static int hf_pdcp_lte_rohc_rnd = -1;
65 static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
66 static int hf_pdcp_lte_rohc_profile = -1;
67 static int hf_pdcp_lte_no_header_pdu = -1;
68 static int hf_pdcp_lte_plane = -1;
69 static int hf_pdcp_lte_seqnum_length = -1;
70 static int hf_pdcp_lte_cid_inclusion_info = -1;
71 static int hf_pdcp_lte_large_cid_present = -1;
73 /* PDCP header fields */
74 static int hf_pdcp_lte_seq_num_5 = -1;
75 static int hf_pdcp_lte_seq_num_7 = -1;
76 static int hf_pdcp_lte_reserved3 = -1;
77 static int hf_pdcp_lte_seq_num_12 = -1;
78 static int hf_pdcp_lte_signalling_data = -1;
79 static int hf_pdcp_lte_mac = -1;
80 static int hf_pdcp_lte_data_control = -1;
81 static int hf_pdcp_lte_user_plane_data = -1;
82 static int hf_pdcp_lte_control_pdu_type = -1;
83 static int hf_pdcp_lte_fms = -1;
84 static int hf_pdcp_lte_bitmap = -1;
85 static int hf_pdcp_lte_bitmap_not_received = -1;
87 /* Robust Header Compression Fields */
88 static int hf_pdcp_lte_rohc_padding = -1;
89 static int hf_pdcp_lte_rohc_r_0_crc = -1;
90 static int hf_pdcp_lte_rohc_feedback = -1;
92 static int hf_pdcp_lte_rohc_type0_t = -1;
93 static int hf_pdcp_lte_rohc_type1_t = -1;
94 static int hf_pdcp_lte_rohc_type2_t = -1;
96 static int hf_pdcp_lte_rohc_d = -1;
97 static int hf_pdcp_lte_rohc_ir_crc = -1;
99 static int hf_pdcp_lte_rohc_static_ipv4 = -1;
100 static int hf_pdcp_lte_rohc_ip_version = -1;
101 static int hf_pdcp_lte_rohc_ip_protocol = -1;
102 static int hf_pdcp_lte_rohc_ip_src = -1;
103 static int hf_pdcp_lte_rohc_ip_dst = -1;
105 static int hf_pdcp_lte_rohc_static_udp = -1;
106 static int hf_pdcp_lte_rohc_static_udp_src_port = -1;
107 static int hf_pdcp_lte_rohc_static_udp_dst_port = -1;
109 static int hf_pdcp_lte_rohc_static_rtp = -1;
110 static int hf_pdcp_lte_rohc_static_rtp_ssrc = -1;
112 static int hf_pdcp_lte_rohc_dynamic_ipv4 = -1;
113 static int hf_pdcp_lte_rohc_dynamic_ipv4_tos = -1;
114 static int hf_pdcp_lte_rohc_dynamic_ipv4_ttl = -1;
115 static int hf_pdcp_lte_rohc_dynamic_ipv4_id = -1;
116 static int hf_pdcp_lte_rohc_dynamic_ipv4_df = -1;
117 static int hf_pdcp_lte_rohc_dynamic_ipv4_rnd = -1;
118 static int hf_pdcp_lte_rohc_dynamic_ipv4_nbo = -1;
120 static int hf_pdcp_lte_rohc_dynamic_udp = -1;
121 static int hf_pdcp_lte_rohc_dynamic_udp_checksum = -1;
122 static int hf_pdcp_lte_rohc_dynamic_udp_seqnum = -1;
124 static int hf_pdcp_lte_rohc_dynamic_rtp = -1;
125 static int hf_pdcp_lte_rohc_dynamic_rtp_rx = -1;
126 static int hf_pdcp_lte_rohc_dynamic_rtp_cc = -1;
127 static int hf_pdcp_lte_rohc_dynamic_rtp_seqnum = -1;
128 static int hf_pdcp_lte_rohc_dynamic_rtp_timestamp = -1;
129 static int hf_pdcp_lte_rohc_dynamic_rtp_reserved3 = -1;
130 static int hf_pdcp_lte_rohc_dynamic_rtp_x = -1;
131 static int hf_pdcp_lte_rohc_dynamic_rtp_mode = -1;
132 static int hf_pdcp_lte_rohc_dynamic_rtp_tis = -1;
133 static int hf_pdcp_lte_rohc_dynamic_rtp_tss = -1;
134 static int hf_pdcp_lte_rohc_dynamic_rtp_ts_stride = -1;
136 static int hf_pdcp_lte_rohc_ts = -1;
137 static int hf_pdcp_lte_rohc_m = -1;
138 static int hf_pdcp_lte_rohc_uor2_sn = -1;
139 static int hf_pdcp_lte_rohc_uor2_x = -1;
141 static int hf_pdcp_lte_rohc_add_cid = -1;
142 static int hf_pdcp_lte_rohc_large_cid = -1;
144 static int hf_pdcp_lte_rohc_uo0_sn = -1;
145 static int hf_pdcp_lte_rohc_uo0_crc = -1;
147 static int hf_pdcp_lte_rohc_r0_sn = -1;
148 static int hf_pdcp_lte_rohc_r0_crc_sn = -1;
149 static int hf_pdcp_lte_rohc_r0_crc_crc = -1;
151 static int hf_pdcp_lte_rohc_feedback_code = -1;
152 static int hf_pdcp_lte_rohc_feedback_size = -1;
153 static int hf_pdcp_lte_rohc_feedback_feedback1 = -1;
154 static int hf_pdcp_lte_rohc_feedback_feedback2 = -1;
155 static int hf_pdcp_lte_rohc_feedback_ack_type = -1;
156 static int hf_pdcp_lte_rohc_feedback_mode = -1;
157 static int hf_pdcp_lte_rohc_feedback_sn = -1;
158 static int hf_pdcp_lte_rohc_feedback_option = -1;
159 static int hf_pdcp_lte_rohc_feedback_length = -1;
160 static int hf_pdcp_lte_rohc_feedback_crc = -1;
161 static int hf_pdcp_lte_rohc_feedback_option_sn = -1;
162 static int hf_pdcp_lte_rohc_feedback_option_clock = -1;
164 static int hf_pdcp_lte_rohc_ip_id = -1;
165 static int hf_pdcp_lte_rohc_udp_checksum = -1;
166 static int hf_pdcp_lte_rohc_payload = -1;
169 /* Protocol subtree. */
170 static int ett_pdcp = -1;
171 static int ett_pdcp_configuration = -1;
172 static int ett_pdcp_packet = -1;
173 static int ett_pdcp_rohc = -1;
174 static int ett_pdcp_rohc_static_ipv4 = -1;
175 static int ett_pdcp_rohc_static_udp = -1;
176 static int ett_pdcp_rohc_static_rtp = -1;
177 static int ett_pdcp_rohc_dynamic_ipv4 = -1;
178 static int ett_pdcp_rohc_dynamic_udp = -1;
179 static int ett_pdcp_rohc_dynamic_rtp = -1;
180 static int ett_pdcp_rohc_report_bitmap = -1;
183 static const value_string direction_vals[] =
185 { DIRECTION_UPLINK, "Uplink"},
186 { DIRECTION_DOWNLINK, "Downlink"},
191 static const value_string pdcp_plane_vals[] = {
192 { SIGNALING_PLANE, "Signalling" },
193 { USER_PLANE, "User" },
198 static const value_string rohc_mode_vals[] = {
199 { UNIDIRECTIONAL, "Unidirectional" },
200 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
201 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
207 static const value_string rohc_profile_vals[] = {
208 { 0, "Uncompressed" },
215 static const value_string pdu_type_vals[] = {
216 { 0, "Control PDU" },
221 static const value_string feedback_ack_vals[] = {
224 { 2, "STATIC-NACK" },
228 static const value_string feedback_option_vals[] = {
231 { 3, "SN-Not-Valid" },
239 static const value_string control_pdu_type_vals[] = {
240 { 0, "PDCP Status report" },
241 { 1, "Header Compression Feedback Information" },
245 static const value_string t_vals[] = {
246 { 0, "ID message format" },
247 { 1, "TS message format" },
251 static const value_string ip_protocol_vals[] = {
258 dissector_handle_t ip_handle = 0;
261 /* Preference variables */
262 static gboolean global_pdcp_show_feedback_option_tag_length = FALSE;
263 static gboolean global_pdcp_dissect_user_plane_as_ip = FALSE;
264 static gboolean global_pdcp_dissect_signalling_plane_as_rrc = FALSE;
265 static gboolean global_pdcp_dissect_rohc = FALSE;
267 /* Dissect a Large-CID field.
268 Return following offset */
269 static int dissect_large_cid(proto_tree *tree,
273 guint8 first_octet = tvb_get_guint8(tvb, offset);
275 if ((first_octet & 0x80) == 0) {
277 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 1,
283 guint16 bytes = tvb_get_ntohs(tvb, offset) & 0x7fff;
284 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 2,
291 static int dissect_pdcp_dynamic_chain(proto_tree *tree,
292 proto_item *root_item _U_,
295 struct pdcp_lte_info *p_pdcp_info,
299 if (p_pdcp_info->rohc_ip_version == 4) {
300 proto_tree *dynamic_ipv4_tree;
302 int tree_start_offset = offset;
303 guint8 tos, ttl, id, rnd, nbo;
305 /* Create dynamic IPv4 subtree */
306 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_ipv4, tvb, offset, -1, FALSE);
307 dynamic_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_ipv4);
310 tos = tvb_get_guint8(tvb, offset);
311 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_tos, tvb, offset, 1, FALSE);
315 ttl = tvb_get_guint8(tvb, offset);
316 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_ttl, tvb, offset, 1, FALSE);
320 id = tvb_get_guint8(tvb, offset);
321 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_id, tvb, offset, 1, FALSE);
325 rnd = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
326 nbo = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
327 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_df, tvb, offset, 1, FALSE);
328 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_rnd, tvb, offset, 1, FALSE);
329 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_nbo, tvb, offset, 1, FALSE);
331 /* TODO: general extension header list... */
334 /* Set proper length for subtree */
335 proto_item_set_len(root_ti, offset-tree_start_offset);
337 /* Add summary to root item */
338 proto_item_append_text(root_ti, " (ToS=%u, TTL=%u, ID=%u, RND=%u, NBO=%u)",
339 tos, ttl, id, rnd, nbo);
343 if ((p_pdcp_info->profile == 1) ||
344 (p_pdcp_info->profile == 2)) {
346 proto_tree *dynamic_udp_tree;
348 unsigned short checksum;
350 /* Create dynamic UDP subtree */
351 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_udp, tvb, offset, 2, FALSE);
352 dynamic_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_udp);
354 /* 16-bit checksum */
355 checksum = tvb_get_ntohs(tvb, offset);
356 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_checksum, tvb, offset, 2, FALSE);
359 if (p_pdcp_info->profile == 2) {
362 seqnum = tvb_get_ntohs(tvb, offset);
363 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_seqnum, tvb, offset, 2, FALSE);
366 /* Add summary to root item */
367 proto_item_append_text(root_ti, " (checksum = %04x, seqnum = %u)", checksum, seqnum);
370 /* Add summary to root item */
371 proto_item_append_text(root_ti, " (checksum = %04x)", checksum);
376 if (p_pdcp_info->profile == 1) {
377 proto_tree *dynamic_rtp_tree;
379 int tree_start_offset = offset;
381 guint8 contributing_csrcs;
382 guint16 sequence_number;
387 /* Create dynamic RTP subtree */
388 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_rtp, tvb, offset, -1, FALSE);
389 dynamic_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_rtp);
392 /* V | P | RX | CC */
393 rx = tvb_get_guint8(tvb, offset) & 0x10;
394 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_rx, tvb, offset, 1, FALSE);
395 contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;
396 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_cc, tvb, offset, 1, FALSE);
403 /* Sequence number */
404 sequence_number = tvb_get_ntohs(tvb, offset);
405 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_seqnum, tvb, offset, 2, FALSE);
408 /* Timestamp (4 octets) */
409 timestamp = tvb_get_ntohl(tvb, offset);
410 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_timestamp, tvb, offset, 4, FALSE);
413 /* TODO: CSRC list */
414 /*offset += (4 * contributing_csrcs); */
417 /* TODO: Reserved | X | Mode | TIS | TIS */
419 guint8 this_byte = tvb_get_guint8(tvb, offset);
420 proto_item *reserved_ti = proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
421 tvb, offset, 1, FALSE);
423 /* Check reserved bits are 0 */
424 if ((this_byte & 0xe0) != 0) {
425 expert_add_info_format(pinfo, reserved_ti, PI_MALFORMED, PI_ERROR,
426 "Reserved bits have value 0x%x - should be 0x0",
429 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_x, tvb, offset, 1, FALSE);
430 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_mode, tvb, offset, 1, FALSE);
431 tss = (this_byte & 0x02);
432 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tss, tvb, offset, 1, FALSE);
433 tis = (this_byte & 0x01);
434 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tis, tvb, offset, 1, FALSE);
438 /* TODO: the length of these fields can be learned by looked at the leading bits, see
439 RFC 3095, "4.5.6. Self-describing variable-length values" */
440 /* TODO: TS-Stride (1-4 bytes) */
442 /* Assume encoded in two bytes for now... */
443 proto_tree_add_bits_ret_val(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
444 tvb, offset*8 + 2, 14, &ts_stride, FALSE);
448 /* TODO: Time-stride (1-4 bytes) */
452 /* Set proper length for subtree */
453 proto_item_set_len(root_ti, offset-tree_start_offset);
455 /* Add summary to root item */
456 proto_item_append_text(root_ti, " (seqnum = %u, timestamp = %u)",
457 sequence_number, timestamp);
465 static int dissect_pdcp_irdyn_packet(proto_tree *tree _U_,
466 proto_item *root_item,
469 struct pdcp_lte_info *p_pdcp_info _U_,
472 if (check_col(pinfo->cinfo, COL_INFO)) {
473 col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
475 proto_item_append_text(root_item, " (IRDYN)");
478 if (p_pdcp_info->large_cid_present) {
479 offset = dissect_large_cid(tree, tvb, offset);
483 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
487 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
490 /* Dissect dynamic chain */
491 offset = dissect_pdcp_dynamic_chain(tree,
501 static int dissect_pdcp_ir_packet(proto_tree *tree,
502 proto_item *root_item,
505 struct pdcp_lte_info *p_pdcp_info,
508 unsigned char dynamic_chain_present;
510 if (check_col(pinfo->cinfo, COL_INFO)) {
511 col_append_str(pinfo->cinfo, COL_INFO, " IR");
513 proto_item_append_text(root_item, " (IR)");
515 /* Is dynamic chain present? */
516 dynamic_chain_present = tvb_get_guint8(tvb, offset) & 0x1;
517 proto_tree_add_item(tree, hf_pdcp_lte_rohc_d, tvb, offset, 1, FALSE);
521 if (p_pdcp_info->large_cid_present) {
522 offset = dissect_large_cid(tree, tvb, offset);
526 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
530 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
533 /* IPv4 static part */
534 if (p_pdcp_info->rohc_ip_version == 4) {
535 proto_tree *static_ipv4_tree;
537 int tree_start_offset = offset;
539 guint32 source, dest;
541 /* Create static IPv4 subtree */
542 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_ipv4, tvb, offset, -1, FALSE);
543 static_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_ipv4);
545 /* IP version (must be 4) */
546 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_version, tvb, offset, 1, FALSE);
550 protocol = tvb_get_guint8(tvb, offset);
551 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_protocol, tvb, offset, 1, FALSE);
555 source = tvb_get_ipv4(tvb, offset);
556 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_src, tvb, offset, 4, FALSE);
560 dest = tvb_get_ipv4(tvb, offset);
561 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_dst, tvb, offset, 4, FALSE);
564 /* Set proper length for subtree */
565 proto_item_set_len(root_ti, offset-tree_start_offset);
567 /* Add summary to root item */
568 proto_item_append_text(root_ti, " (prot=%s: %s -> %s)",
569 val_to_str(protocol, ip_protocol_vals, "Unknown"),
570 (char*)get_hostname(source),
571 (char*)get_hostname(dest));
574 /* UDP static part. TODO: also check protocol from last part!? */
575 if ((p_pdcp_info->profile == 1) ||
576 (p_pdcp_info->profile == 2)) {
578 proto_tree *static_udp_tree;
580 int tree_start_offset = offset;
581 unsigned short source_port, dest_port;
583 /* Create static UDP subtree */
584 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_udp, tvb, offset, -1, FALSE);
585 static_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_udp);
588 source_port = tvb_get_ntohs(tvb, offset);
589 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
593 dest_port = tvb_get_ntohs(tvb, offset);
594 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
597 /* Set proper length for subtree */
598 proto_item_set_len(root_ti, offset-tree_start_offset);
600 /* Add summary to root item */
601 proto_item_append_text(root_ti, " (%u -> %u)", source_port, dest_port);
605 if (p_pdcp_info->profile == 1) {
606 proto_tree *static_rtp_tree;
610 /* Create static RTP subtree */
611 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_rtp, tvb, offset, 4, FALSE);
612 static_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_rtp);
615 ssrc = tvb_get_ntohl(tvb, offset);
616 proto_tree_add_item(static_rtp_tree, hf_pdcp_lte_rohc_static_rtp_ssrc, tvb, offset, 4, FALSE);
619 /* Add summary to root item */
620 proto_item_append_text(root_ti, " (SSRC=%u)", ssrc);
625 if (dynamic_chain_present) {
626 offset = dissect_pdcp_dynamic_chain(tree,
639 static int dissect_pdcp_feedback_feedback1(proto_tree *tree,
643 struct pdcp_lte_info *p_pdcp_info _U_,
648 proto_item_append_text(item, " (type 1)");
650 /* TODO: profile-specific */
651 sn = tvb_get_guint8(tvb, offset);
652 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback1, tvb, offset, 1, FALSE);
655 if (check_col(pinfo->cinfo, COL_INFO)) {
656 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
662 /* Includes Large-CID, if present */
663 static int dissect_pdcp_feedback_feedback2(proto_tree *tree,
668 struct pdcp_lte_info *p_pdcp_info _U_,
669 packet_info *pinfo _U_)
676 const char * full_mode_name;
679 proto_item_append_text(item, " (type 2)");
682 if (p_pdcp_info->large_cid_present) {
683 offset = dissect_large_cid(tree, tvb, offset);
686 /* Feedback2 hidden filter */
687 ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback2, tvb, offset, -1, FALSE);
688 PROTO_ITEM_SET_HIDDEN(ti);
691 first_octet = tvb_get_guint8(tvb, offset);
692 ack_type = (first_octet & 0xc0) >> 6;
693 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_ack_type, tvb, offset, 1, FALSE);
695 /* TODO: expert info on NACK? */
698 mode = (first_octet & 0x30) >> 4;
699 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_mode, tvb, offset, 1, FALSE);
701 /* Show ACK-TYPE(Mode) in info column */
702 if (check_col(pinfo->cinfo, COL_INFO)) {
703 full_mode_name = val_to_str(mode, rohc_mode_vals, "Error");
705 col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
706 val_to_str(ack_type, feedback_ack_vals, "Unknown"),
711 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_sn, tvb, offset, 2, FALSE);
712 sn = tvb_get_ntohs(tvb, offset) & 0x7ff;
715 if (check_col(pinfo->cinfo, COL_INFO)) {
716 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
719 /* Loop over any remaining feedback options */
720 size_remaining = size - 2;
722 while (tvb_length_remaining(tvb, offset) > 0) {
723 guint8 option = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
724 guint8 length = tvb_get_guint8(tvb, offset) & 0x0f;
725 guint8 one_byte_value;
727 /* Preference setting controls showing option and lengths */
728 if (global_pdcp_show_feedback_option_tag_length) {
729 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option, tvb, offset, 1, FALSE);
730 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_length, tvb, offset, 1, FALSE);
735 /* TODO: switch including missing option types */
739 one_byte_value = tvb_get_guint8(tvb, offset);
740 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_crc, tvb, offset, 1, FALSE);
741 if (check_col(pinfo->cinfo, COL_INFO)) {
742 col_append_fstr(pinfo->cinfo, COL_INFO, " CRC=%u ", one_byte_value);
749 /* SN-Not-Valid: TODO */
753 one_byte_value = tvb_get_guint8(tvb, offset);
754 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_sn, tvb, offset, 1, FALSE);
755 if (check_col(pinfo->cinfo, COL_INFO)) {
756 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u ", one_byte_value);
761 one_byte_value = tvb_get_guint8(tvb, offset);
762 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_clock, tvb, offset, 1, FALSE);
763 if (check_col(pinfo->cinfo, COL_INFO)) {
764 col_append_fstr(pinfo->cinfo, COL_INFO, " Clock=%u ", one_byte_value);
775 /* TODO: unhandled option */
781 size_remaining -= length;
788 /* Dissect a feedback packet.
789 Return following offset */
790 static int dissect_pdcp_feedback_packet(proto_tree *tree,
791 proto_item *root_item,
794 struct pdcp_lte_info *p_pdcp_info,
800 proto_item *feedback_ti;
801 proto_tree *feedback_tree;
803 if (check_col(pinfo->cinfo, COL_INFO)) {
804 col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
806 proto_item_append_text(root_item, " (Feedback)");
808 /* Create feedback tree root */
809 feedback_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback, tvb, offset, -1, FALSE);
810 feedback_tree = proto_item_add_subtree(feedback_ti, ett_pdcp_packet);
813 code = tvb_get_guint8(tvb, offset) & 0x07;
814 ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_code, tvb, offset, 1, FALSE);
817 /* Optional length field */
819 proto_item_append_text(ti, " (length of feedback data)");
823 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_size, tvb, offset, 1, FALSE);
824 size = tvb_get_guint8(tvb, offset);
828 /* Work out feedback type */
829 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
830 !p_pdcp_info->large_cid_present) {
834 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
836 else if ((size > 1) && ((tvb_get_guint8(tvb, offset) & 0xc0) == 0xc0)) {
838 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
842 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
845 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
849 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
853 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
860 /* Dissect R-0 packet.
861 Return following offset */
862 static int dissect_pdcp_r_0_packet(proto_tree *tree,
863 proto_item *root_item,
866 struct pdcp_lte_info *p_pdcp_info _U_,
871 if (check_col(pinfo->cinfo, COL_INFO)) {
872 col_append_str(pinfo->cinfo, COL_INFO, " R-0");
874 proto_item_append_text(root_item, " (R-0)");
877 sn = tvb_get_guint8(tvb, offset) & 0x3f;
878 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_sn, tvb, offset, 1, FALSE);
882 if (p_pdcp_info->large_cid_present) {
883 offset = dissect_large_cid(tree, tvb, offset);
886 if (check_col(pinfo->cinfo, COL_INFO)) {
887 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
894 /* Dissect R-0-CRC packet.
895 Return following offset */
896 static int dissect_pdcp_r_0_crc_packet(proto_tree *tree,
897 proto_item *root_item,
900 struct pdcp_lte_info *p_pdcp_info,
905 if (check_col(pinfo->cinfo, COL_INFO)) {
906 col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
908 proto_item_append_text(root_item, " (R-0-CRC)");
910 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r_0_crc, tvb, offset, -1, FALSE);
913 /* TODO: wrong! Large-cid may be in-between!!!! */
914 sn = tvb_get_guint8(tvb, offset) & 0x3f;
918 if (p_pdcp_info->large_cid_present) {
919 offset = dissect_large_cid(tree, tvb, offset);
923 sn = (sn << 1) + ((tvb_get_guint8(tvb, offset) & 0x80) >> 7);
924 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_r0_crc_sn, tvb, offset, 1, sn);
927 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_crc_crc, tvb, offset, 1, FALSE);
930 /* Show SN in info column */
931 if (check_col(pinfo->cinfo, COL_INFO)) {
932 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
939 /* Dissect UO-0-CRC packet.
940 Return following offset */
941 static int dissect_pdcp_uo_0_packet(proto_tree *tree,
942 proto_item *root_item,
945 struct pdcp_lte_info *p_pdcp_info,
950 if (check_col(pinfo->cinfo, COL_INFO)) {
951 col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
953 proto_item_append_text(root_item, " (UO-0)");
956 sn = (tvb_get_guint8(tvb, offset) & 0x78) >> 3;
957 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_sn, tvb, offset, 1, FALSE);
960 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_crc, tvb, offset, 1, FALSE);
965 if (p_pdcp_info->large_cid_present) {
966 offset = dissect_large_cid(tree, tvb, offset);
969 /* Show SN in info column */
970 if (check_col(pinfo->cinfo, COL_INFO)) {
971 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
978 /* Dissect R-1 packet.
979 Return following offset */
980 static int dissect_pdcp_r_1_packet(proto_tree *tree,
981 proto_item *root_item,
984 struct pdcp_lte_info *p_pdcp_info,
987 if (check_col(pinfo->cinfo, COL_INFO)) {
988 col_append_str(pinfo->cinfo, COL_INFO, " R-1");
990 proto_item_append_text(root_item, " (R-1)");
992 /* TODO: octet before large-cid */
996 if (p_pdcp_info->large_cid_present) {
997 offset = dissect_large_cid(tree, tvb, offset);
1000 if (p_pdcp_info->profile == 1) {
1003 else if (p_pdcp_info->profile == 2) {
1011 /* Dissect R-1-TS or R-1-ID packet.
1012 Return following offset */
1013 static int dissect_pdcp_r_1_ts_or_id_packet(proto_tree *tree,
1014 proto_item *root_item,
1017 struct pdcp_lte_info *p_pdcp_info,
1022 /* TODO: octet before large-cid */
1026 if (p_pdcp_info->large_cid_present) {
1027 offset = dissect_large_cid(tree, tvb, offset);
1030 /* T determines frame type */
1031 T = tvb_get_guint8(tvb, ++offset) >> 7;
1032 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type1_t, tvb, offset, 1, FALSE);
1034 if (check_col(pinfo->cinfo, COL_INFO)) {
1035 col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
1037 proto_item_append_text(root_item, " (R-1-TS)");
1040 if (check_col(pinfo->cinfo, COL_INFO)) {
1041 col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
1043 proto_item_append_text(root_item, " (R-1-ID)");
1046 if (p_pdcp_info->profile == 1) {
1049 else if (p_pdcp_info->profile == 2) {
1057 /* Dissect UO-1 packet.
1058 Return following offset */
1059 static int dissect_pdcp_uo_1_packet(proto_tree *tree,
1060 proto_item *root_item,
1063 struct pdcp_lte_info *p_pdcp_info,
1066 if (check_col(pinfo->cinfo, COL_INFO)) {
1067 col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
1069 proto_item_append_text(root_item, " (UO-1)");
1071 /* TODO: octet before large-cid */
1075 if (p_pdcp_info->large_cid_present) {
1076 offset = dissect_large_cid(tree, tvb, offset);
1079 if (p_pdcp_info->profile == 1) {
1082 else if (p_pdcp_info->profile == 2) {
1090 /* Dissect UO-1-TS or UO-1-ID packet.
1091 Return following offset */
1092 static int dissect_pdcp_uo_1_ts_or_id_packet(proto_tree *tree,
1093 proto_item *root_item,
1096 struct pdcp_lte_info *p_pdcp_info,
1101 /* TODO: octet before large-cid */
1105 if (p_pdcp_info->large_cid_present) {
1106 offset = dissect_large_cid(tree, tvb, offset);
1109 /* T determines frame type */
1110 T = tvb_get_guint8(tvb, ++offset) >> 5;
1111 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type0_t, tvb, offset, 1, FALSE);
1113 if (check_col(pinfo->cinfo, COL_INFO)) {
1114 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
1116 proto_item_append_text(root_item, " (UO-1-TS)");
1119 if (check_col(pinfo->cinfo, COL_INFO)) {
1120 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
1122 proto_item_append_text(root_item, " (UO-1-ID)");
1125 if (p_pdcp_info->profile == 1) {
1128 else if (p_pdcp_info->profile == 2) {
1139 /* Dissect UOR-2 packet.
1140 Return following offset */
1141 static int dissect_pdcp_uor_2_packet(proto_tree *tree,
1142 proto_item *root_item,
1145 struct pdcp_lte_info *p_pdcp_info,
1150 if (check_col(pinfo->cinfo, COL_INFO)) {
1151 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
1153 proto_item_append_text(root_item, " (UOR-2)");
1155 /* TS straddles CID */
1156 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1160 if (p_pdcp_info->large_cid_present) {
1161 offset = dissect_large_cid(tree, tvb, offset);
1164 /* Last bit of TS is here */
1165 ts = (ts << 1) | (tvb_get_guint8(tvb, offset) >> 7);
1166 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1168 if (p_pdcp_info->profile == 1) {
1170 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, FALSE);
1173 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_sn, tvb, offset, 1, FALSE);
1177 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_x, tvb, offset, 1, FALSE);
1182 else if (p_pdcp_info->profile == 2) {
1191 /* Dissect UOR-2-TS or UOR-2-ID packet.
1192 Return following offset */
1193 static int dissect_pdcp_uor_2_ts_or_id_packet(proto_tree *tree,
1194 proto_item *root_item,
1197 struct pdcp_lte_info *p_pdcp_info,
1202 /* TODO: octet before large-cid.
1203 TODO: can't decode this until we know what T is,
1204 but T is after large-cid... */
1207 /* T determines frame type */
1208 T = tvb_get_guint8(tvb, offset) >> 7;
1209 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type2_t, tvb, offset, 1, FALSE);
1212 if (check_col(pinfo->cinfo, COL_INFO)) {
1213 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
1215 proto_item_append_text(root_item, " (UOR-2-TS)");
1218 if (check_col(pinfo->cinfo, COL_INFO)) {
1219 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
1221 proto_item_append_text(root_item, " (UOR-2-ID)");
1226 /* UOR-2-TS format */
1229 guint8 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1230 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1234 if (p_pdcp_info->large_cid_present) {
1235 offset = dissect_large_cid(tree, tvb, offset);
1239 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, ts);
1244 /* TODO: UOR-2-ID format */
1249 if (p_pdcp_info->large_cid_present) {
1250 offset = dissect_large_cid(tree, tvb, offset);
1256 if (p_pdcp_info->profile == 1) {
1259 else if (p_pdcp_info->profile == 2) {
1269 /* Show in the tree the config info attached to this frame, as generated fields */
1270 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1271 pdcp_lte_info *p_pdcp_info)
1274 proto_tree *configuration_tree;
1275 proto_item *configuration_ti = proto_tree_add_item(tree,
1276 hf_pdcp_lte_configuration,
1278 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
1281 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_direction, tvb, 0, 0,
1282 p_pdcp_info->direction);
1283 PROTO_ITEM_SET_GENERATED(ti);
1286 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
1287 p_pdcp_info->plane);
1288 PROTO_ITEM_SET_GENERATED(ti);
1290 /* User-plane-specific fields */
1291 if (p_pdcp_info->plane == USER_PLANE) {
1294 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
1295 p_pdcp_info->no_header_pdu);
1296 PROTO_ITEM_SET_GENERATED(ti);
1298 if (!p_pdcp_info->no_header_pdu) {
1301 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
1302 p_pdcp_info->seqnum_length);
1303 PROTO_ITEM_SET_GENERATED(ti);
1307 /* ROHC compression */
1308 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
1309 p_pdcp_info->rohc_compression);
1310 PROTO_ITEM_SET_GENERATED(ti);
1312 /* ROHC-specific settings */
1313 if (p_pdcp_info->rohc_compression) {
1315 /* Show ROHC mode */
1316 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
1318 PROTO_ITEM_SET_GENERATED(ti);
1321 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
1323 PROTO_ITEM_SET_GENERATED(ti);
1326 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
1327 p_pdcp_info->udp_checkum_present);
1328 PROTO_ITEM_SET_GENERATED(ti);
1331 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
1332 p_pdcp_info->profile);
1333 PROTO_ITEM_SET_GENERATED(ti);
1335 /* CID Inclusion Info */
1336 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
1337 p_pdcp_info->cid_inclusion_info);
1338 PROTO_ITEM_SET_GENERATED(ti);
1341 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
1342 p_pdcp_info->large_cid_present);
1343 PROTO_ITEM_SET_GENERATED(ti);
1346 /* Append summary to configuration root */
1347 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
1348 val_to_str(p_pdcp_info->direction, direction_vals, "Unknown"),
1349 val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1351 if (p_pdcp_info->rohc_compression) {
1352 const char *mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
1353 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
1355 val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unknown"));
1357 proto_item_append_text(configuration_ti, ")");
1358 PROTO_ITEM_SET_GENERATED(configuration_ti);
1360 /* Show plane in info column */
1361 if (check_col(pinfo->cinfo, COL_INFO)) {
1362 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
1363 val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1369 /* Look for an RRC dissector for signalling data (using channel type and direction) */
1370 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_lte_info *p_pdcp_info)
1372 dissector_handle_t rrc_handle = 0;
1374 switch (p_pdcp_info->channelType)
1377 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1378 rrc_handle = find_dissector("lte-rrc.ul.ccch");
1381 rrc_handle = find_dissector("lte-rrc.dl.ccch");
1385 rrc_handle = find_dissector("lte-rrc.pcch");
1388 switch (p_pdcp_info->BCCHTransport) {
1390 rrc_handle = find_dissector("lte-rrc.bcch.bch");
1392 case DLSCH_TRANSPORT:
1393 rrc_handle = find_dissector("lte-rrc.bcch.dl.sch");
1406 /******************************/
1407 /* Main dissection function. */
1408 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1411 proto_tree *pdcp_tree = NULL;
1412 proto_item *root_ti = NULL;
1413 proto_tree *rohc_tree = NULL;
1414 proto_item *rohc_ti = NULL;
1417 struct pdcp_lte_info *p_pdcp_info;
1418 guint8 base_header_byte;
1419 gboolean udp_checksum_needed = TRUE;
1420 gboolean ip_id_needed = TRUE;
1422 /* Append this protocol name rather than replace. */
1423 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1424 col_add_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
1426 /* Create pdcp tree. */
1428 root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, FALSE);
1429 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1433 /* Look for attached packet info! */
1434 p_pdcp_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1435 /* Can't dissect anything without it... */
1436 if (p_pdcp_info == NULL) {
1441 /* Set mode string */
1442 mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
1444 /* Show configuration (attached packet) info in tree */
1446 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1449 /* Show ROHC mode */
1450 if (p_pdcp_info->rohc_compression &&
1451 check_col(pinfo->cinfo, COL_INFO)) {
1453 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1457 /* Handle PDCP header (if present) */
1458 if (!p_pdcp_info->no_header_pdu) {
1460 /*****************************/
1461 /* Signalling plane messages */
1462 if (p_pdcp_info->plane == SIGNALING_PLANE) {
1464 guint32 data_length;
1466 /* 5-bit sequence number */
1467 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, FALSE);
1468 if (check_col(pinfo->cinfo, COL_INFO)) {
1469 col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u ",
1470 tvb_get_guint8(tvb, offset) & 0x1f);
1475 /* RRC data is all but last 4 bytes.
1476 Call lte-rrc dissector (according to direction and channel type) */
1477 if (global_pdcp_dissect_signalling_plane_as_rrc) {
1478 /* Get appropriate dissector handle */
1479 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1481 if (rrc_handle != 0) {
1482 /* Call RRC dissector if have one */
1483 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
1484 tvb_length_remaining(tvb, offset) - 4,
1485 tvb_length_remaining(tvb, offset) - 4);
1486 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
1489 /* Just show data */
1490 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1491 tvb_length_remaining(tvb, offset) - 4, FALSE);
1495 /* Just show as unparsed data */
1496 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1497 tvb_length_remaining(tvb, offset) - 4, FALSE);
1500 data_length = tvb_length_remaining(tvb, offset) - 4;
1501 offset += data_length;
1503 /* Last 4 bytes are MAC */
1504 mac = tvb_get_ntohl(tvb, offset);
1505 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, FALSE);
1508 if (check_col(pinfo->cinfo, COL_INFO)) {
1509 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
1515 else if (p_pdcp_info->plane == USER_PLANE) {
1517 /**********************************/
1518 /* User-plane messages */
1520 gboolean pdu_type = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
1522 /* Data/Control flag */
1523 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, FALSE);
1525 if (pdu_type == 1) {
1526 /*****************************/
1527 /* Use-plane Data */
1529 /* Number of sequence number bits depends upon config */
1530 if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_7_BITS) {
1531 seqnum = tvb_get_guint8(tvb, offset) & 0x7f;
1532 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, FALSE);
1535 else if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_12_BITS) {
1537 guint8 reserved_value;
1539 /* 3 reserved bits */
1540 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, FALSE);
1541 reserved_value = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
1543 /* Complain if not 0 */
1544 if (reserved_value != 0) {
1545 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
1546 "Reserved bits have value 0x%x - should be 0x0",
1550 /* 12-bit sequence number */
1551 seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
1552 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, FALSE);
1556 /* Not a recognised data format!!!!! */
1560 if (check_col(pinfo->cinfo, COL_INFO)) {
1561 col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%u ", seqnum);
1565 /*******************************/
1566 /* User-plane Control messages */
1567 guint8 control_pdu_type = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
1568 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, FALSE);
1570 switch (control_pdu_type) {
1571 case 0: /* PDCP status report */
1574 guint not_received = 0;
1576 proto_tree *bitmap_tree;
1577 proto_item *bitmap_ti;
1579 /* First-Missing-Sequence SN */
1580 fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
1582 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
1587 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
1589 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_rohc_report_bitmap);
1592 /* For each byte... */
1593 for ( ; tvb_length_remaining(tvb, offset); offset++) {
1594 guint bit_offset = 0;
1595 /* .. look for error (0) in each bit */
1596 for ( ; bit_offset < 8; bit_offset++) {
1597 if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
1598 proto_tree_add_boolean_format_value(bitmap_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
1602 sn = (sn + 1) % 4096;
1606 proto_item_append_text(bitmap_ti, " (not-received=%u)", not_received);
1607 if (check_col(pinfo->cinfo, COL_INFO)) {
1608 col_append_fstr(pinfo->cinfo, COL_INFO,
1609 " Status Report (fms=%u) not-received=%u",
1615 case 1: /* ROHC Feedback */
1617 break; /* Drop-through to dissect feedback */
1619 default: /* Reserved */
1625 /* Invalid plane setting...! */
1626 if (check_col(pinfo->cinfo, COL_INFO)) {
1627 col_append_fstr(pinfo->cinfo, COL_INFO, " - INVALID PLANE (%u)",
1628 p_pdcp_info->plane);
1634 /* Show that its a no-header PDU */
1635 if (check_col(pinfo->cinfo, COL_INFO)) {
1636 col_append_str(pinfo->cinfo, COL_INFO, " No-Header ");
1641 /* If not compressed with ROHC, show as user-plane data */
1642 if (!p_pdcp_info->rohc_compression) {
1644 if (global_pdcp_dissect_user_plane_as_ip && (ip_handle != 0)) {
1645 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset, -1, -1);
1646 call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
1649 if (tvb_length_remaining(tvb, offset) > 0) {
1650 if (p_pdcp_info->plane == USER_PLANE) {
1651 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, FALSE);
1654 if (global_pdcp_dissect_signalling_plane_as_rrc) {
1655 /* Get appropriate dissector handle */
1656 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1658 if (rrc_handle != 0) {
1659 /* Call RRC dissector if have one */
1660 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
1661 tvb_length_remaining(tvb, offset),
1662 tvb_length_remaining(tvb, offset));
1663 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
1666 /* Just show data */
1667 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1668 tvb_length_remaining(tvb, offset), FALSE);
1672 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset, -1, FALSE);
1676 if (check_col(pinfo->cinfo, COL_INFO)) {
1677 col_append_fstr(pinfo->cinfo, COL_INFO, "(%u bytes data)",
1678 tvb_length_remaining(tvb, offset));
1686 /***************************/
1688 /***************************/
1690 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
1691 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
1692 val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unkown"));
1695 /* Only attempt ROHC if configured to */
1696 if (!global_pdcp_dissect_rohc) {
1700 /* Create pdcp tree. */
1702 rohc_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_rohc, tvb, offset, -1, FALSE);
1703 rohc_tree = proto_item_add_subtree(rohc_ti, ett_pdcp_rohc);
1706 rohc_offset = offset;
1708 /* Skip any leading padding octets (11100000) */
1709 while (tvb_get_guint8(tvb, offset) == 0xe0) {
1712 if (offset > rohc_offset) {
1713 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_padding, tvb, rohc_offset,
1714 offset-rohc_offset, FALSE);
1718 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
1719 !p_pdcp_info->large_cid_present)
1721 if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) {
1722 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
1726 /* Assume CID value of 0 if field absent */
1727 proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 0, 0);
1728 PROTO_ITEM_SET_GENERATED(ti);
1732 /* Now look at first octet of base header and identify packet type */
1733 base_header_byte = tvb_get_guint8(tvb, offset);
1736 if ((base_header_byte & 0xfe) == 0xfc) {
1737 offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1738 udp_checksum_needed = FALSE;
1739 ip_id_needed = FALSE;
1742 /* IRDYN (11111000) */
1743 else if (base_header_byte == 0xf8) {
1744 offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1745 udp_checksum_needed = FALSE;
1746 ip_id_needed = FALSE;
1749 /* Feedback (begins with 11110) */
1750 else if (((base_header_byte & 0xf8) >> 3) == 0x1e) {
1751 offset = dissect_pdcp_feedback_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1755 /* Packet type 0 (0) */
1756 else if ((base_header_byte & 0x80) == 0) {
1758 /* TODO: decide type based upon:
1761 - length remaining (taking into account large-cid) */
1763 /* R-0 begins with 00 */
1764 if (((base_header_byte & 0xc0) == 0) &&
1765 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
1767 offset = dissect_pdcp_r_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1770 /* R-0-CRC begins with 01 */
1771 else if ((((base_header_byte & 0x40) >> 6) == 1) &&
1772 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
1774 offset = dissect_pdcp_r_0_crc_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1778 offset = dissect_pdcp_uo_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1782 /* Packet type 1 (10) */
1783 else if (((base_header_byte & 0xc0) >> 6) == 2) {
1785 switch (p_pdcp_info->mode) {
1787 case RELIABLE_BIDIRECTIONAL:
1788 /* R-1 if !(ipv4 && rand) */
1789 if (!((p_pdcp_info->rohc_ip_version == 4) &&
1790 (!p_pdcp_info->rnd))) {
1791 offset = dissect_pdcp_r_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1795 /* Whether its R-1-ID or R-1-TS depends upon T bit */
1796 dissect_pdcp_r_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1801 case UNIDIRECTIONAL:
1802 case OPTIMISTIC_BIDIRECTIONAL:
1803 /* UO-1 if !(ipv4 && rand) */
1804 if (!((p_pdcp_info->rohc_ip_version == 4) &&
1805 (!p_pdcp_info->rnd))) {
1806 offset = dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1810 /* Whether its UO-1-ID or UO-1-TS depends upon T bit */
1811 dissect_pdcp_uo_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1820 /* Packet type 2 (110) */
1821 else if (((base_header_byte & 0xe0) >> 5) == 6) {
1823 /* UOR-2 if !(ipv4 && rand) */
1824 if (!((p_pdcp_info->rohc_ip_version == 4) &&
1825 (!p_pdcp_info->rnd))) {
1827 offset = dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1830 /* Whether its UOR-2-ID or UOR-2-TS depends upon T bit */
1831 dissect_pdcp_uor_2_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
1836 /* Segment (1111111) */
1837 else if ((base_header_byte & 0xfe) == 0xfe) {
1843 /* Fields beyond base header */
1845 /* These 2 fields not present for IR, IR-DYN frames */
1848 if (p_pdcp_info->rnd && ip_id_needed) {
1849 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_ip_id, tvb, offset, 2, FALSE);
1854 if (p_pdcp_info->udp_checkum_present && udp_checksum_needed) {
1855 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_udp_checksum, tvb, offset, 2, FALSE);
1860 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1861 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_payload, tvb, offset, -1, FALSE);
1865 void proto_register_pdcp(void)
1867 static hf_register_info hf[] =
1869 { &hf_pdcp_lte_configuration,
1871 "pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
1872 "Configuation info passed into dissector", HFILL
1876 { &hf_pdcp_lte_rohc_compression,
1877 { "ROHC Compression",
1878 "pdcp-lte.rohc", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1882 { &hf_pdcp_lte_rohc_mode,
1884 "pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
1888 { &hf_pdcp_lte_rohc_rnd,
1889 { "RND", /* TODO: true/false vals? */
1890 "pdcp-lte.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
1891 "RND of outer ip header", HFILL
1894 { &hf_pdcp_lte_rohc_udp_checksum_present,
1895 { "UDP Checksum", /* TODO: true/false vals? */
1896 "pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
1897 "UDP Checksum_present", HFILL
1902 { &hf_pdcp_lte_direction,
1904 "pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1905 "Direction of message", HFILL
1908 { &hf_pdcp_lte_rohc_profile,
1910 "pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
1914 { &hf_pdcp_lte_no_header_pdu,
1916 "pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
1920 { &hf_pdcp_lte_plane,
1922 "pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
1923 "No Header PDU", HFILL
1926 { &hf_pdcp_lte_seqnum_length,
1928 "pdcp-lte.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
1929 "Sequence Number Length", HFILL
1934 { &hf_pdcp_lte_cid_inclusion_info,
1935 { "CID Inclusion Info",
1936 "pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
1940 { &hf_pdcp_lte_large_cid_present,
1941 { "Large CID Present",
1942 "pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
1947 { &hf_pdcp_lte_seq_num_5,
1949 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
1950 "PDCP Seq num", HFILL
1953 { &hf_pdcp_lte_seq_num_7,
1955 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
1956 "PDCP Seq num", HFILL
1959 { &hf_pdcp_lte_reserved3,
1961 "pdcp-lte.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
1962 "3 reserved bits", HFILL
1965 { &hf_pdcp_lte_seq_num_12,
1967 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
1968 "PDCP Seq num", HFILL
1971 { &hf_pdcp_lte_signalling_data,
1972 { "Signalling Data",
1973 "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1979 "pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
1983 { &hf_pdcp_lte_data_control,
1985 "pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
1989 { &hf_pdcp_lte_user_plane_data,
1990 { "User-Plane Data",
1991 "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1995 { &hf_pdcp_lte_control_pdu_type,
1996 { "Control PDU Type",
1997 "pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
1998 "Control PDU type", HFILL
2002 { "First Missing Sequence Number",
2003 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2004 "First Missing PDCP Sequence Number", HFILL
2007 { &hf_pdcp_lte_bitmap,
2009 "pdcp-lte.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
2010 "Status report bitmap (0=error, 1=OK)", HFILL
2013 { &hf_pdcp_lte_bitmap_not_received,
2015 "pdcp-lte.bitmap.error", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2016 "Status report PDU error", HFILL
2020 { &hf_pdcp_lte_rohc,
2022 "pdcp-lte.rohc", FT_NONE, BASE_NONE, NULL, 0,
2027 { &hf_pdcp_lte_rohc_padding,
2029 "pdcp-lte.rohc.padding", FT_NONE, BASE_NONE, NULL, 0,
2030 "ROHC Padding", HFILL
2033 { &hf_pdcp_lte_rohc_r_0_crc,
2035 "pdcp-lte.r-0-crc", FT_NONE, BASE_NONE, NULL, 0,
2039 { &hf_pdcp_lte_rohc_feedback,
2041 "pdcp-lte.rohc.feedback", FT_NONE, BASE_NONE, NULL, 0,
2042 "Feedback Packet", HFILL
2046 { &hf_pdcp_lte_rohc_type0_t,
2048 "pdcp-lte.rohc.t0.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x20,
2049 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2052 { &hf_pdcp_lte_rohc_type1_t,
2054 "pdcp-lte.rohc.t1.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2055 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2058 { &hf_pdcp_lte_rohc_type2_t,
2060 "pdcp-lte.rohc.t2.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2061 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2065 { &hf_pdcp_lte_rohc_d,
2067 "pdcp-lte.rohc.t2.t", FT_UINT8, BASE_HEX, NULL, 0x01,
2068 "Indicates whether Dynamic chain is present", HFILL
2071 { &hf_pdcp_lte_rohc_ir_crc,
2073 "pdcp-lte.rohc.ir.crc", FT_UINT8, BASE_HEX, NULL, 0x0,
2078 { &hf_pdcp_lte_rohc_static_ipv4,
2079 { "Static IPv4 chain",
2080 "pdcp-lte.rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2084 { &hf_pdcp_lte_rohc_ip_version,
2086 "pdcp-lte.rohc.ip-version", FT_UINT8, BASE_HEX, NULL, 0xf0,
2090 /* TODO: create/use value_string */
2091 { &hf_pdcp_lte_rohc_ip_protocol,
2093 "pdcp-lte.rohc.ip-protocol", FT_UINT8, BASE_DEC, VALS(ip_protocol_vals), 0x0,
2097 { &hf_pdcp_lte_rohc_ip_src,
2098 { "IP Source address",
2099 "pdcp-lte.rohc.ip-src", FT_IPv4, BASE_NONE, NULL, 0x0,
2103 { &hf_pdcp_lte_rohc_ip_dst,
2104 { "IP Destination address",
2105 "pdcp-lte.rohc.ip-dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2110 { &hf_pdcp_lte_rohc_static_udp,
2111 { "Static UDP chain",
2112 "pdcp-lte.rohc.static.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2116 { &hf_pdcp_lte_rohc_static_udp_src_port,
2117 { "Static UDP source port",
2118 "pdcp-lte.rohc.static.udp.src-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2122 { &hf_pdcp_lte_rohc_static_udp_dst_port,
2123 { "Static UDP destination port",
2124 "pdcp-lte.rohc.static.udp.dst-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2130 { &hf_pdcp_lte_rohc_static_rtp,
2131 { "Static RTP chain",
2132 "pdcp-lte.rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2136 { &hf_pdcp_lte_rohc_static_rtp_ssrc,
2138 "pdcp-lte.rohc.static.rtp.ssrc", FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2139 "Static RTP chain SSRC", HFILL
2143 { &hf_pdcp_lte_rohc_dynamic_ipv4,
2144 { "Dynamic IPv4 chain",
2145 "pdcp-lte.rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2149 { &hf_pdcp_lte_rohc_dynamic_ipv4_tos,
2151 "pdcp-lte.rohc.ip.tos", FT_UINT8, BASE_HEX, NULL, 0x0,
2152 "IP Type of Service", HFILL
2155 { &hf_pdcp_lte_rohc_dynamic_ipv4_ttl,
2157 "pdcp-lte.rohc.ip.ttl", FT_UINT8, BASE_HEX, NULL, 0x0,
2158 "IP Time To Live", HFILL
2161 { &hf_pdcp_lte_rohc_dynamic_ipv4_id,
2163 "pdcp-lte.rohc.ip.id", FT_UINT8, BASE_HEX, NULL, 0x0,
2167 { &hf_pdcp_lte_rohc_dynamic_ipv4_df,
2169 "pdcp-lte.rohc.ip.df", FT_UINT8, BASE_HEX, NULL, 0x80,
2170 "IP Don't Fragment flag", HFILL
2173 { &hf_pdcp_lte_rohc_dynamic_ipv4_rnd,
2174 { "Random IP-ID field",
2175 "pdcp-lte.rohc.ip.rnd", FT_UINT8, BASE_HEX, NULL, 0x40,
2179 { &hf_pdcp_lte_rohc_dynamic_ipv4_nbo,
2180 { "Network Byte Order IP-ID field",
2181 "pdcp-lte.rohc.ip.nbo", FT_UINT8, BASE_HEX, NULL, 0x20,
2186 { &hf_pdcp_lte_rohc_dynamic_udp,
2187 { "Dynamic UDP chain",
2188 "pdcp-lte.rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2192 { &hf_pdcp_lte_rohc_dynamic_udp_checksum,
2194 "pdcp-lte.rohc.dynamic.udp.checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2198 { &hf_pdcp_lte_rohc_dynamic_udp_seqnum,
2199 { "UDP Sequence Number",
2200 "pdcp-lte.rohc.dynamic.udp.seqnum", FT_UINT16, BASE_HEX, NULL, 0x0,
2205 { &hf_pdcp_lte_rohc_dynamic_rtp,
2206 { "Dynamic RTP chain",
2207 "pdcp-lte.rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2211 { &hf_pdcp_lte_rohc_dynamic_rtp_rx,
2213 "pdcp-lte.rohc.dynamic.rtp.rx", FT_UINT8, BASE_DEC, NULL, 0x10,
2217 { &hf_pdcp_lte_rohc_dynamic_rtp_cc,
2218 { "Contributing CSRCs",
2219 "pdcp-lte.rohc.dynamic.rtp.cc", FT_UINT8, BASE_DEC, NULL, 0x0f,
2220 "Dynamic RTP chain CCs", HFILL
2223 { &hf_pdcp_lte_rohc_dynamic_rtp_seqnum,
2224 { "RTP Sequence Number",
2225 "pdcp-lte.rohc.dynamic.rtp.seqnum", FT_UINT16, BASE_DEC, NULL, 0x0,
2226 "Dynamic RTP chain Sequence Number", HFILL
2229 { &hf_pdcp_lte_rohc_dynamic_rtp_timestamp,
2231 "pdcp-lte.rohc.dynamic.rtp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
2232 "Dynamic RTP chain Timestamp", HFILL
2236 { &hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
2238 "pdcp-lte.rohc.dynamic.rtp.reserved3", FT_UINT8, BASE_HEX, NULL, 0xc0,
2239 "Reserved bits", HFILL
2242 { &hf_pdcp_lte_rohc_dynamic_rtp_x,
2244 "pdcp-lte.rohc.dynamic.rtp.x", FT_UINT8, BASE_DEC, NULL, 0x10,
2248 { &hf_pdcp_lte_rohc_dynamic_rtp_mode,
2250 "pdcp-lte.rohc.dynamic.rtp.mode", FT_UINT8, BASE_HEX, VALS(rohc_mode_vals), 0x0c,
2254 { &hf_pdcp_lte_rohc_dynamic_rtp_tis,
2256 "pdcp-lte.rohc.dynamic.rtp.tis", FT_UINT8, BASE_HEX, NULL, 0x02,
2257 "Dynamic RTP chain TIS (indicates time_stride present)", HFILL
2260 { &hf_pdcp_lte_rohc_dynamic_rtp_tss,
2262 "pdcp-lte.rohc.dynamic.rtp.tss", FT_UINT8, BASE_HEX, NULL, 0x01,
2263 "Dynamic RTP chain TSS (indicates TS_stride present)", HFILL
2266 { &hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
2268 "pdcp-lte.rohc.dynamic.rtp.ts-stride", FT_UINT32, BASE_DEC, NULL, 0x0,
2269 "Dynamic RTP chain TS Stride", HFILL
2272 { &hf_pdcp_lte_rohc_ts,
2274 "pdcp-lte.rohc.ts", FT_UINT8, BASE_DEC, NULL, 0x0,
2278 { &hf_pdcp_lte_rohc_m,
2280 "pdcp-lte.rohc.m", FT_UINT8, BASE_DEC, NULL, 0x40,
2284 { &hf_pdcp_lte_rohc_uor2_sn,
2286 "pdcp-lte.rohc.uor2.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2290 { &hf_pdcp_lte_rohc_uor2_x,
2292 "pdcp-lte.rohc.uor2.x", FT_UINT8, BASE_DEC, NULL, 0x80,
2297 { &hf_pdcp_lte_rohc_add_cid,
2299 "pdcp-lte.rohc.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
2303 { &hf_pdcp_lte_rohc_large_cid,
2305 "pdcp-lte.rohc.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
2309 { &hf_pdcp_lte_rohc_uo0_sn,
2311 "pdcp-lte.rohc.uo0.sn", FT_UINT8, BASE_DEC, NULL, 0x78,
2315 { &hf_pdcp_lte_rohc_uo0_crc,
2317 "pdcp-lte.rohc.uo0.crc", FT_UINT8, BASE_DEC, NULL, 0x07,
2321 { &hf_pdcp_lte_rohc_r0_sn,
2323 "pdcp-lte.rohc.r0.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2327 { &hf_pdcp_lte_rohc_r0_crc_sn,
2329 "pdcp-lte.rohc.r0-crc.sn", FT_UINT16, BASE_DEC, NULL, 0x0,
2333 { &hf_pdcp_lte_rohc_r0_crc_crc,
2335 "pdcp-lte.rohc.r0-crc.crc", FT_UINT8, BASE_DEC, NULL, 0x7f,
2340 { &hf_pdcp_lte_rohc_feedback_code,
2342 "pdcp-lte.rohc.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
2343 "Feedback options length (if > 0)", HFILL
2346 { &hf_pdcp_lte_rohc_feedback_size,
2348 "pdcp-lte.rohc.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
2349 "Feedback options length", HFILL
2352 { &hf_pdcp_lte_rohc_feedback_feedback1,
2353 { "FEEDBACK-1 (SN)",
2354 "pdcp-lte.rohc.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
2358 { &hf_pdcp_lte_rohc_feedback_feedback2,
2360 "pdcp-lte.rohc.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
2365 { &hf_pdcp_lte_rohc_feedback_ack_type,
2367 "pdcp-lte.rohc.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
2368 "Feedback-2 ack type", HFILL
2371 { &hf_pdcp_lte_rohc_feedback_mode,
2373 "pdcp-lte.rohc.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
2374 "Feedback mode", HFILL
2377 { &hf_pdcp_lte_rohc_feedback_sn,
2379 "pdcp-lte.rohc.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2380 "Feedback mode", HFILL
2384 { &hf_pdcp_lte_rohc_feedback_option,
2386 "pdcp-lte.rohc.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
2387 "Feedback mode", HFILL
2390 { &hf_pdcp_lte_rohc_feedback_length,
2392 "pdcp-lte.rohc.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
2393 "Feedback length", HFILL
2396 { &hf_pdcp_lte_rohc_feedback_crc,
2398 "pdcp-lte.rohc.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
2399 "Feedback CRC", HFILL
2402 { &hf_pdcp_lte_rohc_feedback_option_sn,
2404 "pdcp-lte.rohc.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
2405 "Feedback Option SN", HFILL
2408 { &hf_pdcp_lte_rohc_feedback_option_clock,
2410 "pdcp-lte.rohc.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
2411 "Feedback Option Clock", HFILL
2415 { &hf_pdcp_lte_rohc_ip_id,
2417 "pdcp-lte.rohc.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2421 { &hf_pdcp_lte_rohc_udp_checksum,
2423 "pdcp-lte.rohc.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2427 { &hf_pdcp_lte_rohc_payload,
2429 "pdcp-lte.rohc.payload", FT_BYTES, BASE_NONE, NULL, 0x0,
2436 static gint *ett[] =
2439 &ett_pdcp_configuration,
2442 &ett_pdcp_rohc_static_ipv4,
2443 &ett_pdcp_rohc_static_udp,
2444 &ett_pdcp_rohc_static_rtp,
2445 &ett_pdcp_rohc_dynamic_ipv4,
2446 &ett_pdcp_rohc_dynamic_udp,
2447 &ett_pdcp_rohc_dynamic_rtp,
2448 &ett_pdcp_rohc_report_bitmap
2451 module_t *pdcp_lte_module;
2453 /* Register protocol. */
2454 proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
2455 proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
2456 proto_register_subtree_array(ett, array_length(ett));
2458 /* Allow other dissectors to find this one by name. */
2459 register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
2461 pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, NULL);
2463 /* Dissect uncompressed user-plane data as IP */
2464 prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
2465 "Show uncompressed User-Plane data as IP",
2466 "Show uncompressed User-Plane data as IP",
2467 &global_pdcp_dissect_user_plane_as_ip);
2469 /* Dissect unciphered signalling data as RRC */
2470 prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
2471 "Show unciphered Signalling-Plane data as RRC",
2472 "Show unciphered Signalling-Plane data as RRC",
2473 &global_pdcp_dissect_signalling_plane_as_rrc);
2475 /* Attempt to dissect ROHC headers */
2476 prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
2477 "Attempt to decode ROHC data",
2478 "Attempt to decode ROHC data",
2479 &global_pdcp_dissect_rohc);
2481 prefs_register_bool_preference(pdcp_lte_module, "show_feedback_option_tag_length",
2482 "Show ROHC feedback option tag & length",
2483 "Show ROHC feedback option tag & length",
2484 &global_pdcp_show_feedback_option_tag_length);
2487 void proto_reg_handoff_pdcp_lte(void)
2489 ip_handle = find_dissector("ip");