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.
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/expert.h>
35 #include <epan/addr_resolv.h>
37 #include "packet-pdcp-lte.h"
40 * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
41 * Packet Data Convergence Protocol (PDCP) specification
43 * RFC 3095 RObust Header Compression (ROHC):
44 * Framework and four profiles: RTP, UDP, ESP, and uncompressed
49 - Complete ROHC support for RTP and extend to other profiles (including ROHCv2)
50 - Support for deciphering
51 - Verify MAC authentication bytes
55 /* Initialize the protocol and registered fields. */
56 int proto_pdcp_lte = -1;
58 extern int proto_rlc_lte;
60 /* Configuration (info known outside of PDU) */
61 static int hf_pdcp_lte_configuration = -1;
62 static int hf_pdcp_lte_direction = -1;
63 static int hf_pdcp_lte_ueid = -1;
64 static int hf_pdcp_lte_channel_type = -1;
65 static int hf_pdcp_lte_channel_id = -1;
66 static int hf_pdcp_lte_rohc = -1;
67 static int hf_pdcp_lte_rohc_compression = -1;
68 static int hf_pdcp_lte_rohc_mode = -1;
69 static int hf_pdcp_lte_rohc_rnd = -1;
70 static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
71 static int hf_pdcp_lte_rohc_profile = -1;
72 static int hf_pdcp_lte_no_header_pdu = -1;
73 static int hf_pdcp_lte_plane = -1;
74 static int hf_pdcp_lte_seqnum_length = -1;
75 static int hf_pdcp_lte_cid_inclusion_info = -1;
76 static int hf_pdcp_lte_large_cid_present = -1;
78 /* PDCP header fields */
79 static int hf_pdcp_lte_seq_num_5 = -1;
80 static int hf_pdcp_lte_seq_num_7 = -1;
81 static int hf_pdcp_lte_reserved3 = -1;
82 static int hf_pdcp_lte_seq_num_12 = -1;
83 static int hf_pdcp_lte_signalling_data = -1;
84 static int hf_pdcp_lte_mac = -1;
85 static int hf_pdcp_lte_data_control = -1;
86 static int hf_pdcp_lte_user_plane_data = -1;
87 static int hf_pdcp_lte_control_pdu_type = -1;
88 static int hf_pdcp_lte_fms = -1;
89 static int hf_pdcp_lte_bitmap = -1;
90 static int hf_pdcp_lte_bitmap_not_received = -1;
92 /* Robust Header Compression Fields */
93 static int hf_pdcp_lte_rohc_padding = -1;
94 static int hf_pdcp_lte_rohc_r_0_crc = -1;
95 static int hf_pdcp_lte_rohc_feedback = -1;
97 static int hf_pdcp_lte_rohc_type0_t = -1;
98 static int hf_pdcp_lte_rohc_type1_t = -1;
99 static int hf_pdcp_lte_rohc_type2_t = -1;
101 static int hf_pdcp_lte_rohc_d = -1;
102 static int hf_pdcp_lte_rohc_ir_crc = -1;
104 static int hf_pdcp_lte_rohc_static_ipv4 = -1;
105 static int hf_pdcp_lte_rohc_ip_version = -1;
106 static int hf_pdcp_lte_rohc_ip_protocol = -1;
107 static int hf_pdcp_lte_rohc_ip_src = -1;
108 static int hf_pdcp_lte_rohc_ip_dst = -1;
110 static int hf_pdcp_lte_rohc_static_udp = -1;
111 static int hf_pdcp_lte_rohc_static_udp_src_port = -1;
112 static int hf_pdcp_lte_rohc_static_udp_dst_port = -1;
114 static int hf_pdcp_lte_rohc_static_rtp = -1;
115 static int hf_pdcp_lte_rohc_static_rtp_ssrc = -1;
117 static int hf_pdcp_lte_rohc_dynamic_ipv4 = -1;
118 static int hf_pdcp_lte_rohc_dynamic_ipv4_tos = -1;
119 static int hf_pdcp_lte_rohc_dynamic_ipv4_ttl = -1;
120 static int hf_pdcp_lte_rohc_dynamic_ipv4_id = -1;
121 static int hf_pdcp_lte_rohc_dynamic_ipv4_df = -1;
122 static int hf_pdcp_lte_rohc_dynamic_ipv4_rnd = -1;
123 static int hf_pdcp_lte_rohc_dynamic_ipv4_nbo = -1;
125 static int hf_pdcp_lte_rohc_dynamic_udp = -1;
126 static int hf_pdcp_lte_rohc_dynamic_udp_checksum = -1;
127 static int hf_pdcp_lte_rohc_dynamic_udp_seqnum = -1;
129 static int hf_pdcp_lte_rohc_dynamic_rtp = -1;
130 static int hf_pdcp_lte_rohc_dynamic_rtp_rx = -1;
131 static int hf_pdcp_lte_rohc_dynamic_rtp_cc = -1;
132 static int hf_pdcp_lte_rohc_dynamic_rtp_seqnum = -1;
133 static int hf_pdcp_lte_rohc_dynamic_rtp_timestamp = -1;
134 static int hf_pdcp_lte_rohc_dynamic_rtp_reserved3 = -1;
135 static int hf_pdcp_lte_rohc_dynamic_rtp_x = -1;
136 static int hf_pdcp_lte_rohc_dynamic_rtp_mode = -1;
137 static int hf_pdcp_lte_rohc_dynamic_rtp_tis = -1;
138 static int hf_pdcp_lte_rohc_dynamic_rtp_tss = -1;
139 static int hf_pdcp_lte_rohc_dynamic_rtp_ts_stride = -1;
141 static int hf_pdcp_lte_rohc_ts = -1;
142 static int hf_pdcp_lte_rohc_m = -1;
143 static int hf_pdcp_lte_rohc_uor2_sn = -1;
144 static int hf_pdcp_lte_rohc_uor2_x = -1;
146 static int hf_pdcp_lte_rohc_add_cid = -1;
147 static int hf_pdcp_lte_rohc_large_cid = -1;
149 static int hf_pdcp_lte_rohc_uo0_sn = -1;
150 static int hf_pdcp_lte_rohc_uo0_crc = -1;
152 static int hf_pdcp_lte_rohc_r0_sn = -1;
153 static int hf_pdcp_lte_rohc_r0_crc_sn = -1;
154 static int hf_pdcp_lte_rohc_r0_crc_crc = -1;
156 static int hf_pdcp_lte_rohc_feedback_code = -1;
157 static int hf_pdcp_lte_rohc_feedback_size = -1;
158 static int hf_pdcp_lte_rohc_feedback_feedback1 = -1;
159 static int hf_pdcp_lte_rohc_feedback_feedback2 = -1;
160 static int hf_pdcp_lte_rohc_feedback_ack_type = -1;
161 static int hf_pdcp_lte_rohc_feedback_mode = -1;
162 static int hf_pdcp_lte_rohc_feedback_sn = -1;
163 static int hf_pdcp_lte_rohc_feedback_option = -1;
164 static int hf_pdcp_lte_rohc_feedback_length = -1;
165 static int hf_pdcp_lte_rohc_feedback_crc = -1;
166 static int hf_pdcp_lte_rohc_feedback_option_sn = -1;
167 static int hf_pdcp_lte_rohc_feedback_option_clock = -1;
169 static int hf_pdcp_lte_rohc_ip_id = -1;
170 static int hf_pdcp_lte_rohc_udp_checksum = -1;
171 static int hf_pdcp_lte_rohc_payload = -1;
173 /* Sequence Analysis */
174 static int hf_pdcp_lte_sequence_analysis = -1;
175 static int hf_pdcp_lte_sequence_analysis_ok = -1;
176 static int hf_pdcp_lte_sequence_analysis_previous_frame = -1;
177 static int hf_pdcp_lte_sequence_analysis_expected_sn = -1;
179 static int hf_pdcp_lte_sequence_analysis_repeated = -1;
180 static int hf_pdcp_lte_sequence_analysis_skipped = -1;
185 /* Protocol subtree. */
186 static int ett_pdcp = -1;
187 static int ett_pdcp_configuration = -1;
188 static int ett_pdcp_packet = -1;
189 static int ett_pdcp_lte_sequence_analysis = -1;
190 static int ett_pdcp_rohc = -1;
191 static int ett_pdcp_rohc_static_ipv4 = -1;
192 static int ett_pdcp_rohc_static_udp = -1;
193 static int ett_pdcp_rohc_static_rtp = -1;
194 static int ett_pdcp_rohc_dynamic_ipv4 = -1;
195 static int ett_pdcp_rohc_dynamic_udp = -1;
196 static int ett_pdcp_rohc_dynamic_rtp = -1;
197 static int ett_pdcp_rohc_report_bitmap = -1;
200 static const value_string direction_vals[] =
202 { DIRECTION_UPLINK, "Uplink"},
203 { DIRECTION_DOWNLINK, "Downlink"},
208 static const value_string pdcp_plane_vals[] = {
209 { SIGNALING_PLANE, "Signalling" },
210 { USER_PLANE, "User" },
214 static const value_string logical_channel_vals[] = {
215 { Channel_DCCH, "DCCH"},
216 { Channel_BCCH, "BCCH"},
217 { Channel_CCCH, "CCCH"},
218 { Channel_PCCH, "PCCH"},
222 static const value_string rohc_mode_vals[] = {
223 { UNIDIRECTIONAL, "Unidirectional" },
224 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
225 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
230 /* Values taken from:
231 http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
232 static const value_string rohc_profile_vals[] = {
233 { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
234 { 0x0001, "ROHC RTP" }, /* [RFC3095] */
235 { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
236 { 0x0002, "ROHC UDP" }, /* [RFC3095] */
237 { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
238 { 0x0003, "ROHC ESP" }, /* [RFC3095] */
239 { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
240 { 0x0004, "ROHC IP" }, /* [RFC3843] */
241 { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
242 { 0x0005, "ROHC LLA" }, /* [RFC4362] */
243 { 0x0105, "ROHC LLA with R-mode" }, /* [RFC3408] */
244 { 0x0006, "ROHC TCP" }, /* [RFC4996] */
245 { 0x0007, "ROHC RTP/UDP-Lite" }, /* [RFC4019] */
246 { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /* [RFC5225] */
247 { 0x0008, "ROHC UDP-Lite" }, /* [RFC4019] */
248 { 0x0108, "ROHCv2 UDP-Lite" }, /* [RFC5225] */
252 static const value_string pdu_type_vals[] = {
253 { 0, "Control PDU" },
258 static const value_string feedback_ack_vals[] = {
261 { 2, "STATIC-NACK" },
265 static const value_string feedback_option_vals[] = {
268 { 3, "SN-Not-Valid" },
276 static const value_string control_pdu_type_vals[] = {
277 { 0, "PDCP Status report" },
278 { 1, "Header Compression Feedback Information" },
282 static const value_string t_vals[] = {
283 { 0, "ID message format" },
284 { 1, "TS message format" },
288 static const value_string ip_protocol_vals[] = {
295 static dissector_handle_t ip_handle;
296 static dissector_handle_t ipv6_handle;
297 static dissector_handle_t data_handle;
299 /* Preference variables */
300 static gboolean global_pdcp_show_feedback_option_tag_length = FALSE;
301 static gboolean global_pdcp_dissect_user_plane_as_ip = FALSE;
302 static gboolean global_pdcp_dissect_signalling_plane_as_rrc = FALSE;
303 static gboolean global_pdcp_check_sequence_numbers = FALSE;
304 static gboolean global_pdcp_dissect_rohc = FALSE;
307 /**************************************************/
308 /* Sequence number analysis */
314 LogicalChannelType channelType;
317 } pdcp_channel_hash_key;
322 guint16 previousSequenceNumber;
323 guint32 previousFrameNum;
324 } pdcp_channel_status;
326 /* The sequence analysis channel hash table.
327 Maps key -> status */
328 static GHashTable *pdcp_sequence_analysis_channel_hash = NULL;
331 static gint pdcp_channel_equal(gconstpointer v, gconstpointer v2)
333 const pdcp_channel_hash_key* val1 = v;
334 const pdcp_channel_hash_key* val2 = v2;
336 /* All fields must match */
337 return (memcmp(val1, val2, sizeof(pdcp_channel_hash_key)) == 0);
340 /* Compute a hash value for a given key. */
341 static guint pdcp_channel_hash_func(gconstpointer v)
343 const pdcp_channel_hash_key* val1 = v;
345 /* TODO: use multipliers */
346 return val1->ueId + val1->channelType + val1->channelId + val1->direction;
349 /* Hash table functions for frame reports */
351 /* TODO: copied from packet-rlc-lte.c. extern, or add to lib? */
353 static gint pdcp_frame_equal(gconstpointer v, gconstpointer v2)
358 /* Compute a hash value for a given key. */
359 static guint pdcp_frame_hash_func(gconstpointer v)
361 return GPOINTER_TO_UINT(v);
365 /* Info to attach to frame when first read, recording what to show about sequence */
368 gboolean sequenceExpectedCorrect;
369 guint16 sequenceExpected;
370 guint32 previousFrameNum;
375 enum { SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing} state;
376 } pdcp_sequence_report_in_frame;
378 /* The sequence analysis frame report hash table instance itself */
379 static GHashTable *pdcp_lte_frame_sequence_analysis_report_hash = NULL;
382 /* Add to the tree values associated with sequence analysis for this frame */
383 static void addChannelSequenceInfo(pdcp_sequence_report_in_frame *p,
384 pdcp_lte_info *p_pdcp_lte_info,
385 guint16 sequenceNumber,
386 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
388 proto_tree *seqnum_tree;
389 proto_item *seqnum_ti;
393 seqnum_ti = proto_tree_add_string_format(tree,
394 hf_pdcp_lte_sequence_analysis,
396 "", "Sequence Analysis");
397 seqnum_tree = proto_item_add_subtree(seqnum_ti,
398 ett_pdcp_lte_sequence_analysis);
399 PROTO_ITEM_SET_GENERATED(seqnum_ti);
402 /* Previous channel frame */
403 if (p->previousFrameNum != 0) {
404 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_previous_frame,
405 tvb, 0, 0, p->previousFrameNum);
408 /* Expected sequence number */
409 ti = proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_expected_sn,
410 tvb, 0, 0, p->sequenceExpected);
411 PROTO_ITEM_SET_GENERATED(ti);
413 /* Make sure we have recognised SN length */
414 switch (p_pdcp_lte_info->seqnum_length) {
415 case PDCP_SN_LENGTH_5_BITS:
416 case PDCP_SN_LENGTH_7_BITS:
417 case PDCP_SN_LENGTH_12_BITS:
420 DISSECTOR_ASSERT_NOT_REACHED();
426 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
428 PROTO_ITEM_SET_GENERATED(ti);
429 proto_item_append_text(seqnum_ti, " - OK");
433 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
435 PROTO_ITEM_SET_GENERATED(ti);
436 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_skipped,
438 PROTO_ITEM_SET_GENERATED(ti);
439 if (p->lastSN != p->firstSN) {
440 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
441 "PDCP SNs (%u to %u) missing for %s on UE %u",
442 p->firstSN, p->lastSN,
443 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
444 p_pdcp_lte_info->ueid);
445 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
446 p->firstSN, p->lastSN);
449 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
450 "PDCP SN (%u) missing for %s on UE %u",
452 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
453 p_pdcp_lte_info->ueid);
454 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
460 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
462 PROTO_ITEM_SET_GENERATED(ti);
463 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_repeated,
465 PROTO_ITEM_SET_GENERATED(ti);
466 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
467 "PDCP SN (%u) repeated for %s for UE %u",
469 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
470 p_pdcp_lte_info->ueid);
471 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
476 /* Incorrect sequence number */
477 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
478 "Wrong Sequence Number for %s on UE %u - got %u, expected %u",
479 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
480 p_pdcp_lte_info->ueid, sequenceNumber, p->sequenceExpected);
486 /* Update the channel status and set report for this frame */
487 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
488 pdcp_lte_info *p_pdcp_lte_info,
489 guint16 sequenceNumber,
492 pdcp_channel_hash_key channel_key;
493 pdcp_channel_hash_key *p_channel_key;
494 pdcp_channel_status *p_channel_status;
495 pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
496 gboolean createdChannel = FALSE;
497 guint16 expectedSequenceNumber = 0;
500 /* If find stat_report_in_frame already, use that and get out */
501 if (pinfo->fd->flags.visited) {
502 p_report_in_frame = (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_frame_sequence_analysis_report_hash,
504 if (p_report_in_frame != NULL) {
505 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info,
511 /* Give up - we must have tried already... */
517 /**************************************************/
518 /* Create or find an entry for this channel state */
519 memset(&channel_key, 0, sizeof(channel_key));
520 channel_key.ueId = p_pdcp_lte_info->ueid;
521 channel_key.channelType = p_pdcp_lte_info->channelType;
522 channel_key.channelId = p_pdcp_lte_info->channelId;
523 channel_key.direction = p_pdcp_lte_info->direction;
525 /* Do the table lookup */
526 p_channel_status = (pdcp_channel_status*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash, &channel_key);
528 /* Create table entry if necessary */
529 if (p_channel_status == NULL) {
530 createdChannel = TRUE;
532 /* Allocate a new value and duplicate key contents */
533 p_channel_status = se_alloc0(sizeof(pdcp_channel_status));
534 p_channel_key = se_memdup(&channel_key, sizeof(pdcp_channel_hash_key));
537 g_hash_table_insert(pdcp_sequence_analysis_channel_hash, p_channel_key, p_channel_status);
540 /* Create space for frame state_report */
541 p_report_in_frame = se_alloc(sizeof(pdcp_sequence_report_in_frame));
543 switch (p_pdcp_lte_info->seqnum_length) {
544 case PDCP_SN_LENGTH_5_BITS:
547 case PDCP_SN_LENGTH_7_BITS:
550 case PDCP_SN_LENGTH_12_BITS:
554 DISSECTOR_ASSERT_NOT_REACHED();
558 /* Work out expected sequence number */
559 if (!createdChannel) {
560 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
563 /* Set report for this frame */
564 /* For PDCP, sequence number is always expectedSequence number */
565 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
567 /* For wrong sequence number... */
568 if (!p_report_in_frame->sequenceExpectedCorrect) {
570 /* Frames are not missing if we get an earlier sequence number again */
571 if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
572 p_report_in_frame->state = SN_Missing;
573 p_report_in_frame->firstSN = expectedSequenceNumber;
574 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
576 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
577 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
579 /* Update channel status to remember *this* frame */
580 p_channel_status->previousFrameNum = pinfo->fd->num;
581 p_channel_status->previousSequenceNumber = sequenceNumber;
584 /* An SN has been repeated */
585 p_report_in_frame->state = SN_Repeated;
586 p_report_in_frame->firstSN = sequenceNumber;
588 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
589 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
594 p_report_in_frame->state = SN_OK;
595 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
596 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
598 /* Update channel status to remember *this* frame */
599 p_channel_status->previousFrameNum = pinfo->fd->num;
600 p_channel_status->previousSequenceNumber = sequenceNumber;
603 /* Associate with this frame number */
604 g_hash_table_insert(pdcp_lte_frame_sequence_analysis_report_hash, &pinfo->fd->num, p_report_in_frame);
606 /* Add state report for this frame into tree */
607 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info, sequenceNumber,
612 /* Write the given formatted text to:
614 - the top-level RLC PDU item */
615 static void write_pdu_label_and_info(proto_item *pdu_ti,
616 packet_info *pinfo, const char *format, ...)
618 #define MAX_INFO_BUFFER 256
619 static char info_buffer[MAX_INFO_BUFFER];
623 va_start(ap, format);
624 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
627 /* Add to indicated places */
628 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
629 proto_item_append_text(pdu_ti, "%s", info_buffer);
634 /***************************************************************/
637 /* Dissect a Large-CID field.
638 Return following offset */
639 static int dissect_large_cid(proto_tree *tree,
643 guint8 first_octet = tvb_get_guint8(tvb, offset);
645 if ((first_octet & 0x80) == 0) {
647 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 1,
653 guint16 bytes = tvb_get_ntohs(tvb, offset) & 0x7fff;
654 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 2,
661 static int dissect_pdcp_dynamic_chain(proto_tree *tree,
662 proto_item *root_item _U_,
665 struct pdcp_lte_info *p_pdcp_info,
669 if (p_pdcp_info->rohc_ip_version == 4) {
670 proto_tree *dynamic_ipv4_tree;
672 int tree_start_offset = offset;
673 guint8 tos, ttl, id, rnd, nbo;
675 /* Create dynamic IPv4 subtree */
676 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_ipv4, tvb, offset, -1, ENC_NA);
677 dynamic_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_ipv4);
680 tos = tvb_get_guint8(tvb, offset);
681 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_tos, tvb, offset, 1, FALSE);
685 ttl = tvb_get_guint8(tvb, offset);
686 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_ttl, tvb, offset, 1, FALSE);
690 id = tvb_get_guint8(tvb, offset);
691 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_id, tvb, offset, 1, FALSE);
695 rnd = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
696 nbo = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
697 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_df, tvb, offset, 1, FALSE);
698 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_rnd, tvb, offset, 1, FALSE);
699 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_nbo, tvb, offset, 1, FALSE);
701 /* TODO: general extension header list... */
704 /* Set proper length for subtree */
705 proto_item_set_len(root_ti, offset-tree_start_offset);
707 /* Add summary to root item */
708 proto_item_append_text(root_ti, " (ToS=%u, TTL=%u, ID=%u, RND=%u, NBO=%u)",
709 tos, ttl, id, rnd, nbo);
713 if ((p_pdcp_info->profile == 1) ||
714 (p_pdcp_info->profile == 2)) {
716 proto_tree *dynamic_udp_tree;
718 unsigned short checksum;
720 /* Create dynamic UDP subtree */
721 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_udp, tvb, offset, 2, ENC_NA);
722 dynamic_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_udp);
724 /* 16-bit checksum */
725 checksum = tvb_get_ntohs(tvb, offset);
726 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_checksum, tvb, offset, 2, FALSE);
729 if (p_pdcp_info->profile == 2) {
732 seqnum = tvb_get_ntohs(tvb, offset);
733 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_seqnum, tvb, offset, 2, FALSE);
736 /* Add summary to root item */
737 proto_item_append_text(root_ti, " (checksum = %04x, seqnum = %u)", checksum, seqnum);
740 /* Add summary to root item */
741 proto_item_append_text(root_ti, " (checksum = %04x)", checksum);
746 if (p_pdcp_info->profile == 1) {
747 proto_tree *dynamic_rtp_tree;
749 int tree_start_offset = offset;
751 /*guint8 contributing_csrcs;*/
752 guint16 sequence_number;
757 /* Create dynamic RTP subtree */
758 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_rtp, tvb, offset, -1, ENC_NA);
759 dynamic_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_rtp);
762 /* V | P | RX | CC */
763 rx = tvb_get_guint8(tvb, offset) & 0x10;
764 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_rx, tvb, offset, 1, FALSE);
765 /*contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;*/
766 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_cc, tvb, offset, 1, FALSE);
773 /* Sequence number */
774 sequence_number = tvb_get_ntohs(tvb, offset);
775 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_seqnum, tvb, offset, 2, FALSE);
778 /* Timestamp (4 octets) */
779 timestamp = tvb_get_ntohl(tvb, offset);
780 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_timestamp, tvb, offset, 4, FALSE);
783 /* TODO: CSRC list */
784 /*offset += (4 * contributing_csrcs); */
787 /* TODO: Reserved | X | Mode | TIS | TIS */
789 guint8 this_byte = tvb_get_guint8(tvb, offset);
790 proto_item *reserved_ti = proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
791 tvb, offset, 1, FALSE);
793 /* Check reserved bits are 0 */
794 if ((this_byte & 0xe0) != 0) {
795 expert_add_info_format(pinfo, reserved_ti, PI_MALFORMED, PI_ERROR,
796 "Reserved bits have value 0x%x - should be 0x0",
799 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_x, tvb, offset, 1, FALSE);
800 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_mode, tvb, offset, 1, FALSE);
801 tss = (this_byte & 0x02);
802 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tss, tvb, offset, 1, FALSE);
803 tis = (this_byte & 0x01);
804 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tis, tvb, offset, 1, FALSE);
808 /* TODO: the length of these fields can be learned by looked at the leading bits, see
809 RFC 3095, "4.5.6. Self-describing variable-length values" */
810 /* TODO: TS-Stride (1-4 bytes) */
812 /* Assume encoded in two bytes for now... */
813 proto_tree_add_bits_ret_val(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
814 tvb, offset*8 + 2, 14, &ts_stride, FALSE);
818 /* TODO: Time-stride (1-4 bytes) */
822 /* Set proper length for subtree */
823 proto_item_set_len(root_ti, offset-tree_start_offset);
825 /* Add summary to root item */
826 proto_item_append_text(root_ti, " (seqnum = %u, timestamp = %u)",
827 sequence_number, timestamp);
835 static int dissect_pdcp_irdyn_packet(proto_tree *tree,
836 proto_item *root_item,
839 struct pdcp_lte_info *p_pdcp_info,
842 col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
843 proto_item_append_text(root_item, " (IRDYN)");
846 if (p_pdcp_info->large_cid_present) {
847 offset = dissect_large_cid(tree, tvb, offset);
851 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
855 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
858 /* Dissect dynamic chain */
859 offset = dissect_pdcp_dynamic_chain(tree,
869 static int dissect_pdcp_ir_packet(proto_tree *tree,
870 proto_item *root_item,
873 struct pdcp_lte_info *p_pdcp_info,
876 unsigned char dynamic_chain_present;
878 col_append_str(pinfo->cinfo, COL_INFO, " IR");
879 proto_item_append_text(root_item, " (IR)");
881 /* Is dynamic chain present? */
882 dynamic_chain_present = tvb_get_guint8(tvb, offset) & 0x1;
883 proto_tree_add_item(tree, hf_pdcp_lte_rohc_d, tvb, offset, 1, FALSE);
887 if (p_pdcp_info->large_cid_present) {
888 offset = dissect_large_cid(tree, tvb, offset);
892 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
896 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
899 /* IPv4 static part */
900 if (p_pdcp_info->rohc_ip_version == 4) {
901 proto_tree *static_ipv4_tree;
903 int tree_start_offset = offset;
905 guint32 source, dest;
907 /* Create static IPv4 subtree */
908 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_ipv4, tvb, offset, -1, ENC_NA);
909 static_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_ipv4);
911 /* IP version (must be 4) */
912 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_version, tvb, offset, 1, FALSE);
916 protocol = tvb_get_guint8(tvb, offset);
917 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_protocol, tvb, offset, 1, FALSE);
921 source = tvb_get_ipv4(tvb, offset);
922 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_src, tvb, offset, 4, FALSE);
926 dest = tvb_get_ipv4(tvb, offset);
927 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_dst, tvb, offset, 4, FALSE);
930 /* Set proper length for subtree */
931 proto_item_set_len(root_ti, offset-tree_start_offset);
933 /* Add summary to root item */
934 proto_item_append_text(root_ti, " (prot=%s: %s -> %s)",
935 val_to_str_const(protocol, ip_protocol_vals, "Unknown"),
936 (char*)get_hostname(source),
937 (char*)get_hostname(dest));
940 /* UDP static part. TODO: also check protocol from last part!? */
941 if ((p_pdcp_info->profile == 1) ||
942 (p_pdcp_info->profile == 2)) {
944 proto_tree *static_udp_tree;
946 int tree_start_offset = offset;
947 unsigned short source_port, dest_port;
949 /* Create static UDP subtree */
950 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_udp, tvb, offset, -1, ENC_NA);
951 static_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_udp);
954 source_port = tvb_get_ntohs(tvb, offset);
955 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
959 dest_port = tvb_get_ntohs(tvb, offset);
960 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
963 /* Set proper length for subtree */
964 proto_item_set_len(root_ti, offset-tree_start_offset);
966 /* Add summary to root item */
967 proto_item_append_text(root_ti, " (%u -> %u)", source_port, dest_port);
971 if (p_pdcp_info->profile == 1) {
972 proto_tree *static_rtp_tree;
976 /* Create static RTP subtree */
977 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_rtp, tvb, offset, 4, ENC_NA);
978 static_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_rtp);
981 ssrc = tvb_get_ntohl(tvb, offset);
982 proto_tree_add_item(static_rtp_tree, hf_pdcp_lte_rohc_static_rtp_ssrc, tvb, offset, 4, FALSE);
985 /* Add summary to root item */
986 proto_item_append_text(root_ti, " (SSRC=%u)", ssrc);
991 if (dynamic_chain_present) {
992 offset = dissect_pdcp_dynamic_chain(tree,
1005 static int dissect_pdcp_feedback_feedback1(proto_tree *tree,
1009 struct pdcp_lte_info *p_pdcp_info _U_,
1014 proto_item_append_text(item, " (type 1)");
1016 /* TODO: profile-specific */
1017 sn = tvb_get_guint8(tvb, offset);
1018 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback1, tvb, offset, 1, FALSE);
1021 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1026 /* Includes Large-CID, if present */
1027 static int dissect_pdcp_feedback_feedback2(proto_tree *tree,
1032 struct pdcp_lte_info *p_pdcp_info,
1040 const char * full_mode_name;
1043 proto_item_append_text(item, " (type 2)");
1046 if (p_pdcp_info->large_cid_present) {
1047 offset = dissect_large_cid(tree, tvb, offset);
1050 /* Feedback2 hidden filter */
1051 ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback2, tvb, offset, -1, ENC_NA);
1052 PROTO_ITEM_SET_HIDDEN(ti);
1055 first_octet = tvb_get_guint8(tvb, offset);
1056 ack_type = (first_octet & 0xc0) >> 6;
1057 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_ack_type, tvb, offset, 1, FALSE);
1059 /* TODO: expert info on NACK? */
1062 mode = (first_octet & 0x30) >> 4;
1063 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_mode, tvb, offset, 1, FALSE);
1065 /* Show ACK-TYPE(Mode) in info column */
1066 full_mode_name = val_to_str_const(mode, rohc_mode_vals, "Error");
1068 col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
1069 val_to_str_const(ack_type, feedback_ack_vals, "Unknown"),
1073 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_sn, tvb, offset, 2, FALSE);
1074 sn = tvb_get_ntohs(tvb, offset) & 0x7ff;
1077 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1079 /* Loop over any remaining feedback options */
1080 size_remaining = size - 2;
1082 while (tvb_length_remaining(tvb, offset) > 0) {
1083 guint8 option = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
1084 guint8 length = tvb_get_guint8(tvb, offset) & 0x0f;
1085 guint8 one_byte_value;
1087 /* Preference setting controls showing option and lengths */
1088 if (global_pdcp_show_feedback_option_tag_length) {
1089 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option, tvb, offset, 1, FALSE);
1090 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_length, tvb, offset, 1, FALSE);
1095 /* TODO: switch including missing option types */
1099 one_byte_value = tvb_get_guint8(tvb, offset);
1100 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_crc, tvb, offset, 1, FALSE);
1101 col_append_fstr(pinfo->cinfo, COL_INFO, " CRC=%u ", one_byte_value);
1107 /* SN-Not-Valid: TODO */
1111 one_byte_value = tvb_get_guint8(tvb, offset);
1112 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_sn, tvb, offset, 1, FALSE);
1113 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u ", one_byte_value);
1117 one_byte_value = tvb_get_guint8(tvb, offset);
1118 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_clock, tvb, offset, 1, FALSE);
1119 col_append_fstr(pinfo->cinfo, COL_INFO, " Clock=%u ", one_byte_value);
1129 /* TODO: unhandled option */
1135 size_remaining -= length;
1142 /* Dissect a feedback packet.
1143 Return following offset */
1144 static int dissect_pdcp_feedback_packet(proto_tree *tree,
1145 proto_item *root_item,
1148 struct pdcp_lte_info *p_pdcp_info,
1154 proto_item *feedback_ti;
1155 proto_tree *feedback_tree;
1157 col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
1158 proto_item_append_text(root_item, " (Feedback)");
1160 /* Create feedback tree root */
1161 feedback_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback, tvb, offset, -1, ENC_NA);
1162 feedback_tree = proto_item_add_subtree(feedback_ti, ett_pdcp_packet);
1165 code = tvb_get_guint8(tvb, offset) & 0x07;
1166 ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_code, tvb, offset, 1, FALSE);
1169 /* Optional length field */
1171 proto_item_append_text(ti, " (length of feedback data)");
1175 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_size, tvb, offset, 1, FALSE);
1176 size = tvb_get_guint8(tvb, offset);
1180 /* Work out feedback type */
1181 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
1182 !p_pdcp_info->large_cid_present) {
1186 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
1188 else if ((size > 1) && ((tvb_get_guint8(tvb, offset) & 0xc0) == 0xc0)) {
1190 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
1194 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
1197 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1201 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1205 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1212 /* Dissect R-0 packet.
1213 Return following offset */
1214 static int dissect_pdcp_r_0_packet(proto_tree *tree,
1215 proto_item *root_item,
1218 struct pdcp_lte_info *p_pdcp_info,
1223 col_append_str(pinfo->cinfo, COL_INFO, " R-0");
1224 proto_item_append_text(root_item, " (R-0)");
1227 sn = tvb_get_guint8(tvb, offset) & 0x3f;
1228 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_sn, tvb, offset, 1, FALSE);
1232 if (p_pdcp_info->large_cid_present) {
1233 offset = dissect_large_cid(tree, tvb, offset);
1236 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1242 /* Dissect R-0-CRC packet.
1243 Return following offset */
1244 static int dissect_pdcp_r_0_crc_packet(proto_tree *tree,
1245 proto_item *root_item,
1248 struct pdcp_lte_info *p_pdcp_info,
1253 col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
1254 proto_item_append_text(root_item, " (R-0-CRC)");
1256 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r_0_crc, tvb, offset, -1, ENC_NA);
1259 /* TODO: wrong! Large-cid may be in-between!!!! */
1260 sn = tvb_get_guint8(tvb, offset) & 0x3f;
1264 if (p_pdcp_info->large_cid_present) {
1265 offset = dissect_large_cid(tree, tvb, offset);
1269 sn = (sn << 1) + ((tvb_get_guint8(tvb, offset) & 0x80) >> 7);
1270 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_r0_crc_sn, tvb, offset, 1, sn);
1273 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_crc_crc, tvb, offset, 1, FALSE);
1276 /* Show SN in info column */
1277 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1283 /* Dissect UO-0-CRC packet.
1284 Return following offset */
1285 static int dissect_pdcp_uo_0_packet(proto_tree *tree,
1286 proto_item *root_item,
1289 struct pdcp_lte_info *p_pdcp_info,
1294 col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
1295 proto_item_append_text(root_item, " (UO-0)");
1298 sn = (tvb_get_guint8(tvb, offset) & 0x78) >> 3;
1299 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_sn, tvb, offset, 1, FALSE);
1302 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_crc, tvb, offset, 1, FALSE);
1307 if (p_pdcp_info->large_cid_present) {
1308 offset = dissect_large_cid(tree, tvb, offset);
1311 /* Show SN in info column */
1312 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1318 /* Dissect R-1 packet.
1319 Return following offset */
1320 static int dissect_pdcp_r_1_packet(proto_tree *tree,
1321 proto_item *root_item,
1324 struct pdcp_lte_info *p_pdcp_info,
1327 col_append_str(pinfo->cinfo, COL_INFO, " R-1");
1328 proto_item_append_text(root_item, " (R-1)");
1330 /* TODO: octet before large-cid */
1334 if (p_pdcp_info->large_cid_present) {
1335 offset = dissect_large_cid(tree, tvb, offset);
1338 if (p_pdcp_info->profile == 1) {
1341 else if (p_pdcp_info->profile == 2) {
1349 /* Dissect R-1-TS or R-1-ID packet.
1350 Return following offset */
1351 static int dissect_pdcp_r_1_ts_or_id_packet(proto_tree *tree,
1352 proto_item *root_item,
1355 struct pdcp_lte_info *p_pdcp_info,
1360 /* TODO: octet before large-cid */
1364 if (p_pdcp_info->large_cid_present) {
1365 offset = dissect_large_cid(tree, tvb, offset);
1368 /* T determines frame type */
1369 T = tvb_get_guint8(tvb, ++offset) >> 7;
1370 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type1_t, tvb, offset, 1, FALSE);
1372 col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
1373 proto_item_append_text(root_item, " (R-1-TS)");
1376 col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
1377 proto_item_append_text(root_item, " (R-1-ID)");
1380 if (p_pdcp_info->profile == 1) {
1383 else if (p_pdcp_info->profile == 2) {
1391 /* Dissect UO-1 packet.
1392 Return following offset */
1393 static int dissect_pdcp_uo_1_packet(proto_tree *tree,
1394 proto_item *root_item,
1397 struct pdcp_lte_info *p_pdcp_info,
1400 col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
1401 proto_item_append_text(root_item, " (UO-1)");
1403 /* TODO: octet before large-cid */
1407 if (p_pdcp_info->large_cid_present) {
1408 offset = dissect_large_cid(tree, tvb, offset);
1411 if (p_pdcp_info->profile == 1) {
1414 else if (p_pdcp_info->profile == 2) {
1422 /* Dissect UO-1-TS or UO-1-ID packet.
1423 Return following offset */
1424 static int dissect_pdcp_uo_1_ts_or_id_packet(proto_tree *tree,
1425 proto_item *root_item,
1428 struct pdcp_lte_info *p_pdcp_info,
1433 /* TODO: octet before large-cid */
1437 if (p_pdcp_info->large_cid_present) {
1438 offset = dissect_large_cid(tree, tvb, offset);
1441 /* T determines frame type */
1442 T = tvb_get_guint8(tvb, ++offset) >> 5;
1443 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type0_t, tvb, offset, 1, FALSE);
1445 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
1446 proto_item_append_text(root_item, " (UO-1-TS)");
1449 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
1450 proto_item_append_text(root_item, " (UO-1-ID)");
1453 if (p_pdcp_info->profile == 1) {
1456 else if (p_pdcp_info->profile == 2) {
1467 /* Dissect UOR-2 packet.
1468 Return following offset */
1469 static int dissect_pdcp_uor_2_packet(proto_tree *tree,
1470 proto_item *root_item,
1473 struct pdcp_lte_info *p_pdcp_info,
1478 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
1479 proto_item_append_text(root_item, " (UOR-2)");
1481 /* TS straddles CID */
1482 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1486 if (p_pdcp_info->large_cid_present) {
1487 offset = dissect_large_cid(tree, tvb, offset);
1490 /* Last bit of TS is here */
1491 ts = (ts << 1) | (tvb_get_guint8(tvb, offset) >> 7);
1492 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1494 if (p_pdcp_info->profile == 1) {
1496 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, FALSE);
1499 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_sn, tvb, offset, 1, FALSE);
1503 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_x, tvb, offset, 1, FALSE);
1508 else if (p_pdcp_info->profile == 2) {
1517 /* Dissect UOR-2-TS or UOR-2-ID packet.
1518 Return following offset */
1519 static int dissect_pdcp_uor_2_ts_or_id_packet(proto_tree *tree,
1520 proto_item *root_item,
1523 struct pdcp_lte_info *p_pdcp_info,
1528 /* TODO: octet before large-cid.
1529 TODO: can't decode this until we know what T is,
1530 but T is after large-cid... */
1533 /* T determines frame type */
1534 T = tvb_get_guint8(tvb, offset) >> 7;
1535 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type2_t, tvb, offset, 1, FALSE);
1538 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
1539 proto_item_append_text(root_item, " (UOR-2-TS)");
1542 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
1543 proto_item_append_text(root_item, " (UOR-2-ID)");
1548 /* UOR-2-TS format */
1551 guint8 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1552 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1556 if (p_pdcp_info->large_cid_present) {
1557 offset = dissect_large_cid(tree, tvb, offset);
1561 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, ts);
1566 /* TODO: UOR-2-ID format */
1571 if (p_pdcp_info->large_cid_present) {
1572 offset = dissect_large_cid(tree, tvb, offset);
1578 if (p_pdcp_info->profile == 1) {
1581 else if (p_pdcp_info->profile == 2) {
1591 /* Show in the tree the config info attached to this frame, as generated fields */
1592 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1593 pdcp_lte_info *p_pdcp_info)
1596 proto_tree *configuration_tree;
1597 proto_item *configuration_ti = proto_tree_add_item(tree,
1598 hf_pdcp_lte_configuration,
1600 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
1603 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_direction, tvb, 0, 0,
1604 p_pdcp_info->direction);
1605 PROTO_ITEM_SET_GENERATED(ti);
1608 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
1609 p_pdcp_info->plane);
1610 PROTO_ITEM_SET_GENERATED(ti);
1613 if (p_pdcp_info->ueid != 0) {
1614 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_ueid, tvb, 0, 0,
1616 PROTO_ITEM_SET_GENERATED(ti);
1620 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_type, tvb, 0, 0,
1621 p_pdcp_info->channelType);
1622 PROTO_ITEM_SET_GENERATED(ti);
1623 if (p_pdcp_info->channelId != 0) {
1625 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_id, tvb, 0, 0,
1626 p_pdcp_info->channelId);
1627 PROTO_ITEM_SET_GENERATED(ti);
1631 /* User-plane-specific fields */
1632 if (p_pdcp_info->plane == USER_PLANE) {
1635 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
1636 p_pdcp_info->no_header_pdu);
1637 PROTO_ITEM_SET_GENERATED(ti);
1639 if (!p_pdcp_info->no_header_pdu) {
1642 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
1643 p_pdcp_info->seqnum_length);
1644 PROTO_ITEM_SET_GENERATED(ti);
1648 /* ROHC compression */
1649 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
1650 p_pdcp_info->rohc_compression);
1651 PROTO_ITEM_SET_GENERATED(ti);
1653 /* ROHC-specific settings */
1654 if (p_pdcp_info->rohc_compression) {
1656 /* Show ROHC mode */
1657 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
1659 PROTO_ITEM_SET_GENERATED(ti);
1662 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
1664 PROTO_ITEM_SET_GENERATED(ti);
1667 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
1668 p_pdcp_info->udp_checkum_present);
1669 PROTO_ITEM_SET_GENERATED(ti);
1672 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
1673 p_pdcp_info->profile);
1674 PROTO_ITEM_SET_GENERATED(ti);
1676 /* CID Inclusion Info */
1677 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
1678 p_pdcp_info->cid_inclusion_info);
1679 PROTO_ITEM_SET_GENERATED(ti);
1682 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
1683 p_pdcp_info->large_cid_present);
1684 PROTO_ITEM_SET_GENERATED(ti);
1687 /* Append summary to configuration root */
1688 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
1689 val_to_str_const(p_pdcp_info->direction, direction_vals, "Unknown"),
1690 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1692 if (p_pdcp_info->rohc_compression) {
1693 const char *mode = val_to_str_const(p_pdcp_info->mode, rohc_mode_vals, "Error");
1694 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
1696 val_to_str_const(p_pdcp_info->profile, rohc_profile_vals, "Unknown"));
1698 proto_item_append_text(configuration_ti, ")");
1699 PROTO_ITEM_SET_GENERATED(configuration_ti);
1701 /* Show plane in info column */
1702 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
1703 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1708 /* Look for an RRC dissector for signalling data (using channel type and direction) */
1709 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_lte_info *p_pdcp_info)
1711 dissector_handle_t rrc_handle = 0;
1713 switch (p_pdcp_info->channelType)
1716 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1717 rrc_handle = find_dissector("lte_rrc.ul_ccch");
1720 rrc_handle = find_dissector("lte_rrc.dl_ccch");
1724 rrc_handle = find_dissector("lte-rrc.pcch");
1727 switch (p_pdcp_info->BCCHTransport) {
1729 rrc_handle = find_dissector("lte_rrc.bcch_bch");
1731 case DLSCH_TRANSPORT:
1732 rrc_handle = find_dissector("lte_rrc.bcch_dl_sch");
1737 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1738 rrc_handle = find_dissector("lte_rrc.ul_dcch");
1741 rrc_handle = find_dissector("lte_rrc.dl_dcch");
1754 /* Forwad declarations */
1755 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
1757 /* Heuristic dissection */
1758 static gboolean global_pdcp_lte_heur = FALSE;
1760 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
1761 static gboolean dissect_pdcp_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
1765 struct pdcp_lte_info *p_pdcp_lte_info;
1768 gboolean infoAlreadySet = FALSE;
1769 gboolean seqnumLengthTagPresent = FALSE;
1771 /* This is a heuristic dissector, which means we get all the UDP
1772 * traffic not sent to a known dissector and not claimed by
1773 * a heuristic dissector called before us!
1776 if (!global_pdcp_lte_heur) {
1780 /* Do this again on re-dissection to re-discover offset of actual PDU */
1782 /* Needs to be at least as long as:
1783 - the signature string
1784 - fixed header bytes
1786 - at least one byte of PDCP PDU payload */
1787 if ((size_t)tvb_length_remaining(tvb, offset) < (strlen(PDCP_LTE_START_STRING)+3+2)) {
1791 /* OK, compare with signature string */
1792 if (tvb_strneql(tvb, offset, PDCP_LTE_START_STRING, strlen(PDCP_LTE_START_STRING)) != 0) {
1795 offset += (gint)strlen(PDCP_LTE_START_STRING);
1798 /* If redissecting, use previous info struct (if available) */
1799 p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1800 if (p_pdcp_lte_info == NULL) {
1801 /* Allocate new info struct for this frame */
1802 p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
1803 infoAlreadySet = FALSE;
1806 infoAlreadySet = TRUE;
1810 /* Read fixed fields */
1811 p_pdcp_lte_info->no_header_pdu = tvb_get_guint8(tvb, offset++);
1812 p_pdcp_lte_info->plane = tvb_get_guint8(tvb, offset++);
1813 p_pdcp_lte_info->rohc_compression = tvb_get_guint8(tvb, offset++);
1815 /* Read optional fields */
1816 while (tag != PDCP_LTE_PAYLOAD_TAG) {
1817 /* Process next tag */
1818 tag = tvb_get_guint8(tvb, offset++);
1820 case PDCP_LTE_SEQNUM_LENGTH_TAG:
1821 p_pdcp_lte_info->seqnum_length = tvb_get_guint8(tvb, offset);
1823 seqnumLengthTagPresent = TRUE;
1825 case PDCP_LTE_DIRECTION_TAG:
1826 p_pdcp_lte_info->direction = tvb_get_guint8(tvb, offset);
1829 case PDCP_LTE_LOG_CHAN_TYPE_TAG:
1830 p_pdcp_lte_info->channelType = tvb_get_guint8(tvb, offset);
1833 case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG:
1834 p_pdcp_lte_info->BCCHTransport = tvb_get_guint8(tvb, offset);
1837 case PDCP_LTE_ROHC_IP_VERSION_TAG:
1838 p_pdcp_lte_info->rohc_ip_version = tvb_get_ntohs(tvb, offset);
1841 case PDCP_LTE_ROHC_CID_INC_INFO_TAG:
1842 p_pdcp_lte_info->cid_inclusion_info = tvb_get_guint8(tvb, offset);
1845 case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG:
1846 p_pdcp_lte_info->large_cid_present = tvb_get_guint8(tvb, offset);
1849 case PDCP_LTE_ROHC_MODE_TAG:
1850 p_pdcp_lte_info->mode = tvb_get_guint8(tvb, offset);
1853 case PDCP_LTE_ROHC_RND_TAG:
1854 p_pdcp_lte_info->rnd = tvb_get_guint8(tvb, offset);
1857 case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG:
1858 p_pdcp_lte_info->udp_checkum_present = tvb_get_guint8(tvb, offset);
1861 case PDCP_LTE_ROHC_PROFILE_TAG:
1862 p_pdcp_lte_info->profile = tvb_get_ntohs(tvb, offset);
1866 case PDCP_LTE_PAYLOAD_TAG:
1867 /* Have reached data, so get out of loop */
1871 /* It must be a recognised tag */
1876 if ((p_pdcp_lte_info->plane == USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
1877 /* Conditional field is not present */
1881 if (!infoAlreadySet) {
1882 /* Store info in packet */
1883 p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
1886 /**************************************/
1887 /* OK, now dissect as PDCP LTE */
1889 /* Create tvb that starts at actual PDCP PDU */
1890 pdcp_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
1891 dissect_pdcp_lte(pdcp_tvb, pinfo, tree);
1896 /******************************/
1897 /* Main dissection function. */
1898 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1901 proto_tree *pdcp_tree = NULL;
1902 proto_item *root_ti = NULL;
1903 proto_tree *rohc_tree = NULL;
1904 proto_item *rohc_ti = NULL;
1907 struct pdcp_lte_info *p_pdcp_info;
1908 guint8 base_header_byte;
1909 gboolean udp_checksum_needed = TRUE;
1910 gboolean ip_id_needed = TRUE;
1912 /* Append this protocol name rather than replace. */
1913 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
1915 /* Create pdcp tree. */
1917 root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, FALSE);
1918 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1922 /* Look for attached packet info! */
1923 p_pdcp_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1924 /* Can't dissect anything without it... */
1925 if (p_pdcp_info == NULL) {
1930 /* Set mode string */
1931 mode = val_to_str_const(p_pdcp_info->mode, rohc_mode_vals, "Error");
1933 /* Show configuration (attached packet) info in tree */
1935 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1938 /* Show ROHC mode */
1939 if (p_pdcp_info->rohc_compression) {
1940 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1944 /* Handle PDCP header (if present) */
1945 if (!p_pdcp_info->no_header_pdu) {
1947 /* TODO: shouldn't need to initialise this one!! */
1949 gboolean seqnum_set = FALSE;
1951 /*****************************/
1952 /* Signalling plane messages */
1953 if (p_pdcp_info->plane == SIGNALING_PLANE) {
1955 guint32 data_length;
1957 /* 5-bit sequence number */
1958 seqnum = tvb_get_guint8(tvb, offset) & 0x1f;
1960 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, FALSE);
1961 write_pdu_label_and_info(root_ti, pinfo, " sn=%-2u ", seqnum);
1964 /* RRC data is all but last 4 bytes.
1965 Call lte-rrc dissector (according to direction and channel type) */
1966 if (global_pdcp_dissect_signalling_plane_as_rrc) {
1967 /* Get appropriate dissector handle */
1968 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1970 if (rrc_handle != 0) {
1971 /* Call RRC dissector if have one */
1972 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
1973 tvb_length_remaining(tvb, offset) - 4,
1974 tvb_length_remaining(tvb, offset) - 4);
1975 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
1978 /* Just show data */
1979 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1980 tvb_length_remaining(tvb, offset) - 4, ENC_NA);
1984 /* Just show as unparsed data */
1985 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1986 tvb_length_remaining(tvb, offset) - 4, ENC_NA);
1989 data_length = tvb_length_remaining(tvb, offset) - 4;
1990 offset += data_length;
1992 /* Last 4 bytes are MAC */
1993 mac = tvb_get_ntohl(tvb, offset);
1994 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, FALSE);
1997 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
2001 else if (p_pdcp_info->plane == USER_PLANE) {
2003 /**********************************/
2004 /* User-plane messages */
2005 gboolean pdu_type = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
2007 /* Data/Control flag */
2008 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, FALSE);
2010 if (pdu_type == 1) {
2011 /*****************************/
2012 /* Use-plane Data */
2014 /* Number of sequence number bits depends upon config */
2015 if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_7_BITS) {
2016 seqnum = tvb_get_guint8(tvb, offset) & 0x7f;
2018 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, FALSE);
2021 else if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_12_BITS) {
2023 guint8 reserved_value;
2025 /* 3 reserved bits */
2026 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, FALSE);
2027 reserved_value = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
2029 /* Complain if not 0 */
2030 if (reserved_value != 0) {
2031 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
2032 "Reserved bits have value 0x%x - should be 0x0",
2036 /* 12-bit sequence number */
2037 seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
2039 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, FALSE);
2043 /* Not a recognised data format!!!!! */
2047 write_pdu_label_and_info(root_ti, pinfo, " (SN=%u)", seqnum);
2050 /*******************************/
2051 /* User-plane Control messages */
2052 guint8 control_pdu_type = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
2053 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, FALSE);
2055 switch (control_pdu_type) {
2056 case 0: /* PDCP status report */
2059 guint not_received = 0;
2061 proto_tree *bitmap_tree;
2062 proto_item *bitmap_ti = NULL;
2064 /* First-Missing-Sequence SN */
2065 fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
2066 sn = (fms + 1) % 4096;
2067 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
2072 if (tvb_length_remaining(tvb, offset) > 0) {
2073 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
2075 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_rohc_report_bitmap);
2078 /* For each byte... */
2079 for ( ; tvb_length_remaining(tvb, offset); offset++) {
2080 guint bit_offset = 0;
2081 /* .. look for error (0) in each bit */
2082 for ( ; bit_offset < 8; bit_offset++) {
2083 if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
2084 proto_tree_add_boolean_format_value(bitmap_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
2088 sn = (sn + 1) % 4096;
2093 if (bitmap_ti != NULL) {
2094 proto_item_append_text(bitmap_ti, " (not-received=%u)", not_received);
2096 write_pdu_label_and_info(root_ti, pinfo, " Status Report (fms=%u) not-received=%u",
2101 case 1: /* ROHC Feedback */
2103 break; /* Drop-through to dissect feedback */
2105 default: /* Reserved */
2111 /* Invalid plane setting...! */
2112 write_pdu_label_and_info(root_ti, pinfo, " - INVALID PLANE (%u)",
2113 p_pdcp_info->plane);
2117 /* For now, only do sequence analysis if RLC wasn't present in the frame */
2118 /* This can be fixed once RLC does re-assembly... */
2119 if (global_pdcp_check_sequence_numbers && seqnum_set &&
2120 (p_get_proto_data(pinfo->fd, proto_rlc_lte) == NULL)) {
2122 checkChannelSequenceInfo(pinfo, tvb, p_pdcp_info,
2123 (guint16)seqnum, pdcp_tree);
2128 /* Show that its a no-header PDU */
2129 write_pdu_label_and_info(root_ti, pinfo, " No-Header ");
2133 /* If not compressed with ROHC, show as user-plane data */
2134 if (!p_pdcp_info->rohc_compression) {
2135 if (tvb_length_remaining(tvb, offset) > 0) {
2136 if (p_pdcp_info->plane == USER_PLANE) {
2137 if (global_pdcp_dissect_user_plane_as_ip) {
2138 tvbuff_t *payload_tvb = tvb_new_subset_remaining(tvb, offset);
2139 switch (tvb_get_guint8(tvb, offset) & 0xf0) {
2141 call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
2144 call_dissector_only(ipv6_handle, payload_tvb, pinfo, pdcp_tree);
2147 call_dissector_only(data_handle, payload_tvb, pinfo, pdcp_tree);
2152 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, ENC_NA);
2156 if (global_pdcp_dissect_signalling_plane_as_rrc) {
2157 /* Get appropriate dissector handle */
2158 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
2160 if (rrc_handle != 0) {
2161 /* Call RRC dissector if have one */
2162 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
2163 tvb_length_remaining(tvb, offset),
2164 tvb_length_remaining(tvb, offset));
2165 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
2168 /* Just show data */
2169 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
2170 tvb_length_remaining(tvb, offset), ENC_NA);
2174 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset, -1, ENC_NA);
2178 write_pdu_label_and_info(root_ti, pinfo, "(%u bytes data)",
2179 tvb_length_remaining(tvb, offset));
2185 /***************************/
2187 /***************************/
2189 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
2190 val_to_str_const(p_pdcp_info->profile, rohc_profile_vals, "Unknown"));
2192 /* Only attempt ROHC if configured to */
2193 if (!global_pdcp_dissect_rohc) {
2197 /* Create pdcp tree. */
2199 rohc_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_rohc, tvb, offset, -1, ENC_NA);
2200 rohc_tree = proto_item_add_subtree(rohc_ti, ett_pdcp_rohc);
2203 rohc_offset = offset;
2205 /* Skip any leading padding octets (11100000) */
2206 while (tvb_get_guint8(tvb, offset) == 0xe0) {
2209 if (offset > rohc_offset) {
2210 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_padding, tvb, rohc_offset,
2211 offset-rohc_offset, ENC_NA);
2215 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
2216 !p_pdcp_info->large_cid_present)
2218 if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) {
2219 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
2223 /* Assume CID value of 0 if field absent */
2224 proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 0, 0);
2225 PROTO_ITEM_SET_GENERATED(ti);
2229 /* Now look at first octet of base header and identify packet type */
2230 base_header_byte = tvb_get_guint8(tvb, offset);
2233 if ((base_header_byte & 0xfe) == 0xfc) {
2234 offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2235 udp_checksum_needed = FALSE;
2236 ip_id_needed = FALSE;
2239 /* IRDYN (11111000) */
2240 else if (base_header_byte == 0xf8) {
2241 offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2242 udp_checksum_needed = FALSE;
2243 ip_id_needed = FALSE;
2246 /* Feedback (begins with 11110) */
2247 else if (((base_header_byte & 0xf8) >> 3) == 0x1e) {
2248 offset = dissect_pdcp_feedback_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2252 /* Packet type 0 (0) */
2253 else if ((base_header_byte & 0x80) == 0) {
2255 /* TODO: decide type based upon:
2258 - length remaining (taking into account large-cid) */
2260 /* R-0 begins with 00 */
2261 if (((base_header_byte & 0xc0) == 0) &&
2262 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
2264 offset = dissect_pdcp_r_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2267 /* R-0-CRC begins with 01 */
2268 else if ((((base_header_byte & 0x40) >> 6) == 1) &&
2269 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
2271 offset = dissect_pdcp_r_0_crc_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2275 offset = dissect_pdcp_uo_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2279 /* Packet type 1 (10) */
2280 else if (((base_header_byte & 0xc0) >> 6) == 2) {
2282 switch (p_pdcp_info->mode) {
2284 case RELIABLE_BIDIRECTIONAL:
2285 /* R-1 if !(ipv4 && rand) */
2286 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2287 (!p_pdcp_info->rnd))) {
2288 offset = dissect_pdcp_r_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2292 /* Whether its R-1-ID or R-1-TS depends upon T bit */
2293 dissect_pdcp_r_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2298 case UNIDIRECTIONAL:
2299 case OPTIMISTIC_BIDIRECTIONAL:
2300 /* UO-1 if !(ipv4 && rand) */
2301 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2302 (!p_pdcp_info->rnd))) {
2304 dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2306 /* Whether its UO-1-ID or UO-1-TS depends upon T bit */
2307 dissect_pdcp_uo_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2315 /* Packet type 2 (110) */
2316 else if (((base_header_byte & 0xe0) >> 5) == 6) {
2318 /* UOR-2 if !(ipv4 && rand) */
2319 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2320 (!p_pdcp_info->rnd))) {
2322 dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2325 /* Whether its UOR-2-ID or UOR-2-TS depends upon T bit */
2326 dissect_pdcp_uor_2_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2331 /* Segment (1111111) */
2332 else if ((base_header_byte & 0xfe) == 0xfe) {
2338 /* Fields beyond base header */
2340 /* These 2 fields not present for IR, IR-DYN frames */
2343 if (p_pdcp_info->rnd && ip_id_needed) {
2344 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_ip_id, tvb, offset, 2, FALSE);
2349 if (p_pdcp_info->udp_checkum_present && udp_checksum_needed) {
2350 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_udp_checksum, tvb, offset, 2, FALSE);
2355 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2356 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_payload, tvb, offset, -1, ENC_NA);
2361 /* Initializes the hash table and the mem_chunk area each time a new
2362 * file is loaded or re-loaded in wireshark */
2364 pdcp_lte_init_protocol(void)
2366 /* Destroy any existing hashes. */
2367 if (pdcp_sequence_analysis_channel_hash) {
2368 g_hash_table_destroy(pdcp_sequence_analysis_channel_hash);
2370 if (pdcp_lte_frame_sequence_analysis_report_hash) {
2371 g_hash_table_destroy(pdcp_lte_frame_sequence_analysis_report_hash);
2375 /* Now create them over */
2376 pdcp_sequence_analysis_channel_hash = g_hash_table_new(pdcp_channel_hash_func, pdcp_channel_equal);
2377 pdcp_lte_frame_sequence_analysis_report_hash = g_hash_table_new(pdcp_frame_hash_func, pdcp_frame_equal);
2382 void proto_register_pdcp(void)
2384 static hf_register_info hf[] =
2386 { &hf_pdcp_lte_configuration,
2388 "pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
2389 "Configuration info passed into dissector", HFILL
2393 { &hf_pdcp_lte_rohc_compression,
2394 { "ROHC Compression",
2395 "pdcp-lte.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2399 { &hf_pdcp_lte_rohc_mode,
2401 "pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
2405 { &hf_pdcp_lte_rohc_rnd,
2406 { "RND", /* TODO: true/false vals? */
2407 "pdcp-lte.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
2408 "RND of outer ip header", HFILL
2411 { &hf_pdcp_lte_rohc_udp_checksum_present,
2412 { "UDP Checksum", /* TODO: true/false vals? */
2413 "pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2414 "UDP Checksum present", HFILL
2417 { &hf_pdcp_lte_direction,
2419 "pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2420 "Direction of message", HFILL
2423 { &hf_pdcp_lte_ueid,
2425 "pdcp-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
2426 "UE Identifier", HFILL
2429 { &hf_pdcp_lte_channel_type,
2431 "pdcp-lte.channel-type", FT_UINT8, BASE_DEC, VALS(logical_channel_vals), 0x0,
2435 { &hf_pdcp_lte_channel_id,
2437 "pdcp-lte.channel-id", FT_UINT8, BASE_DEC, 0, 0x0,
2441 { &hf_pdcp_lte_rohc_profile,
2443 "pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
2447 { &hf_pdcp_lte_no_header_pdu,
2449 "pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
2453 { &hf_pdcp_lte_plane,
2455 "pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
2459 { &hf_pdcp_lte_seqnum_length,
2461 "pdcp-lte.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
2462 "Sequence Number Length", HFILL
2467 { &hf_pdcp_lte_cid_inclusion_info,
2468 { "CID Inclusion Info",
2469 "pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
2473 { &hf_pdcp_lte_large_cid_present,
2474 { "Large CID Present",
2475 "pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2480 { &hf_pdcp_lte_seq_num_5,
2482 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
2483 "PDCP Seq num", HFILL
2486 { &hf_pdcp_lte_seq_num_7,
2488 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
2489 "PDCP Seq num", HFILL
2492 { &hf_pdcp_lte_reserved3,
2494 "pdcp-lte.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
2495 "3 reserved bits", HFILL
2498 { &hf_pdcp_lte_seq_num_12,
2500 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2501 "PDCP Seq num", HFILL
2504 { &hf_pdcp_lte_signalling_data,
2505 { "Signalling Data",
2506 "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2512 "pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
2516 { &hf_pdcp_lte_data_control,
2518 "pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
2522 { &hf_pdcp_lte_user_plane_data,
2523 { "User-Plane Data",
2524 "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2528 { &hf_pdcp_lte_control_pdu_type,
2529 { "Control PDU Type",
2530 "pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
2535 { "First Missing Sequence Number",
2536 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2537 "First Missing PDCP Sequence Number", HFILL
2540 { &hf_pdcp_lte_bitmap,
2542 "pdcp-lte.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
2543 "Status report bitmap (0=error, 1=OK)", HFILL
2546 { &hf_pdcp_lte_bitmap_not_received,
2548 "pdcp-lte.bitmap.error", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2549 "Status report PDU error", HFILL
2554 { &hf_pdcp_lte_sequence_analysis,
2555 { "Sequence Analysis",
2556 "pdcp-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
2560 { &hf_pdcp_lte_sequence_analysis_ok,
2562 "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2566 { &hf_pdcp_lte_sequence_analysis_previous_frame,
2567 { "Previous frame for channel",
2568 "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
2572 { &hf_pdcp_lte_sequence_analysis_expected_sn,
2574 "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
2578 { &hf_pdcp_lte_sequence_analysis_skipped,
2580 "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2584 { &hf_pdcp_lte_sequence_analysis_repeated,
2586 "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2591 { &hf_pdcp_lte_rohc,
2593 "pdcp-lte.rohc", FT_NONE, BASE_NONE, NULL, 0,
2598 { &hf_pdcp_lte_rohc_padding,
2600 "pdcp-lte.rohc.padding", FT_NONE, BASE_NONE, NULL, 0,
2601 "ROHC Padding", HFILL
2604 { &hf_pdcp_lte_rohc_r_0_crc,
2606 "pdcp-lte.r-0-crc", FT_NONE, BASE_NONE, NULL, 0,
2610 { &hf_pdcp_lte_rohc_feedback,
2612 "pdcp-lte.rohc.feedback", FT_NONE, BASE_NONE, NULL, 0,
2613 "Feedback Packet", HFILL
2616 { &hf_pdcp_lte_rohc_type0_t,
2618 "pdcp-lte.rohc.t0.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x20,
2619 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2622 { &hf_pdcp_lte_rohc_type1_t,
2624 "pdcp-lte.rohc.t1.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2625 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2628 { &hf_pdcp_lte_rohc_type2_t,
2630 "pdcp-lte.rohc.t2.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2631 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2634 { &hf_pdcp_lte_rohc_d,
2636 "pdcp-lte.rohc.d", FT_UINT8, BASE_HEX, NULL, 0x01,
2637 "Indicates whether Dynamic chain is present", HFILL
2640 { &hf_pdcp_lte_rohc_ir_crc,
2642 "pdcp-lte.rohc.ir.crc", FT_UINT8, BASE_HEX, NULL, 0x0,
2647 { &hf_pdcp_lte_rohc_static_ipv4,
2648 { "Static IPv4 chain",
2649 "pdcp-lte.rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2653 { &hf_pdcp_lte_rohc_ip_version,
2655 "pdcp-lte.rohc.ip-version", FT_UINT8, BASE_HEX, NULL, 0xf0,
2659 /* TODO: create/use value_string */
2660 { &hf_pdcp_lte_rohc_ip_protocol,
2662 "pdcp-lte.rohc.ip-protocol", FT_UINT8, BASE_DEC, VALS(ip_protocol_vals), 0x0,
2666 { &hf_pdcp_lte_rohc_ip_src,
2667 { "IP Source address",
2668 "pdcp-lte.rohc.ip-src", FT_IPv4, BASE_NONE, NULL, 0x0,
2672 { &hf_pdcp_lte_rohc_ip_dst,
2673 { "IP Destination address",
2674 "pdcp-lte.rohc.ip-dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2679 { &hf_pdcp_lte_rohc_static_udp,
2680 { "Static UDP chain",
2681 "pdcp-lte.rohc.static.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2685 { &hf_pdcp_lte_rohc_static_udp_src_port,
2686 { "Static UDP source port",
2687 "pdcp-lte.rohc.static.udp.src-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2691 { &hf_pdcp_lte_rohc_static_udp_dst_port,
2692 { "Static UDP destination port",
2693 "pdcp-lte.rohc.static.udp.dst-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2697 { &hf_pdcp_lte_rohc_static_rtp,
2698 { "Static RTP chain",
2699 "pdcp-lte.rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2703 { &hf_pdcp_lte_rohc_static_rtp_ssrc,
2705 "pdcp-lte.rohc.static.rtp.ssrc", FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2706 "Static RTP chain SSRC", HFILL
2710 { &hf_pdcp_lte_rohc_dynamic_ipv4,
2711 { "Dynamic IPv4 chain",
2712 "pdcp-lte.rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2716 { &hf_pdcp_lte_rohc_dynamic_ipv4_tos,
2718 "pdcp-lte.rohc.ip.tos", FT_UINT8, BASE_HEX, NULL, 0x0,
2719 "IP Type of Service", HFILL
2722 { &hf_pdcp_lte_rohc_dynamic_ipv4_ttl,
2724 "pdcp-lte.rohc.ip.ttl", FT_UINT8, BASE_HEX, NULL, 0x0,
2725 "IP Time To Live", HFILL
2728 { &hf_pdcp_lte_rohc_dynamic_ipv4_id,
2730 "pdcp-lte.rohc.ip.id", FT_UINT8, BASE_HEX, NULL, 0x0,
2734 { &hf_pdcp_lte_rohc_dynamic_ipv4_df,
2736 "pdcp-lte.rohc.ip.df", FT_UINT8, BASE_HEX, NULL, 0x80,
2737 "IP Don't Fragment flag", HFILL
2740 { &hf_pdcp_lte_rohc_dynamic_ipv4_rnd,
2741 { "Random IP-ID field",
2742 "pdcp-lte.rohc.ip.rnd", FT_UINT8, BASE_HEX, NULL, 0x40,
2746 { &hf_pdcp_lte_rohc_dynamic_ipv4_nbo,
2747 { "Network Byte Order IP-ID field",
2748 "pdcp-lte.rohc.ip.nbo", FT_UINT8, BASE_HEX, NULL, 0x20,
2752 { &hf_pdcp_lte_rohc_dynamic_udp,
2753 { "Dynamic UDP chain",
2754 "pdcp-lte.rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2758 { &hf_pdcp_lte_rohc_dynamic_udp_checksum,
2760 "pdcp-lte.rohc.dynamic.udp.checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2764 { &hf_pdcp_lte_rohc_dynamic_udp_seqnum,
2765 { "UDP Sequence Number",
2766 "pdcp-lte.rohc.dynamic.udp.seqnum", FT_UINT16, BASE_HEX, NULL, 0x0,
2771 { &hf_pdcp_lte_rohc_dynamic_rtp,
2772 { "Dynamic RTP chain",
2773 "pdcp-lte.rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2777 { &hf_pdcp_lte_rohc_dynamic_rtp_rx,
2779 "pdcp-lte.rohc.dynamic.rtp.rx", FT_UINT8, BASE_DEC, NULL, 0x10,
2783 { &hf_pdcp_lte_rohc_dynamic_rtp_cc,
2784 { "Contributing CSRCs",
2785 "pdcp-lte.rohc.dynamic.rtp.cc", FT_UINT8, BASE_DEC, NULL, 0x0f,
2786 "Dynamic RTP chain CCs", HFILL
2789 { &hf_pdcp_lte_rohc_dynamic_rtp_seqnum,
2790 { "RTP Sequence Number",
2791 "pdcp-lte.rohc.dynamic.rtp.seqnum", FT_UINT16, BASE_DEC, NULL, 0x0,
2792 "Dynamic RTP chain Sequence Number", HFILL
2795 { &hf_pdcp_lte_rohc_dynamic_rtp_timestamp,
2797 "pdcp-lte.rohc.dynamic.rtp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
2798 "Dynamic RTP chain Timestamp", HFILL
2801 { &hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
2803 "pdcp-lte.rohc.dynamic.rtp.reserved3", FT_UINT8, BASE_HEX, NULL, 0xc0,
2804 "Reserved bits", HFILL
2807 { &hf_pdcp_lte_rohc_dynamic_rtp_x,
2809 "pdcp-lte.rohc.dynamic.rtp.x", FT_UINT8, BASE_DEC, NULL, 0x10,
2813 { &hf_pdcp_lte_rohc_dynamic_rtp_mode,
2815 "pdcp-lte.rohc.dynamic.rtp.mode", FT_UINT8, BASE_HEX, VALS(rohc_mode_vals), 0x0c,
2819 { &hf_pdcp_lte_rohc_dynamic_rtp_tis,
2821 "pdcp-lte.rohc.dynamic.rtp.tis", FT_UINT8, BASE_HEX, NULL, 0x02,
2822 "Dynamic RTP chain TIS (indicates time_stride present)", HFILL
2825 { &hf_pdcp_lte_rohc_dynamic_rtp_tss,
2827 "pdcp-lte.rohc.dynamic.rtp.tss", FT_UINT8, BASE_HEX, NULL, 0x01,
2828 "Dynamic RTP chain TSS (indicates TS_stride present)", HFILL
2831 { &hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
2833 "pdcp-lte.rohc.dynamic.rtp.ts-stride", FT_UINT32, BASE_DEC, NULL, 0x0,
2834 "Dynamic RTP chain TS Stride", HFILL
2837 { &hf_pdcp_lte_rohc_ts,
2839 "pdcp-lte.rohc.ts", FT_UINT8, BASE_DEC, NULL, 0x0,
2843 { &hf_pdcp_lte_rohc_m,
2845 "pdcp-lte.rohc.m", FT_UINT8, BASE_DEC, NULL, 0x40,
2849 { &hf_pdcp_lte_rohc_uor2_sn,
2851 "pdcp-lte.rohc.uor2.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2855 { &hf_pdcp_lte_rohc_uor2_x,
2857 "pdcp-lte.rohc.uor2.x", FT_UINT8, BASE_DEC, NULL, 0x80,
2862 { &hf_pdcp_lte_rohc_add_cid,
2864 "pdcp-lte.rohc.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
2868 { &hf_pdcp_lte_rohc_large_cid,
2870 "pdcp-lte.rohc.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
2874 { &hf_pdcp_lte_rohc_uo0_sn,
2876 "pdcp-lte.rohc.uo0.sn", FT_UINT8, BASE_DEC, NULL, 0x78,
2880 { &hf_pdcp_lte_rohc_uo0_crc,
2882 "pdcp-lte.rohc.uo0.crc", FT_UINT8, BASE_DEC, NULL, 0x07,
2886 { &hf_pdcp_lte_rohc_r0_sn,
2888 "pdcp-lte.rohc.r0.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2892 { &hf_pdcp_lte_rohc_r0_crc_sn,
2894 "pdcp-lte.rohc.r0-crc.sn", FT_UINT16, BASE_DEC, NULL, 0x0,
2898 { &hf_pdcp_lte_rohc_r0_crc_crc,
2900 "pdcp-lte.rohc.r0-crc.crc", FT_UINT8, BASE_DEC, NULL, 0x7f,
2904 { &hf_pdcp_lte_rohc_feedback_code,
2906 "pdcp-lte.rohc.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
2907 "Feedback options length (if > 0)", HFILL
2910 { &hf_pdcp_lte_rohc_feedback_size,
2912 "pdcp-lte.rohc.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
2913 "Feedback options length", HFILL
2916 { &hf_pdcp_lte_rohc_feedback_feedback1,
2917 { "FEEDBACK-1 (SN)",
2918 "pdcp-lte.rohc.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
2922 { &hf_pdcp_lte_rohc_feedback_feedback2,
2924 "pdcp-lte.rohc.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
2929 { &hf_pdcp_lte_rohc_feedback_ack_type,
2931 "pdcp-lte.rohc.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
2932 "Feedback-2 ack type", HFILL
2935 { &hf_pdcp_lte_rohc_feedback_mode,
2937 "pdcp-lte.rohc.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
2938 "Feedback mode", HFILL
2941 { &hf_pdcp_lte_rohc_feedback_sn,
2943 "pdcp-lte.rohc.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2944 "Feedback sequence number", HFILL
2948 { &hf_pdcp_lte_rohc_feedback_option,
2950 "pdcp-lte.rohc.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
2951 "Feedback option", HFILL
2954 { &hf_pdcp_lte_rohc_feedback_length,
2956 "pdcp-lte.rohc.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
2957 "Feedback length", HFILL
2960 { &hf_pdcp_lte_rohc_feedback_crc,
2962 "pdcp-lte.rohc.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
2963 "Feedback CRC", HFILL
2966 { &hf_pdcp_lte_rohc_feedback_option_sn,
2968 "pdcp-lte.rohc.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
2969 "Feedback Option SN", HFILL
2972 { &hf_pdcp_lte_rohc_feedback_option_clock,
2974 "pdcp-lte.rohc.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
2975 "Feedback Option Clock", HFILL
2979 { &hf_pdcp_lte_rohc_ip_id,
2981 "pdcp-lte.rohc.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2985 { &hf_pdcp_lte_rohc_udp_checksum,
2987 "pdcp-lte.rohc.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2991 { &hf_pdcp_lte_rohc_payload,
2993 "pdcp-lte.rohc.payload", FT_BYTES, BASE_NONE, NULL, 0x0,
3000 static gint *ett[] =
3003 &ett_pdcp_configuration,
3005 &ett_pdcp_lte_sequence_analysis,
3007 &ett_pdcp_rohc_static_ipv4,
3008 &ett_pdcp_rohc_static_udp,
3009 &ett_pdcp_rohc_static_rtp,
3010 &ett_pdcp_rohc_dynamic_ipv4,
3011 &ett_pdcp_rohc_dynamic_udp,
3012 &ett_pdcp_rohc_dynamic_rtp,
3013 &ett_pdcp_rohc_report_bitmap
3016 module_t *pdcp_lte_module;
3018 /* Register protocol. */
3019 proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
3020 proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
3021 proto_register_subtree_array(ett, array_length(ett));
3023 /* Allow other dissectors to find this one by name. */
3024 register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
3026 pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, NULL);
3028 /* Dissect uncompressed user-plane data as IP */
3029 prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
3030 "Show uncompressed User-Plane data as IP",
3031 "Show uncompressed User-Plane data as IP",
3032 &global_pdcp_dissect_user_plane_as_ip);
3034 /* Dissect unciphered signalling data as RRC */
3035 prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
3036 "Show unciphered Signalling-Plane data as RRC",
3037 "Show unciphered Signalling-Plane data as RRC",
3038 &global_pdcp_dissect_signalling_plane_as_rrc);
3040 /* Check for missing sequence numbers */
3041 prefs_register_bool_preference(pdcp_lte_module, "check_sequence_numbers",
3042 "Do sequence number analysis",
3043 "Do sequence number analysis",
3044 &global_pdcp_check_sequence_numbers);
3046 /* Attempt to dissect ROHC headers */
3047 prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
3048 "Attempt to decode ROHC data",
3049 "Attempt to decode ROHC data",
3050 &global_pdcp_dissect_rohc);
3052 prefs_register_bool_preference(pdcp_lte_module, "show_feedback_option_tag_length",
3053 "Show ROHC feedback option tag & length",
3054 "Show ROHC feedback option tag & length",
3055 &global_pdcp_show_feedback_option_tag_length);
3057 prefs_register_bool_preference(pdcp_lte_module, "heuristic_pdcp_lte_over_udp",
3058 "Try Heuristic LTE-PDCP over UDP framing",
3059 "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
3061 &global_pdcp_lte_heur);
3063 register_init_routine(&pdcp_lte_init_protocol);
3066 void proto_reg_handoff_pdcp_lte(void)
3068 /* Add as a heuristic UDP dissector */
3069 heur_dissector_add("udp", dissect_pdcp_lte_heur, proto_pdcp_lte);
3071 ip_handle = find_dissector("ip");
3072 ipv6_handle = find_dissector("ipv6");
3073 data_handle = find_dissector("data");