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 - Update to latest version of 36.323
50 - Complete ROHC support for RTP and extend to other profiles (including ROHCv2)
51 - Support for decryption
52 - Verify MAC authentication bytes
56 /* Initialize the protocol and registered fields. */
57 int proto_pdcp_lte = -1;
59 extern int proto_rlc_lte;
61 /* Configuration (info known outside of PDU) */
62 static int hf_pdcp_lte_configuration = -1;
63 static int hf_pdcp_lte_direction = -1;
64 static int hf_pdcp_lte_ueid = -1;
65 static int hf_pdcp_lte_channel_type = -1;
66 static int hf_pdcp_lte_channel_id = -1;
67 static int hf_pdcp_lte_rohc = -1;
68 static int hf_pdcp_lte_rohc_compression = -1;
69 static int hf_pdcp_lte_rohc_mode = -1;
70 static int hf_pdcp_lte_rohc_rnd = -1;
71 static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
72 static int hf_pdcp_lte_rohc_profile = -1;
73 static int hf_pdcp_lte_no_header_pdu = -1;
74 static int hf_pdcp_lte_plane = -1;
75 static int hf_pdcp_lte_seqnum_length = -1;
76 static int hf_pdcp_lte_cid_inclusion_info = -1;
77 static int hf_pdcp_lte_large_cid_present = -1;
79 /* PDCP header fields */
80 static int hf_pdcp_lte_seq_num_5 = -1;
81 static int hf_pdcp_lte_seq_num_7 = -1;
82 static int hf_pdcp_lte_reserved3 = -1;
83 static int hf_pdcp_lte_seq_num_12 = -1;
84 static int hf_pdcp_lte_signalling_data = -1;
85 static int hf_pdcp_lte_mac = -1;
86 static int hf_pdcp_lte_data_control = -1;
87 static int hf_pdcp_lte_user_plane_data = -1;
88 static int hf_pdcp_lte_control_pdu_type = -1;
89 static int hf_pdcp_lte_fms = -1;
90 static int hf_pdcp_lte_bitmap = -1;
91 static int hf_pdcp_lte_bitmap_not_received = -1;
93 /* Robust Header Compression Fields */
94 static int hf_pdcp_lte_rohc_padding = -1;
95 static int hf_pdcp_lte_rohc_r_0_crc = -1;
96 static int hf_pdcp_lte_rohc_feedback = -1;
98 static int hf_pdcp_lte_rohc_type0_t = -1;
99 static int hf_pdcp_lte_rohc_type1_t = -1;
100 static int hf_pdcp_lte_rohc_type2_t = -1;
102 static int hf_pdcp_lte_rohc_d = -1;
103 static int hf_pdcp_lte_rohc_ir_crc = -1;
105 static int hf_pdcp_lte_rohc_static_ipv4 = -1;
106 static int hf_pdcp_lte_rohc_ip_version = -1;
107 static int hf_pdcp_lte_rohc_ip_protocol = -1;
108 static int hf_pdcp_lte_rohc_ip_src = -1;
109 static int hf_pdcp_lte_rohc_ip_dst = -1;
111 static int hf_pdcp_lte_rohc_static_udp = -1;
112 static int hf_pdcp_lte_rohc_static_udp_src_port = -1;
113 static int hf_pdcp_lte_rohc_static_udp_dst_port = -1;
115 static int hf_pdcp_lte_rohc_static_rtp = -1;
116 static int hf_pdcp_lte_rohc_static_rtp_ssrc = -1;
118 static int hf_pdcp_lte_rohc_dynamic_ipv4 = -1;
119 static int hf_pdcp_lte_rohc_dynamic_ipv4_tos = -1;
120 static int hf_pdcp_lte_rohc_dynamic_ipv4_ttl = -1;
121 static int hf_pdcp_lte_rohc_dynamic_ipv4_id = -1;
122 static int hf_pdcp_lte_rohc_dynamic_ipv4_df = -1;
123 static int hf_pdcp_lte_rohc_dynamic_ipv4_rnd = -1;
124 static int hf_pdcp_lte_rohc_dynamic_ipv4_nbo = -1;
126 static int hf_pdcp_lte_rohc_dynamic_udp = -1;
127 static int hf_pdcp_lte_rohc_dynamic_udp_checksum = -1;
128 static int hf_pdcp_lte_rohc_dynamic_udp_seqnum = -1;
130 static int hf_pdcp_lte_rohc_dynamic_rtp = -1;
131 static int hf_pdcp_lte_rohc_dynamic_rtp_rx = -1;
132 static int hf_pdcp_lte_rohc_dynamic_rtp_cc = -1;
133 static int hf_pdcp_lte_rohc_dynamic_rtp_seqnum = -1;
134 static int hf_pdcp_lte_rohc_dynamic_rtp_timestamp = -1;
135 static int hf_pdcp_lte_rohc_dynamic_rtp_reserved3 = -1;
136 static int hf_pdcp_lte_rohc_dynamic_rtp_x = -1;
137 static int hf_pdcp_lte_rohc_dynamic_rtp_mode = -1;
138 static int hf_pdcp_lte_rohc_dynamic_rtp_tis = -1;
139 static int hf_pdcp_lte_rohc_dynamic_rtp_tss = -1;
140 static int hf_pdcp_lte_rohc_dynamic_rtp_ts_stride = -1;
142 static int hf_pdcp_lte_rohc_ts = -1;
143 static int hf_pdcp_lte_rohc_m = -1;
144 static int hf_pdcp_lte_rohc_uor2_sn = -1;
145 static int hf_pdcp_lte_rohc_uor2_x = -1;
147 static int hf_pdcp_lte_rohc_add_cid = -1;
148 static int hf_pdcp_lte_rohc_large_cid = -1;
150 static int hf_pdcp_lte_rohc_uo0_sn = -1;
151 static int hf_pdcp_lte_rohc_uo0_crc = -1;
153 static int hf_pdcp_lte_rohc_r0_sn = -1;
154 static int hf_pdcp_lte_rohc_r0_crc_sn = -1;
155 static int hf_pdcp_lte_rohc_r0_crc_crc = -1;
157 static int hf_pdcp_lte_rohc_feedback_code = -1;
158 static int hf_pdcp_lte_rohc_feedback_size = -1;
159 static int hf_pdcp_lte_rohc_feedback_feedback1 = -1;
160 static int hf_pdcp_lte_rohc_feedback_feedback2 = -1;
161 static int hf_pdcp_lte_rohc_feedback_ack_type = -1;
162 static int hf_pdcp_lte_rohc_feedback_mode = -1;
163 static int hf_pdcp_lte_rohc_feedback_sn = -1;
164 static int hf_pdcp_lte_rohc_feedback_option = -1;
165 static int hf_pdcp_lte_rohc_feedback_length = -1;
166 static int hf_pdcp_lte_rohc_feedback_crc = -1;
167 static int hf_pdcp_lte_rohc_feedback_option_sn = -1;
168 static int hf_pdcp_lte_rohc_feedback_option_clock = -1;
170 static int hf_pdcp_lte_rohc_ip_id = -1;
171 static int hf_pdcp_lte_rohc_udp_checksum = -1;
172 static int hf_pdcp_lte_rohc_payload = -1;
174 /* Sequence Analysis */
175 static int hf_pdcp_lte_sequence_analysis = -1;
176 static int hf_pdcp_lte_sequence_analysis_ok = -1;
177 static int hf_pdcp_lte_sequence_analysis_previous_frame = -1;
178 static int hf_pdcp_lte_sequence_analysis_expected_sn = -1;
180 static int hf_pdcp_lte_sequence_analysis_repeated = -1;
181 static int hf_pdcp_lte_sequence_analysis_skipped = -1;
186 /* Protocol subtree. */
187 static int ett_pdcp = -1;
188 static int ett_pdcp_configuration = -1;
189 static int ett_pdcp_packet = -1;
190 static int ett_pdcp_lte_sequence_analysis = -1;
191 static int ett_pdcp_rohc = -1;
192 static int ett_pdcp_rohc_static_ipv4 = -1;
193 static int ett_pdcp_rohc_static_udp = -1;
194 static int ett_pdcp_rohc_static_rtp = -1;
195 static int ett_pdcp_rohc_dynamic_ipv4 = -1;
196 static int ett_pdcp_rohc_dynamic_udp = -1;
197 static int ett_pdcp_rohc_dynamic_rtp = -1;
198 static int ett_pdcp_rohc_report_bitmap = -1;
201 static const value_string direction_vals[] =
203 { DIRECTION_UPLINK, "Uplink"},
204 { DIRECTION_DOWNLINK, "Downlink"},
209 static const value_string pdcp_plane_vals[] = {
210 { SIGNALING_PLANE, "Signalling" },
211 { USER_PLANE, "User" },
215 static const value_string logical_channel_vals[] = {
216 { Channel_DCCH, "DCCH"},
217 { Channel_BCCH, "BCCH"},
218 { Channel_CCCH, "CCCH"},
219 { Channel_PCCH, "PCCH"},
223 static const value_string rohc_mode_vals[] = {
224 { UNIDIRECTIONAL, "Unidirectional" },
225 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
226 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
232 static const value_string rohc_profile_vals[] = {
233 { 0, "Uncompressed" },
240 static const value_string pdu_type_vals[] = {
241 { 0, "Control PDU" },
246 static const value_string feedback_ack_vals[] = {
249 { 2, "STATIC-NACK" },
253 static const value_string feedback_option_vals[] = {
256 { 3, "SN-Not-Valid" },
264 static const value_string control_pdu_type_vals[] = {
265 { 0, "PDCP Status report" },
266 { 1, "Header Compression Feedback Information" },
270 static const value_string t_vals[] = {
271 { 0, "ID message format" },
272 { 1, "TS message format" },
276 static const value_string ip_protocol_vals[] = {
283 static dissector_handle_t ip_handle;
286 /* Preference variables */
287 static gboolean global_pdcp_show_feedback_option_tag_length = FALSE;
288 static gboolean global_pdcp_dissect_user_plane_as_ip = FALSE;
289 static gboolean global_pdcp_dissect_signalling_plane_as_rrc = FALSE;
290 static gboolean global_pdcp_check_sequence_numbers = FALSE;
291 static gboolean global_pdcp_dissect_rohc = FALSE;
294 /**************************************************/
295 /* Sequence number analysis */
301 LogicalChannelType channelType;
304 } pdcp_channel_hash_key;
309 guint16 previousSequenceNumber;
310 guint32 previousFrameNum;
311 } pdcp_channel_status;
313 /* The sequence analysis channel hash table.
314 Maps key -> status */
315 static GHashTable *pdcp_sequence_analysis_channel_hash = NULL;
318 static gint pdcp_channel_equal(gconstpointer v, gconstpointer v2)
320 const pdcp_channel_hash_key* val1 = v;
321 const pdcp_channel_hash_key* val2 = v2;
323 /* All fields must match */
324 return (memcmp(val1, val2, sizeof(pdcp_channel_hash_key)) == 0);
327 /* Compute a hash value for a given key. */
328 static guint pdcp_channel_hash_func(gconstpointer v)
330 const pdcp_channel_hash_key* val1 = v;
332 /* TODO: use multipliers */
333 return val1->ueId + val1->channelType + val1->channelId + val1->direction;
336 /* Hash table functions for frame reports */
338 /* TODO: copied from packet-rlc-lte.c. extern, or add to lib? */
340 static gint pdcp_frame_equal(gconstpointer v, gconstpointer v2)
345 /* Compute a hash value for a given key. */
346 static guint pdcp_frame_hash_func(gconstpointer v)
348 return GPOINTER_TO_UINT(v);
352 /* Info to attach to frame when first read, recording what to show about sequence */
355 gboolean sequenceExpectedCorrect;
356 guint16 sequenceExpected;
357 guint32 previousFrameNum;
362 enum { SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing} state;
363 } pdcp_sequence_report_in_frame;
365 /* The sequence analysis frame report hash table instance itself */
366 static GHashTable *pdcp_lte_frame_sequence_analysis_report_hash = NULL;
369 /* Add to the tree values associated with sequence analysis for this frame */
370 static void addChannelSequenceInfo(pdcp_sequence_report_in_frame *p,
371 pdcp_lte_info *p_pdcp_lte_info,
372 guint16 sequenceNumber,
373 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
375 proto_tree *seqnum_tree;
376 proto_item *seqnum_ti;
381 seqnum_ti = proto_tree_add_string_format(tree,
382 hf_pdcp_lte_sequence_analysis,
384 "", "Sequence Analysis");
385 seqnum_tree = proto_item_add_subtree(seqnum_ti,
386 ett_pdcp_lte_sequence_analysis);
387 PROTO_ITEM_SET_GENERATED(seqnum_ti);
390 /* Previous channel frame */
391 if (p->previousFrameNum != 0) {
392 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_previous_frame,
393 tvb, 0, 0, p->previousFrameNum);
396 /* Expected sequence number */
397 ti = proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_expected_sn,
398 tvb, 0, 0, p->sequenceExpected);
399 PROTO_ITEM_SET_GENERATED(ti);
401 /* Work out SN wrap (in case needed below) */
402 switch (p_pdcp_lte_info->seqnum_length) {
403 case PDCP_SN_LENGTH_5_BITS:
406 case PDCP_SN_LENGTH_7_BITS:
409 case PDCP_SN_LENGTH_12_BITS:
413 DISSECTOR_ASSERT_NOT_REACHED();
419 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
421 PROTO_ITEM_SET_GENERATED(ti);
422 proto_item_append_text(seqnum_ti, " - OK");
426 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
428 PROTO_ITEM_SET_GENERATED(ti);
429 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_skipped,
431 PROTO_ITEM_SET_GENERATED(ti);
432 if (p->lastSN != p->firstSN) {
433 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
434 "PDCP SNs (%u to %u) missing for %s on UE %u",
435 p->firstSN, p->lastSN,
436 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
437 p_pdcp_lte_info->ueid);
438 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
439 p->firstSN, p->lastSN);
442 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
443 "PDCP SN (%u) missing for %s on UE %u",
445 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
446 p_pdcp_lte_info->ueid);
447 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
453 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
455 PROTO_ITEM_SET_GENERATED(ti);
456 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_repeated,
458 PROTO_ITEM_SET_GENERATED(ti);
459 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
460 "PDCP SN (%u) repeated for %s for UE %u",
462 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
463 p_pdcp_lte_info->ueid);
464 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
469 /* Incorrect sequence number */
470 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
471 "Wrong Sequence Number for %s on UE %u - got %u, expected %u",
472 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
473 p_pdcp_lte_info->ueid, sequenceNumber, p->sequenceExpected);
479 /* Update the channel status and set report for this frame */
480 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
481 pdcp_lte_info *p_pdcp_lte_info,
482 guint16 sequenceNumber,
485 pdcp_channel_hash_key channel_key;
486 pdcp_channel_hash_key *p_channel_key;
487 pdcp_channel_status *p_channel_status;
488 pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
489 gboolean createdChannel = FALSE;
490 guint16 expectedSequenceNumber = 0;
493 /* If find stat_report_in_frame already, use that and get out */
494 if (pinfo->fd->flags.visited) {
495 p_report_in_frame = (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_frame_sequence_analysis_report_hash,
497 if (p_report_in_frame != NULL) {
498 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info,
504 /* Give up - we must have tried already... */
510 /**************************************************/
511 /* Create or find an entry for this channel state */
512 memset(&channel_key, 0, sizeof(channel_key));
513 channel_key.ueId = p_pdcp_lte_info->ueid;
514 channel_key.channelType = p_pdcp_lte_info->channelType;
515 channel_key.channelId = p_pdcp_lte_info->channelId;
516 channel_key.direction = p_pdcp_lte_info->direction;
518 /* Do the table lookup */
519 p_channel_status = (pdcp_channel_status*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash, &channel_key);
521 /* Create table entry if necessary */
522 if (p_channel_status == NULL) {
523 createdChannel = TRUE;
525 /* Allocate a new key and value */
526 p_channel_key = se_alloc(sizeof(pdcp_channel_hash_key));
527 p_channel_status = se_alloc0(sizeof(pdcp_channel_status));
529 /* Copy key contents */
530 memcpy(p_channel_key, &channel_key, sizeof(pdcp_channel_hash_key));
533 g_hash_table_insert(pdcp_sequence_analysis_channel_hash, p_channel_key, p_channel_status);
536 /* Create space for frame state_report */
537 p_report_in_frame = se_alloc(sizeof(pdcp_sequence_report_in_frame));
539 switch (p_pdcp_lte_info->seqnum_length) {
540 case PDCP_SN_LENGTH_5_BITS:
543 case PDCP_SN_LENGTH_7_BITS:
546 case PDCP_SN_LENGTH_12_BITS:
550 DISSECTOR_ASSERT_NOT_REACHED();
554 /* Work out expected sequence number */
555 if (!createdChannel) {
556 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
559 /* Set report for this frame */
560 /* For PDCP, sequence number is always expectedSequence number */
561 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
563 /* For wrong sequence number... */
564 if (!p_report_in_frame->sequenceExpectedCorrect) {
566 /* Frames are not missing if we get an earlier sequence number again */
567 if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
568 p_report_in_frame->state = SN_Missing;
569 p_report_in_frame->firstSN = expectedSequenceNumber;
570 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
572 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
573 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
575 /* Update channel status to remember *this* frame */
576 p_channel_status->previousFrameNum = pinfo->fd->num;
577 p_channel_status->previousSequenceNumber = sequenceNumber;
580 /* An SN has been repeated */
581 p_report_in_frame->state = SN_Repeated;
582 p_report_in_frame->firstSN = sequenceNumber;
584 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
585 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
590 p_report_in_frame->state = SN_OK;
591 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
592 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
594 /* Update channel status to remember *this* frame */
595 p_channel_status->previousFrameNum = pinfo->fd->num;
596 p_channel_status->previousSequenceNumber = sequenceNumber;
599 /* Associate with this frame number */
600 g_hash_table_insert(pdcp_lte_frame_sequence_analysis_report_hash, &pinfo->fd->num, p_report_in_frame);
602 /* Add state report for this frame into tree */
603 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info, sequenceNumber,
609 /***************************************************************/
612 /* Dissect a Large-CID field.
613 Return following offset */
614 static int dissect_large_cid(proto_tree *tree,
618 guint8 first_octet = tvb_get_guint8(tvb, offset);
620 if ((first_octet & 0x80) == 0) {
622 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 1,
628 guint16 bytes = tvb_get_ntohs(tvb, offset) & 0x7fff;
629 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_large_cid, tvb, offset, 2,
636 static int dissect_pdcp_dynamic_chain(proto_tree *tree,
637 proto_item *root_item _U_,
640 struct pdcp_lte_info *p_pdcp_info,
644 if (p_pdcp_info->rohc_ip_version == 4) {
645 proto_tree *dynamic_ipv4_tree;
647 int tree_start_offset = offset;
648 guint8 tos, ttl, id, rnd, nbo;
650 /* Create dynamic IPv4 subtree */
651 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_ipv4, tvb, offset, -1, FALSE);
652 dynamic_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_ipv4);
655 tos = tvb_get_guint8(tvb, offset);
656 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_tos, tvb, offset, 1, FALSE);
660 ttl = tvb_get_guint8(tvb, offset);
661 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_ttl, tvb, offset, 1, FALSE);
665 id = tvb_get_guint8(tvb, offset);
666 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_id, tvb, offset, 1, FALSE);
670 rnd = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
671 nbo = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
672 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_df, tvb, offset, 1, FALSE);
673 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_rnd, tvb, offset, 1, FALSE);
674 proto_tree_add_item(dynamic_ipv4_tree, hf_pdcp_lte_rohc_dynamic_ipv4_nbo, tvb, offset, 1, FALSE);
676 /* TODO: general extension header list... */
679 /* Set proper length for subtree */
680 proto_item_set_len(root_ti, offset-tree_start_offset);
682 /* Add summary to root item */
683 proto_item_append_text(root_ti, " (ToS=%u, TTL=%u, ID=%u, RND=%u, NBO=%u)",
684 tos, ttl, id, rnd, nbo);
688 if ((p_pdcp_info->profile == 1) ||
689 (p_pdcp_info->profile == 2)) {
691 proto_tree *dynamic_udp_tree;
693 unsigned short checksum;
695 /* Create dynamic UDP subtree */
696 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_udp, tvb, offset, 2, FALSE);
697 dynamic_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_udp);
699 /* 16-bit checksum */
700 checksum = tvb_get_ntohs(tvb, offset);
701 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_checksum, tvb, offset, 2, FALSE);
704 if (p_pdcp_info->profile == 2) {
707 seqnum = tvb_get_ntohs(tvb, offset);
708 proto_tree_add_item(dynamic_udp_tree, hf_pdcp_lte_rohc_dynamic_udp_seqnum, tvb, offset, 2, FALSE);
711 /* Add summary to root item */
712 proto_item_append_text(root_ti, " (checksum = %04x, seqnum = %u)", checksum, seqnum);
715 /* Add summary to root item */
716 proto_item_append_text(root_ti, " (checksum = %04x)", checksum);
721 if (p_pdcp_info->profile == 1) {
722 proto_tree *dynamic_rtp_tree;
724 int tree_start_offset = offset;
726 guint8 contributing_csrcs;
727 guint16 sequence_number;
732 /* Create dynamic RTP subtree */
733 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_dynamic_rtp, tvb, offset, -1, FALSE);
734 dynamic_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_dynamic_rtp);
737 /* V | P | RX | CC */
738 rx = tvb_get_guint8(tvb, offset) & 0x10;
739 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_rx, tvb, offset, 1, FALSE);
740 contributing_csrcs = tvb_get_guint8(tvb, offset) & 0x0f;
741 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_cc, tvb, offset, 1, FALSE);
748 /* Sequence number */
749 sequence_number = tvb_get_ntohs(tvb, offset);
750 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_seqnum, tvb, offset, 2, FALSE);
753 /* Timestamp (4 octets) */
754 timestamp = tvb_get_ntohl(tvb, offset);
755 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_timestamp, tvb, offset, 4, FALSE);
758 /* TODO: CSRC list */
759 /*offset += (4 * contributing_csrcs); */
762 /* TODO: Reserved | X | Mode | TIS | TIS */
764 guint8 this_byte = tvb_get_guint8(tvb, offset);
765 proto_item *reserved_ti = proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
766 tvb, offset, 1, FALSE);
768 /* Check reserved bits are 0 */
769 if ((this_byte & 0xe0) != 0) {
770 expert_add_info_format(pinfo, reserved_ti, PI_MALFORMED, PI_ERROR,
771 "Reserved bits have value 0x%x - should be 0x0",
774 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_x, tvb, offset, 1, FALSE);
775 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_mode, tvb, offset, 1, FALSE);
776 tss = (this_byte & 0x02);
777 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tss, tvb, offset, 1, FALSE);
778 tis = (this_byte & 0x01);
779 proto_tree_add_item(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_tis, tvb, offset, 1, FALSE);
783 /* TODO: the length of these fields can be learned by looked at the leading bits, see
784 RFC 3095, "4.5.6. Self-describing variable-length values" */
785 /* TODO: TS-Stride (1-4 bytes) */
787 /* Assume encoded in two bytes for now... */
788 proto_tree_add_bits_ret_val(dynamic_rtp_tree, hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
789 tvb, offset*8 + 2, 14, &ts_stride, FALSE);
793 /* TODO: Time-stride (1-4 bytes) */
797 /* Set proper length for subtree */
798 proto_item_set_len(root_ti, offset-tree_start_offset);
800 /* Add summary to root item */
801 proto_item_append_text(root_ti, " (seqnum = %u, timestamp = %u)",
802 sequence_number, timestamp);
810 static int dissect_pdcp_irdyn_packet(proto_tree *tree _U_,
811 proto_item *root_item,
814 struct pdcp_lte_info *p_pdcp_info _U_,
817 col_append_str(pinfo->cinfo, COL_INFO, " IRDYN");
818 proto_item_append_text(root_item, " (IRDYN)");
821 if (p_pdcp_info->large_cid_present) {
822 offset = dissect_large_cid(tree, tvb, offset);
826 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
830 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
833 /* Dissect dynamic chain */
834 offset = dissect_pdcp_dynamic_chain(tree,
844 static int dissect_pdcp_ir_packet(proto_tree *tree,
845 proto_item *root_item,
848 struct pdcp_lte_info *p_pdcp_info,
851 unsigned char dynamic_chain_present;
853 col_append_str(pinfo->cinfo, COL_INFO, " IR");
854 proto_item_append_text(root_item, " (IR)");
856 /* Is dynamic chain present? */
857 dynamic_chain_present = tvb_get_guint8(tvb, offset) & 0x1;
858 proto_tree_add_item(tree, hf_pdcp_lte_rohc_d, tvb, offset, 1, FALSE);
862 if (p_pdcp_info->large_cid_present) {
863 offset = dissect_large_cid(tree, tvb, offset);
867 proto_tree_add_item(tree, hf_pdcp_lte_rohc_profile, tvb, offset, 1, FALSE);
871 proto_tree_add_item(tree, hf_pdcp_lte_rohc_ir_crc, tvb, offset, 1, FALSE);
874 /* IPv4 static part */
875 if (p_pdcp_info->rohc_ip_version == 4) {
876 proto_tree *static_ipv4_tree;
878 int tree_start_offset = offset;
880 guint32 source, dest;
882 /* Create static IPv4 subtree */
883 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_ipv4, tvb, offset, -1, FALSE);
884 static_ipv4_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_ipv4);
886 /* IP version (must be 4) */
887 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_version, tvb, offset, 1, FALSE);
891 protocol = tvb_get_guint8(tvb, offset);
892 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_protocol, tvb, offset, 1, FALSE);
896 source = tvb_get_ipv4(tvb, offset);
897 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_src, tvb, offset, 4, FALSE);
901 dest = tvb_get_ipv4(tvb, offset);
902 proto_tree_add_item(static_ipv4_tree, hf_pdcp_lte_rohc_ip_dst, tvb, offset, 4, FALSE);
905 /* Set proper length for subtree */
906 proto_item_set_len(root_ti, offset-tree_start_offset);
908 /* Add summary to root item */
909 proto_item_append_text(root_ti, " (prot=%s: %s -> %s)",
910 val_to_str(protocol, ip_protocol_vals, "Unknown"),
911 (char*)get_hostname(source),
912 (char*)get_hostname(dest));
915 /* UDP static part. TODO: also check protocol from last part!? */
916 if ((p_pdcp_info->profile == 1) ||
917 (p_pdcp_info->profile == 2)) {
919 proto_tree *static_udp_tree;
921 int tree_start_offset = offset;
922 unsigned short source_port, dest_port;
924 /* Create static UDP subtree */
925 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_udp, tvb, offset, -1, FALSE);
926 static_udp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_udp);
929 source_port = tvb_get_ntohs(tvb, offset);
930 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
934 dest_port = tvb_get_ntohs(tvb, offset);
935 proto_tree_add_item(static_udp_tree, hf_pdcp_lte_rohc_static_udp_src_port, tvb, offset, 2, FALSE);
938 /* Set proper length for subtree */
939 proto_item_set_len(root_ti, offset-tree_start_offset);
941 /* Add summary to root item */
942 proto_item_append_text(root_ti, " (%u -> %u)", source_port, dest_port);
946 if (p_pdcp_info->profile == 1) {
947 proto_tree *static_rtp_tree;
951 /* Create static RTP subtree */
952 root_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_static_rtp, tvb, offset, 4, FALSE);
953 static_rtp_tree = proto_item_add_subtree(root_ti, ett_pdcp_rohc_static_rtp);
956 ssrc = tvb_get_ntohl(tvb, offset);
957 proto_tree_add_item(static_rtp_tree, hf_pdcp_lte_rohc_static_rtp_ssrc, tvb, offset, 4, FALSE);
960 /* Add summary to root item */
961 proto_item_append_text(root_ti, " (SSRC=%u)", ssrc);
966 if (dynamic_chain_present) {
967 offset = dissect_pdcp_dynamic_chain(tree,
980 static int dissect_pdcp_feedback_feedback1(proto_tree *tree,
984 struct pdcp_lte_info *p_pdcp_info _U_,
989 proto_item_append_text(item, " (type 1)");
991 /* TODO: profile-specific */
992 sn = tvb_get_guint8(tvb, offset);
993 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback1, tvb, offset, 1, FALSE);
996 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1001 /* Includes Large-CID, if present */
1002 static int dissect_pdcp_feedback_feedback2(proto_tree *tree,
1007 struct pdcp_lte_info *p_pdcp_info _U_,
1008 packet_info *pinfo _U_)
1015 const char * full_mode_name;
1018 proto_item_append_text(item, " (type 2)");
1021 if (p_pdcp_info->large_cid_present) {
1022 offset = dissect_large_cid(tree, tvb, offset);
1025 /* Feedback2 hidden filter */
1026 ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_feedback2, tvb, offset, -1, FALSE);
1027 PROTO_ITEM_SET_HIDDEN(ti);
1030 first_octet = tvb_get_guint8(tvb, offset);
1031 ack_type = (first_octet & 0xc0) >> 6;
1032 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_ack_type, tvb, offset, 1, FALSE);
1034 /* TODO: expert info on NACK? */
1037 mode = (first_octet & 0x30) >> 4;
1038 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_mode, tvb, offset, 1, FALSE);
1040 /* Show ACK-TYPE(Mode) in info column */
1041 full_mode_name = val_to_str(mode, rohc_mode_vals, "Error");
1043 col_append_fstr(pinfo->cinfo, COL_INFO, " %s(%c)",
1044 val_to_str(ack_type, feedback_ack_vals, "Unknown"),
1048 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_sn, tvb, offset, 2, FALSE);
1049 sn = tvb_get_ntohs(tvb, offset) & 0x7ff;
1052 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1054 /* Loop over any remaining feedback options */
1055 size_remaining = size - 2;
1057 while (tvb_length_remaining(tvb, offset) > 0) {
1058 guint8 option = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
1059 guint8 length = tvb_get_guint8(tvb, offset) & 0x0f;
1060 guint8 one_byte_value;
1062 /* Preference setting controls showing option and lengths */
1063 if (global_pdcp_show_feedback_option_tag_length) {
1064 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option, tvb, offset, 1, FALSE);
1065 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_length, tvb, offset, 1, FALSE);
1070 /* TODO: switch including missing option types */
1074 one_byte_value = tvb_get_guint8(tvb, offset);
1075 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_crc, tvb, offset, 1, FALSE);
1076 col_append_fstr(pinfo->cinfo, COL_INFO, " CRC=%u ", one_byte_value);
1082 /* SN-Not-Valid: TODO */
1086 one_byte_value = tvb_get_guint8(tvb, offset);
1087 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_sn, tvb, offset, 1, FALSE);
1088 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u ", one_byte_value);
1092 one_byte_value = tvb_get_guint8(tvb, offset);
1093 proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback_option_clock, tvb, offset, 1, FALSE);
1094 col_append_fstr(pinfo->cinfo, COL_INFO, " Clock=%u ", one_byte_value);
1104 /* TODO: unhandled option */
1110 size_remaining -= length;
1117 /* Dissect a feedback packet.
1118 Return following offset */
1119 static int dissect_pdcp_feedback_packet(proto_tree *tree,
1120 proto_item *root_item,
1123 struct pdcp_lte_info *p_pdcp_info,
1129 proto_item *feedback_ti;
1130 proto_tree *feedback_tree;
1132 col_append_str(pinfo->cinfo, COL_INFO, " Feedback");
1133 proto_item_append_text(root_item, " (Feedback)");
1135 /* Create feedback tree root */
1136 feedback_ti = proto_tree_add_item(tree, hf_pdcp_lte_rohc_feedback, tvb, offset, -1, FALSE);
1137 feedback_tree = proto_item_add_subtree(feedback_ti, ett_pdcp_packet);
1140 code = tvb_get_guint8(tvb, offset) & 0x07;
1141 ti = proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_code, tvb, offset, 1, FALSE);
1144 /* Optional length field */
1146 proto_item_append_text(ti, " (length of feedback data)");
1150 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_feedback_size, tvb, offset, 1, FALSE);
1151 size = tvb_get_guint8(tvb, offset);
1155 /* Work out feedback type */
1156 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
1157 !p_pdcp_info->large_cid_present) {
1161 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
1163 else if ((size > 1) && ((tvb_get_guint8(tvb, offset) & 0xc0) == 0xc0)) {
1165 proto_tree_add_item(feedback_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
1169 offset = dissect_pdcp_feedback_feedback1(feedback_tree, feedback_ti, tvb, offset, p_pdcp_info, pinfo);
1172 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1176 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1180 offset = dissect_pdcp_feedback_feedback2(feedback_tree, feedback_ti, tvb, offset, size, p_pdcp_info, pinfo);
1187 /* Dissect R-0 packet.
1188 Return following offset */
1189 static int dissect_pdcp_r_0_packet(proto_tree *tree,
1190 proto_item *root_item,
1193 struct pdcp_lte_info *p_pdcp_info _U_,
1198 col_append_str(pinfo->cinfo, COL_INFO, " R-0");
1199 proto_item_append_text(root_item, " (R-0)");
1202 sn = tvb_get_guint8(tvb, offset) & 0x3f;
1203 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_sn, tvb, offset, 1, FALSE);
1207 if (p_pdcp_info->large_cid_present) {
1208 offset = dissect_large_cid(tree, tvb, offset);
1211 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1217 /* Dissect R-0-CRC packet.
1218 Return following offset */
1219 static int dissect_pdcp_r_0_crc_packet(proto_tree *tree,
1220 proto_item *root_item,
1223 struct pdcp_lte_info *p_pdcp_info,
1228 col_append_str(pinfo->cinfo, COL_INFO, " R-0-CRC");
1229 proto_item_append_text(root_item, " (R-0-CRC)");
1231 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r_0_crc, tvb, offset, -1, FALSE);
1234 /* TODO: wrong! Large-cid may be in-between!!!! */
1235 sn = tvb_get_guint8(tvb, offset) & 0x3f;
1239 if (p_pdcp_info->large_cid_present) {
1240 offset = dissect_large_cid(tree, tvb, offset);
1244 sn = (sn << 1) + ((tvb_get_guint8(tvb, offset) & 0x80) >> 7);
1245 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_r0_crc_sn, tvb, offset, 1, sn);
1248 proto_tree_add_item(tree, hf_pdcp_lte_rohc_r0_crc_crc, tvb, offset, 1, FALSE);
1251 /* Show SN in info column */
1252 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1258 /* Dissect UO-0-CRC packet.
1259 Return following offset */
1260 static int dissect_pdcp_uo_0_packet(proto_tree *tree,
1261 proto_item *root_item,
1264 struct pdcp_lte_info *p_pdcp_info,
1269 col_append_str(pinfo->cinfo, COL_INFO, " U0-0");
1270 proto_item_append_text(root_item, " (UO-0)");
1273 sn = (tvb_get_guint8(tvb, offset) & 0x78) >> 3;
1274 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_sn, tvb, offset, 1, FALSE);
1277 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uo0_crc, tvb, offset, 1, FALSE);
1282 if (p_pdcp_info->large_cid_present) {
1283 offset = dissect_large_cid(tree, tvb, offset);
1286 /* Show SN in info column */
1287 col_append_fstr(pinfo->cinfo, COL_INFO, " (sn=%u)", sn);
1293 /* Dissect R-1 packet.
1294 Return following offset */
1295 static int dissect_pdcp_r_1_packet(proto_tree *tree,
1296 proto_item *root_item,
1299 struct pdcp_lte_info *p_pdcp_info,
1302 col_append_str(pinfo->cinfo, COL_INFO, " R-1");
1303 proto_item_append_text(root_item, " (R-1)");
1305 /* TODO: octet before large-cid */
1309 if (p_pdcp_info->large_cid_present) {
1310 offset = dissect_large_cid(tree, tvb, offset);
1313 if (p_pdcp_info->profile == 1) {
1316 else if (p_pdcp_info->profile == 2) {
1324 /* Dissect R-1-TS or R-1-ID packet.
1325 Return following offset */
1326 static int dissect_pdcp_r_1_ts_or_id_packet(proto_tree *tree,
1327 proto_item *root_item,
1330 struct pdcp_lte_info *p_pdcp_info,
1335 /* TODO: octet before large-cid */
1339 if (p_pdcp_info->large_cid_present) {
1340 offset = dissect_large_cid(tree, tvb, offset);
1343 /* T determines frame type */
1344 T = tvb_get_guint8(tvb, ++offset) >> 7;
1345 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type1_t, tvb, offset, 1, FALSE);
1347 col_append_str(pinfo->cinfo, COL_INFO, " R-1-TS");
1348 proto_item_append_text(root_item, " (R-1-TS)");
1351 col_append_str(pinfo->cinfo, COL_INFO, " R-1-ID");
1352 proto_item_append_text(root_item, " (R-1-ID)");
1355 if (p_pdcp_info->profile == 1) {
1358 else if (p_pdcp_info->profile == 2) {
1366 /* Dissect UO-1 packet.
1367 Return following offset */
1368 static int dissect_pdcp_uo_1_packet(proto_tree *tree,
1369 proto_item *root_item,
1372 struct pdcp_lte_info *p_pdcp_info,
1375 col_append_str(pinfo->cinfo, COL_INFO, " UO-1");
1376 proto_item_append_text(root_item, " (UO-1)");
1378 /* TODO: octet before large-cid */
1382 if (p_pdcp_info->large_cid_present) {
1383 offset = dissect_large_cid(tree, tvb, offset);
1386 if (p_pdcp_info->profile == 1) {
1389 else if (p_pdcp_info->profile == 2) {
1397 /* Dissect UO-1-TS or UO-1-ID packet.
1398 Return following offset */
1399 static int dissect_pdcp_uo_1_ts_or_id_packet(proto_tree *tree,
1400 proto_item *root_item,
1403 struct pdcp_lte_info *p_pdcp_info,
1408 /* TODO: octet before large-cid */
1412 if (p_pdcp_info->large_cid_present) {
1413 offset = dissect_large_cid(tree, tvb, offset);
1416 /* T determines frame type */
1417 T = tvb_get_guint8(tvb, ++offset) >> 5;
1418 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type0_t, tvb, offset, 1, FALSE);
1420 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-TS");
1421 proto_item_append_text(root_item, " (UO-1-TS)");
1424 col_append_str(pinfo->cinfo, COL_INFO, " UO-1-ID");
1425 proto_item_append_text(root_item, " (UO-1-ID)");
1428 if (p_pdcp_info->profile == 1) {
1431 else if (p_pdcp_info->profile == 2) {
1442 /* Dissect UOR-2 packet.
1443 Return following offset */
1444 static int dissect_pdcp_uor_2_packet(proto_tree *tree,
1445 proto_item *root_item,
1448 struct pdcp_lte_info *p_pdcp_info,
1453 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2");
1454 proto_item_append_text(root_item, " (UOR-2)");
1456 /* TS straddles CID */
1457 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1461 if (p_pdcp_info->large_cid_present) {
1462 offset = dissect_large_cid(tree, tvb, offset);
1465 /* Last bit of TS is here */
1466 ts = (ts << 1) | (tvb_get_guint8(tvb, offset) >> 7);
1467 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1469 if (p_pdcp_info->profile == 1) {
1471 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, FALSE);
1474 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_sn, tvb, offset, 1, FALSE);
1478 proto_tree_add_item(tree, hf_pdcp_lte_rohc_uor2_x, tvb, offset, 1, FALSE);
1483 else if (p_pdcp_info->profile == 2) {
1492 /* Dissect UOR-2-TS or UOR-2-ID packet.
1493 Return following offset */
1494 static int dissect_pdcp_uor_2_ts_or_id_packet(proto_tree *tree,
1495 proto_item *root_item,
1498 struct pdcp_lte_info *p_pdcp_info,
1503 /* TODO: octet before large-cid.
1504 TODO: can't decode this until we know what T is,
1505 but T is after large-cid... */
1508 /* T determines frame type */
1509 T = tvb_get_guint8(tvb, offset) >> 7;
1510 proto_tree_add_item(tree, hf_pdcp_lte_rohc_type2_t, tvb, offset, 1, FALSE);
1513 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-TS");
1514 proto_item_append_text(root_item, " (UOR-2-TS)");
1517 col_append_str(pinfo->cinfo, COL_INFO, " U0R-2-ID");
1518 proto_item_append_text(root_item, " (UOR-2-ID)");
1523 /* UOR-2-TS format */
1526 guint8 ts = tvb_get_guint8(tvb, offset) & 0x1f;
1527 proto_tree_add_uint(tree, hf_pdcp_lte_rohc_ts, tvb, offset, 1, ts);
1531 if (p_pdcp_info->large_cid_present) {
1532 offset = dissect_large_cid(tree, tvb, offset);
1536 proto_tree_add_item(tree, hf_pdcp_lte_rohc_m, tvb, offset, 1, ts);
1541 /* TODO: UOR-2-ID format */
1546 if (p_pdcp_info->large_cid_present) {
1547 offset = dissect_large_cid(tree, tvb, offset);
1553 if (p_pdcp_info->profile == 1) {
1556 else if (p_pdcp_info->profile == 2) {
1566 /* Show in the tree the config info attached to this frame, as generated fields */
1567 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1568 pdcp_lte_info *p_pdcp_info)
1571 proto_tree *configuration_tree;
1572 proto_item *configuration_ti = proto_tree_add_item(tree,
1573 hf_pdcp_lte_configuration,
1575 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
1578 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_direction, tvb, 0, 0,
1579 p_pdcp_info->direction);
1580 PROTO_ITEM_SET_GENERATED(ti);
1583 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
1584 p_pdcp_info->plane);
1585 PROTO_ITEM_SET_GENERATED(ti);
1588 if (p_pdcp_info->ueid != 0) {
1589 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_ueid, tvb, 0, 0,
1591 PROTO_ITEM_SET_GENERATED(ti);
1595 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_type, tvb, 0, 0,
1596 p_pdcp_info->channelType);
1597 PROTO_ITEM_SET_GENERATED(ti);
1598 if (p_pdcp_info->channelId != 0) {
1600 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_id, tvb, 0, 0,
1601 p_pdcp_info->channelId);
1602 PROTO_ITEM_SET_GENERATED(ti);
1606 /* User-plane-specific fields */
1607 if (p_pdcp_info->plane == USER_PLANE) {
1610 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
1611 p_pdcp_info->no_header_pdu);
1612 PROTO_ITEM_SET_GENERATED(ti);
1614 if (!p_pdcp_info->no_header_pdu) {
1617 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
1618 p_pdcp_info->seqnum_length);
1619 PROTO_ITEM_SET_GENERATED(ti);
1623 /* ROHC compression */
1624 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
1625 p_pdcp_info->rohc_compression);
1626 PROTO_ITEM_SET_GENERATED(ti);
1628 /* ROHC-specific settings */
1629 if (p_pdcp_info->rohc_compression) {
1631 /* Show ROHC mode */
1632 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
1634 PROTO_ITEM_SET_GENERATED(ti);
1637 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
1639 PROTO_ITEM_SET_GENERATED(ti);
1642 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
1643 p_pdcp_info->udp_checkum_present);
1644 PROTO_ITEM_SET_GENERATED(ti);
1647 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
1648 p_pdcp_info->profile);
1649 PROTO_ITEM_SET_GENERATED(ti);
1651 /* CID Inclusion Info */
1652 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
1653 p_pdcp_info->cid_inclusion_info);
1654 PROTO_ITEM_SET_GENERATED(ti);
1657 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
1658 p_pdcp_info->large_cid_present);
1659 PROTO_ITEM_SET_GENERATED(ti);
1662 /* Append summary to configuration root */
1663 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
1664 val_to_str(p_pdcp_info->direction, direction_vals, "Unknown"),
1665 val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1667 if (p_pdcp_info->rohc_compression) {
1668 const char *mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
1669 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
1671 val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unknown"));
1673 proto_item_append_text(configuration_ti, ")");
1674 PROTO_ITEM_SET_GENERATED(configuration_ti);
1676 /* Show plane in info column */
1677 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
1678 val_to_str(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1683 /* Look for an RRC dissector for signalling data (using channel type and direction) */
1684 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_lte_info *p_pdcp_info)
1686 dissector_handle_t rrc_handle = 0;
1688 switch (p_pdcp_info->channelType)
1691 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1692 rrc_handle = find_dissector("lte_rrc.ul_ccch");
1695 rrc_handle = find_dissector("lte_rrc.dl_ccch");
1699 rrc_handle = find_dissector("lte-rrc.pcch");
1702 switch (p_pdcp_info->BCCHTransport) {
1704 rrc_handle = find_dissector("lte-rrc.bcch.bch");
1706 case DLSCH_TRANSPORT:
1707 rrc_handle = find_dissector("lte-rrc.bcch.dl.sch");
1712 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1713 rrc_handle = find_dissector("lte_rrc.ul_dcch");
1716 rrc_handle = find_dissector("lte_rrc.dl_dcch");
1729 /* Forwad declarations */
1730 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
1732 /* Heuristic dissection */
1733 static gboolean global_pdcp_lte_heur = FALSE;
1735 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
1736 static gboolean dissect_pdcp_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
1740 struct pdcp_lte_info *p_pdcp_lte_info;
1743 gboolean infoAlreadySet = FALSE;
1744 gboolean seqnumLengthTagPresent = FALSE;
1746 /* This is a heuristic dissector, which means we get all the UDP
1747 * traffic not sent to a known dissector and not claimed by
1748 * a heuristic dissector called before us!
1751 if (!global_pdcp_lte_heur) {
1755 /* Do this again on re-dissection to re-discover offset of actual PDU */
1757 /* Needs to be at least as long as:
1758 - the signature string
1759 - fixed header bytes
1761 - at least one byte of PDCP PDU payload */
1762 if ((size_t)tvb_length_remaining(tvb, offset) < (strlen(PDCP_LTE_START_STRING)+3+2)) {
1766 /* OK, compare with signature string */
1767 if (tvb_strneql(tvb, offset, PDCP_LTE_START_STRING, strlen(PDCP_LTE_START_STRING)) != 0) {
1770 offset += (gint)strlen(PDCP_LTE_START_STRING);
1773 /* If redissecting, use previous info struct (if available) */
1774 p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1775 if (p_pdcp_lte_info == NULL) {
1776 /* Allocate new info struct for this frame */
1777 p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
1778 infoAlreadySet = FALSE;
1781 infoAlreadySet = TRUE;
1785 /* Read fixed fields */
1786 p_pdcp_lte_info->no_header_pdu = tvb_get_guint8(tvb, offset++);
1787 p_pdcp_lte_info->plane = tvb_get_guint8(tvb, offset++);
1788 p_pdcp_lte_info->rohc_compression = tvb_get_guint8(tvb, offset++);
1790 /* Read optional fields */
1791 while (tag != PDCP_LTE_PAYLOAD_TAG) {
1792 /* Process next tag */
1793 tag = tvb_get_guint8(tvb, offset++);
1795 case PDCP_LTE_SEQNUM_LENGTH_TAG:
1796 p_pdcp_lte_info->seqnum_length = tvb_get_guint8(tvb, offset);
1798 seqnumLengthTagPresent = TRUE;
1800 case PDCP_LTE_DIRECTION_TAG:
1801 p_pdcp_lte_info->direction = tvb_get_guint8(tvb, offset);
1804 case PDCP_LTE_LOG_CHAN_TYPE_TAG:
1805 p_pdcp_lte_info->channelType = tvb_get_guint8(tvb, offset);
1808 case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG:
1809 p_pdcp_lte_info->BCCHTransport = tvb_get_guint8(tvb, offset);
1812 case PDCP_LTE_ROHC_IP_VERSION_TAG:
1813 p_pdcp_lte_info->rohc_ip_version = tvb_get_ntohs(tvb, offset);
1816 case PDCP_LTE_ROHC_CID_INC_INFO_TAG:
1817 p_pdcp_lte_info->cid_inclusion_info = tvb_get_guint8(tvb, offset);
1820 case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG:
1821 p_pdcp_lte_info->large_cid_present = tvb_get_guint8(tvb, offset);
1824 case PDCP_LTE_ROHC_MODE_TAG:
1825 p_pdcp_lte_info->mode = tvb_get_guint8(tvb, offset);
1828 case PDCP_LTE_ROHC_RND_TAG:
1829 p_pdcp_lte_info->rnd = tvb_get_guint8(tvb, offset);
1832 case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG:
1833 p_pdcp_lte_info->udp_checkum_present = tvb_get_guint8(tvb, offset);
1836 case PDCP_LTE_ROHC_PROFILE_TAG:
1837 p_pdcp_lte_info->profile = tvb_get_ntohs(tvb, offset);
1841 case PDCP_LTE_PAYLOAD_TAG:
1842 /* Have reached data, so get out of loop */
1846 /* It must be a recognised tag */
1851 if ((p_pdcp_lte_info->plane == USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
1852 /* Conditional field is not present */
1856 if (!infoAlreadySet) {
1857 /* Store info in packet */
1858 p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
1861 /**************************************/
1862 /* OK, now dissect as PDCP LTE */
1864 /* Create tvb that starts at actual PDCP PDU */
1865 pdcp_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
1866 dissect_pdcp_lte(pdcp_tvb, pinfo, tree);
1871 /******************************/
1872 /* Main dissection function. */
1873 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1876 proto_tree *pdcp_tree = NULL;
1877 proto_item *root_ti = NULL;
1878 proto_tree *rohc_tree = NULL;
1879 proto_item *rohc_ti = NULL;
1882 struct pdcp_lte_info *p_pdcp_info;
1883 guint8 base_header_byte;
1884 gboolean udp_checksum_needed = TRUE;
1885 gboolean ip_id_needed = TRUE;
1887 /* Append this protocol name rather than replace. */
1888 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
1890 /* Create pdcp tree. */
1892 root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, FALSE);
1893 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1897 /* Look for attached packet info! */
1898 p_pdcp_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1899 /* Can't dissect anything without it... */
1900 if (p_pdcp_info == NULL) {
1905 /* Set mode string */
1906 mode = val_to_str(p_pdcp_info->mode, rohc_mode_vals, "Error");
1908 /* Show configuration (attached packet) info in tree */
1910 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1913 /* Show ROHC mode */
1914 if (p_pdcp_info->rohc_compression) {
1915 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1919 /* Handle PDCP header (if present) */
1920 if (!p_pdcp_info->no_header_pdu) {
1922 /* TODO: shouldn't need to initialise this one!! */
1924 gboolean seqnum_set = FALSE;
1926 /*****************************/
1927 /* Signalling plane messages */
1928 if (p_pdcp_info->plane == SIGNALING_PLANE) {
1930 guint32 data_length;
1932 /* 5-bit sequence number */
1933 seqnum = tvb_get_guint8(tvb, offset) & 0x1f;
1935 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, FALSE);
1936 col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%-2u ", seqnum);
1940 /* RRC data is all but last 4 bytes.
1941 Call lte-rrc dissector (according to direction and channel type) */
1942 if (global_pdcp_dissect_signalling_plane_as_rrc) {
1943 /* Get appropriate dissector handle */
1944 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1946 if (rrc_handle != 0) {
1947 /* Call RRC dissector if have one */
1948 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
1949 tvb_length_remaining(tvb, offset) - 4,
1950 tvb_length_remaining(tvb, offset) - 4);
1951 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
1954 /* Just show data */
1955 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1956 tvb_length_remaining(tvb, offset) - 4, FALSE);
1960 /* Just show as unparsed data */
1961 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1962 tvb_length_remaining(tvb, offset) - 4, FALSE);
1965 data_length = tvb_length_remaining(tvb, offset) - 4;
1966 offset += data_length;
1968 /* Last 4 bytes are MAC */
1969 mac = tvb_get_ntohl(tvb, offset);
1970 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, FALSE);
1973 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
1977 else if (p_pdcp_info->plane == USER_PLANE) {
1979 /**********************************/
1980 /* User-plane messages */
1981 gboolean pdu_type = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
1983 /* Data/Control flag */
1984 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, FALSE);
1986 if (pdu_type == 1) {
1987 /*****************************/
1988 /* Use-plane Data */
1990 /* Number of sequence number bits depends upon config */
1991 if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_7_BITS) {
1992 seqnum = tvb_get_guint8(tvb, offset) & 0x7f;
1994 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, FALSE);
1997 else if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_12_BITS) {
1999 guint8 reserved_value;
2001 /* 3 reserved bits */
2002 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, FALSE);
2003 reserved_value = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
2005 /* Complain if not 0 */
2006 if (reserved_value != 0) {
2007 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
2008 "Reserved bits have value 0x%x - should be 0x0",
2012 /* 12-bit sequence number */
2013 seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
2015 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, FALSE);
2019 /* Not a recognised data format!!!!! */
2023 col_append_fstr(pinfo->cinfo, COL_INFO, " sn=%-4u ", seqnum);
2026 /*******************************/
2027 /* User-plane Control messages */
2028 guint8 control_pdu_type = (tvb_get_guint8(tvb, offset) & 0x70) >> 4;
2029 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, FALSE);
2031 switch (control_pdu_type) {
2032 case 0: /* PDCP status report */
2035 guint not_received = 0;
2037 proto_tree *bitmap_tree;
2038 proto_item *bitmap_ti = NULL;
2040 /* First-Missing-Sequence SN */
2041 fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
2042 sn = (fms + 1) % 4096;
2043 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
2048 if (tvb_length_remaining(tvb, offset) > 0) {
2049 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
2051 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_rohc_report_bitmap);
2054 /* For each byte... */
2055 for ( ; tvb_length_remaining(tvb, offset); offset++) {
2056 guint bit_offset = 0;
2057 /* .. look for error (0) in each bit */
2058 for ( ; bit_offset < 8; bit_offset++) {
2059 if ((tvb_get_guint8(tvb, offset) >> (7-bit_offset) & 0x1) == 0) {
2060 proto_tree_add_boolean_format_value(bitmap_tree, hf_pdcp_lte_bitmap_not_received, tvb, offset, 1, TRUE,
2064 sn = (sn + 1) % 4096;
2069 if (bitmap_ti != NULL) {
2070 proto_item_append_text(bitmap_ti, " (not-received=%u)", not_received);
2072 col_append_fstr(pinfo->cinfo, COL_INFO,
2073 " Status Report (fms=%u) not-received=%u",
2078 case 1: /* ROHC Feedback */
2080 break; /* Drop-through to dissect feedback */
2082 default: /* Reserved */
2088 /* Invalid plane setting...! */
2089 col_append_fstr(pinfo->cinfo, COL_INFO, " - INVALID PLANE (%u)",
2090 p_pdcp_info->plane);
2094 /* For now, only do sequence analysis if RLC wasn't present in the frame */
2095 /* This can be fixed once RLC does re-assembly... */
2096 if (global_pdcp_check_sequence_numbers && seqnum_set &&
2097 (p_get_proto_data(pinfo->fd, proto_rlc_lte) == NULL)) {
2099 checkChannelSequenceInfo(pinfo, tvb, p_pdcp_info,
2100 (guint16)seqnum, pdcp_tree);
2105 /* Show that its a no-header PDU */
2106 col_append_str(pinfo->cinfo, COL_INFO, " No-Header ");
2110 /* If not compressed with ROHC, show as user-plane data */
2111 if (!p_pdcp_info->rohc_compression) {
2112 if (tvb_length_remaining(tvb, offset) > 0) {
2113 if (p_pdcp_info->plane == USER_PLANE) {
2114 if (global_pdcp_dissect_user_plane_as_ip) {
2115 tvbuff_t *payload_tvb = tvb_new_subset_remaining(tvb, offset);
2116 call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree);
2119 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, FALSE);
2123 if (global_pdcp_dissect_signalling_plane_as_rrc) {
2124 /* Get appropriate dissector handle */
2125 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
2127 if (rrc_handle != 0) {
2128 /* Call RRC dissector if have one */
2129 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
2130 tvb_length_remaining(tvb, offset),
2131 tvb_length_remaining(tvb, offset));
2132 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree);
2135 /* Just show data */
2136 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
2137 tvb_length_remaining(tvb, offset), FALSE);
2141 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset, -1, FALSE);
2145 col_append_fstr(pinfo->cinfo, COL_INFO, "(%u bytes data)",
2146 tvb_length_remaining(tvb, offset));
2152 /***************************/
2154 /***************************/
2156 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
2157 val_to_str(p_pdcp_info->profile, rohc_profile_vals, "Unkown"));
2159 /* Only attempt ROHC if configured to */
2160 if (!global_pdcp_dissect_rohc) {
2164 /* Create pdcp tree. */
2166 rohc_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_rohc, tvb, offset, -1, FALSE);
2167 rohc_tree = proto_item_add_subtree(rohc_ti, ett_pdcp_rohc);
2170 rohc_offset = offset;
2172 /* Skip any leading padding octets (11100000) */
2173 while (tvb_get_guint8(tvb, offset) == 0xe0) {
2176 if (offset > rohc_offset) {
2177 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_padding, tvb, rohc_offset,
2178 offset-rohc_offset, FALSE);
2182 if ((p_pdcp_info->cid_inclusion_info == CID_IN_ROHC_PACKET) &&
2183 !p_pdcp_info->large_cid_present)
2185 if (((tvb_get_guint8(tvb, offset) >> 4) & 0x0f) == 0x0e) {
2186 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 1, FALSE);
2190 /* Assume CID value of 0 if field absent */
2191 proto_item *ti = proto_tree_add_uint(rohc_tree, hf_pdcp_lte_rohc_add_cid, tvb, offset, 0, 0);
2192 PROTO_ITEM_SET_GENERATED(ti);
2196 /* Now look at first octet of base header and identify packet type */
2197 base_header_byte = tvb_get_guint8(tvb, offset);
2200 if ((base_header_byte & 0xfe) == 0xfc) {
2201 offset = dissect_pdcp_ir_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2202 udp_checksum_needed = FALSE;
2203 ip_id_needed = FALSE;
2206 /* IRDYN (11111000) */
2207 else if (base_header_byte == 0xf8) {
2208 offset = dissect_pdcp_irdyn_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2209 udp_checksum_needed = FALSE;
2210 ip_id_needed = FALSE;
2213 /* Feedback (begins with 11110) */
2214 else if (((base_header_byte & 0xf8) >> 3) == 0x1e) {
2215 offset = dissect_pdcp_feedback_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2219 /* Packet type 0 (0) */
2220 else if ((base_header_byte & 0x80) == 0) {
2222 /* TODO: decide type based upon:
2225 - length remaining (taking into account large-cid) */
2227 /* R-0 begins with 00 */
2228 if (((base_header_byte & 0xc0) == 0) &&
2229 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
2231 offset = dissect_pdcp_r_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2234 /* R-0-CRC begins with 01 */
2235 else if ((((base_header_byte & 0x40) >> 6) == 1) &&
2236 (p_pdcp_info->mode == RELIABLE_BIDIRECTIONAL)) {
2238 offset = dissect_pdcp_r_0_crc_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2242 offset = dissect_pdcp_uo_0_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2246 /* Packet type 1 (10) */
2247 else if (((base_header_byte & 0xc0) >> 6) == 2) {
2249 switch (p_pdcp_info->mode) {
2251 case RELIABLE_BIDIRECTIONAL:
2252 /* R-1 if !(ipv4 && rand) */
2253 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2254 (!p_pdcp_info->rnd))) {
2255 offset = dissect_pdcp_r_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2259 /* Whether its R-1-ID or R-1-TS depends upon T bit */
2260 dissect_pdcp_r_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2265 case UNIDIRECTIONAL:
2266 case OPTIMISTIC_BIDIRECTIONAL:
2267 /* UO-1 if !(ipv4 && rand) */
2268 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2269 (!p_pdcp_info->rnd))) {
2270 offset = dissect_pdcp_uo_1_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2274 /* Whether its UO-1-ID or UO-1-TS depends upon T bit */
2275 dissect_pdcp_uo_1_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2284 /* Packet type 2 (110) */
2285 else if (((base_header_byte & 0xe0) >> 5) == 6) {
2287 /* UOR-2 if !(ipv4 && rand) */
2288 if (!((p_pdcp_info->rohc_ip_version == 4) &&
2289 (!p_pdcp_info->rnd))) {
2291 offset = dissect_pdcp_uor_2_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2294 /* Whether its UOR-2-ID or UOR-2-TS depends upon T bit */
2295 dissect_pdcp_uor_2_ts_or_id_packet(rohc_tree, rohc_ti, tvb, offset, p_pdcp_info, pinfo);
2300 /* Segment (1111111) */
2301 else if ((base_header_byte & 0xfe) == 0xfe) {
2307 /* Fields beyond base header */
2309 /* These 2 fields not present for IR, IR-DYN frames */
2312 if (p_pdcp_info->rnd && ip_id_needed) {
2313 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_ip_id, tvb, offset, 2, FALSE);
2318 if (p_pdcp_info->udp_checkum_present && udp_checksum_needed) {
2319 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_udp_checksum, tvb, offset, 2, FALSE);
2324 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2325 proto_tree_add_item(rohc_tree, hf_pdcp_lte_rohc_payload, tvb, offset, -1, FALSE);
2329 /* Initializes the hash table and the mem_chunk area each time a new
2330 * file is loaded or re-loaded in wireshark */
2332 pdcp_lte_init_protocol(void)
2334 /* Destroy any existing hashes. */
2335 if (pdcp_sequence_analysis_channel_hash) {
2336 g_hash_table_destroy(pdcp_sequence_analysis_channel_hash);
2338 if (pdcp_lte_frame_sequence_analysis_report_hash) {
2339 g_hash_table_destroy(pdcp_lte_frame_sequence_analysis_report_hash);
2343 /* Now create them over */
2344 pdcp_sequence_analysis_channel_hash = g_hash_table_new(pdcp_channel_hash_func, pdcp_channel_equal);
2345 pdcp_lte_frame_sequence_analysis_report_hash = g_hash_table_new(pdcp_frame_hash_func, pdcp_frame_equal);
2350 void proto_register_pdcp(void)
2352 static hf_register_info hf[] =
2354 { &hf_pdcp_lte_configuration,
2356 "pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
2357 "Configuration info passed into dissector", HFILL
2361 { &hf_pdcp_lte_rohc_compression,
2362 { "ROHC Compression",
2363 "pdcp-lte.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2367 { &hf_pdcp_lte_rohc_mode,
2369 "pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
2373 { &hf_pdcp_lte_rohc_rnd,
2374 { "RND", /* TODO: true/false vals? */
2375 "pdcp-lte.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
2376 "RND of outer ip header", HFILL
2379 { &hf_pdcp_lte_rohc_udp_checksum_present,
2380 { "UDP Checksum", /* TODO: true/false vals? */
2381 "pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2382 "UDP Checksum present", HFILL
2385 { &hf_pdcp_lte_direction,
2387 "pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2388 "Direction of message", HFILL
2391 { &hf_pdcp_lte_ueid,
2393 "pdcp-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
2394 "UE Identifier", HFILL
2397 { &hf_pdcp_lte_channel_type,
2399 "pdcp-lte.channel-type", FT_UINT8, BASE_DEC, VALS(logical_channel_vals), 0x0,
2403 { &hf_pdcp_lte_channel_id,
2405 "pdcp-lte.channel-id", FT_UINT8, BASE_DEC, 0, 0x0,
2409 { &hf_pdcp_lte_rohc_profile,
2411 "pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
2415 { &hf_pdcp_lte_no_header_pdu,
2417 "pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
2421 { &hf_pdcp_lte_plane,
2423 "pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
2427 { &hf_pdcp_lte_seqnum_length,
2429 "pdcp-lte.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
2430 "Sequence Number Length", HFILL
2435 { &hf_pdcp_lte_cid_inclusion_info,
2436 { "CID Inclusion Info",
2437 "pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
2441 { &hf_pdcp_lte_large_cid_present,
2442 { "Large CID Present",
2443 "pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2448 { &hf_pdcp_lte_seq_num_5,
2450 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
2451 "PDCP Seq num", HFILL
2454 { &hf_pdcp_lte_seq_num_7,
2456 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
2457 "PDCP Seq num", HFILL
2460 { &hf_pdcp_lte_reserved3,
2462 "pdcp-lte.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
2463 "3 reserved bits", HFILL
2466 { &hf_pdcp_lte_seq_num_12,
2468 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2469 "PDCP Seq num", HFILL
2472 { &hf_pdcp_lte_signalling_data,
2473 { "Signalling Data",
2474 "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2480 "pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
2484 { &hf_pdcp_lte_data_control,
2486 "pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
2490 { &hf_pdcp_lte_user_plane_data,
2491 { "User-Plane Data",
2492 "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2496 { &hf_pdcp_lte_control_pdu_type,
2497 { "Control PDU Type",
2498 "pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
2503 { "First Missing Sequence Number",
2504 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2505 "First Missing PDCP Sequence Number", HFILL
2508 { &hf_pdcp_lte_bitmap,
2510 "pdcp-lte.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
2511 "Status report bitmap (0=error, 1=OK)", HFILL
2514 { &hf_pdcp_lte_bitmap_not_received,
2516 "pdcp-lte.bitmap.error", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2517 "Status report PDU error", HFILL
2522 { &hf_pdcp_lte_sequence_analysis,
2523 { "Sequence Analysis",
2524 "pdcp-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
2528 { &hf_pdcp_lte_sequence_analysis_ok,
2530 "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2534 { &hf_pdcp_lte_sequence_analysis_previous_frame,
2535 { "Previous frame for channel",
2536 "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
2540 { &hf_pdcp_lte_sequence_analysis_expected_sn,
2542 "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
2546 { &hf_pdcp_lte_sequence_analysis_skipped,
2548 "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2552 { &hf_pdcp_lte_sequence_analysis_repeated,
2554 "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2559 { &hf_pdcp_lte_rohc,
2561 "pdcp-lte.rohc", FT_NONE, BASE_NONE, NULL, 0,
2566 { &hf_pdcp_lte_rohc_padding,
2568 "pdcp-lte.rohc.padding", FT_NONE, BASE_NONE, NULL, 0,
2569 "ROHC Padding", HFILL
2572 { &hf_pdcp_lte_rohc_r_0_crc,
2574 "pdcp-lte.r-0-crc", FT_NONE, BASE_NONE, NULL, 0,
2578 { &hf_pdcp_lte_rohc_feedback,
2580 "pdcp-lte.rohc.feedback", FT_NONE, BASE_NONE, NULL, 0,
2581 "Feedback Packet", HFILL
2584 { &hf_pdcp_lte_rohc_type0_t,
2586 "pdcp-lte.rohc.t0.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x20,
2587 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2590 { &hf_pdcp_lte_rohc_type1_t,
2592 "pdcp-lte.rohc.t1.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2593 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2596 { &hf_pdcp_lte_rohc_type2_t,
2598 "pdcp-lte.rohc.t2.t", FT_UINT8, BASE_HEX, VALS(t_vals), 0x80,
2599 "Indicates whether frame type is TS (1) or ID (0)", HFILL
2602 { &hf_pdcp_lte_rohc_d,
2604 "pdcp-lte.rohc.d", FT_UINT8, BASE_HEX, NULL, 0x01,
2605 "Indicates whether Dynamic chain is present", HFILL
2608 { &hf_pdcp_lte_rohc_ir_crc,
2610 "pdcp-lte.rohc.ir.crc", FT_UINT8, BASE_HEX, NULL, 0x0,
2615 { &hf_pdcp_lte_rohc_static_ipv4,
2616 { "Static IPv4 chain",
2617 "pdcp-lte.rohc.static.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2621 { &hf_pdcp_lte_rohc_ip_version,
2623 "pdcp-lte.rohc.ip-version", FT_UINT8, BASE_HEX, NULL, 0xf0,
2627 /* TODO: create/use value_string */
2628 { &hf_pdcp_lte_rohc_ip_protocol,
2630 "pdcp-lte.rohc.ip-protocol", FT_UINT8, BASE_DEC, VALS(ip_protocol_vals), 0x0,
2634 { &hf_pdcp_lte_rohc_ip_src,
2635 { "IP Source address",
2636 "pdcp-lte.rohc.ip-src", FT_IPv4, BASE_NONE, NULL, 0x0,
2640 { &hf_pdcp_lte_rohc_ip_dst,
2641 { "IP Destination address",
2642 "pdcp-lte.rohc.ip-dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2647 { &hf_pdcp_lte_rohc_static_udp,
2648 { "Static UDP chain",
2649 "pdcp-lte.rohc.static.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2653 { &hf_pdcp_lte_rohc_static_udp_src_port,
2654 { "Static UDP source port",
2655 "pdcp-lte.rohc.static.udp.src-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2659 { &hf_pdcp_lte_rohc_static_udp_dst_port,
2660 { "Static UDP destination port",
2661 "pdcp-lte.rohc.static.udp.dst-port", FT_UINT16, BASE_DEC, NULL, 0x0,
2665 { &hf_pdcp_lte_rohc_static_rtp,
2666 { "Static RTP chain",
2667 "pdcp-lte.rohc.static.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2671 { &hf_pdcp_lte_rohc_static_rtp_ssrc,
2673 "pdcp-lte.rohc.static.rtp.ssrc", FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2674 "Static RTP chain SSRC", HFILL
2678 { &hf_pdcp_lte_rohc_dynamic_ipv4,
2679 { "Dynamic IPv4 chain",
2680 "pdcp-lte.rohc.dynamic.ipv4", FT_NONE, BASE_NONE, NULL, 0x0,
2684 { &hf_pdcp_lte_rohc_dynamic_ipv4_tos,
2686 "pdcp-lte.rohc.ip.tos", FT_UINT8, BASE_HEX, NULL, 0x0,
2687 "IP Type of Service", HFILL
2690 { &hf_pdcp_lte_rohc_dynamic_ipv4_ttl,
2692 "pdcp-lte.rohc.ip.ttl", FT_UINT8, BASE_HEX, NULL, 0x0,
2693 "IP Time To Live", HFILL
2696 { &hf_pdcp_lte_rohc_dynamic_ipv4_id,
2698 "pdcp-lte.rohc.ip.id", FT_UINT8, BASE_HEX, NULL, 0x0,
2702 { &hf_pdcp_lte_rohc_dynamic_ipv4_df,
2704 "pdcp-lte.rohc.ip.df", FT_UINT8, BASE_HEX, NULL, 0x80,
2705 "IP Don't Fragment flag", HFILL
2708 { &hf_pdcp_lte_rohc_dynamic_ipv4_rnd,
2709 { "Random IP-ID field",
2710 "pdcp-lte.rohc.ip.rnd", FT_UINT8, BASE_HEX, NULL, 0x40,
2714 { &hf_pdcp_lte_rohc_dynamic_ipv4_nbo,
2715 { "Network Byte Order IP-ID field",
2716 "pdcp-lte.rohc.ip.nbo", FT_UINT8, BASE_HEX, NULL, 0x20,
2720 { &hf_pdcp_lte_rohc_dynamic_udp,
2721 { "Dynamic UDP chain",
2722 "pdcp-lte.rohc.dynamic.udp", FT_NONE, BASE_NONE, NULL, 0x0,
2726 { &hf_pdcp_lte_rohc_dynamic_udp_checksum,
2728 "pdcp-lte.rohc.dynamic.udp.checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2732 { &hf_pdcp_lte_rohc_dynamic_udp_seqnum,
2733 { "UDP Sequence Number",
2734 "pdcp-lte.rohc.dynamic.udp.seqnum", FT_UINT16, BASE_HEX, NULL, 0x0,
2739 { &hf_pdcp_lte_rohc_dynamic_rtp,
2740 { "Dynamic RTP chain",
2741 "pdcp-lte.rohc.dynamic.rtp", FT_NONE, BASE_NONE, NULL, 0x0,
2745 { &hf_pdcp_lte_rohc_dynamic_rtp_rx,
2747 "pdcp-lte.rohc.dynamic.rtp.rx", FT_UINT8, BASE_DEC, NULL, 0x10,
2751 { &hf_pdcp_lte_rohc_dynamic_rtp_cc,
2752 { "Contributing CSRCs",
2753 "pdcp-lte.rohc.dynamic.rtp.cc", FT_UINT8, BASE_DEC, NULL, 0x0f,
2754 "Dynamic RTP chain CCs", HFILL
2757 { &hf_pdcp_lte_rohc_dynamic_rtp_seqnum,
2758 { "RTP Sequence Number",
2759 "pdcp-lte.rohc.dynamic.rtp.seqnum", FT_UINT16, BASE_DEC, NULL, 0x0,
2760 "Dynamic RTP chain Sequence Number", HFILL
2763 { &hf_pdcp_lte_rohc_dynamic_rtp_timestamp,
2765 "pdcp-lte.rohc.dynamic.rtp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
2766 "Dynamic RTP chain Timestamp", HFILL
2769 { &hf_pdcp_lte_rohc_dynamic_rtp_reserved3,
2771 "pdcp-lte.rohc.dynamic.rtp.reserved3", FT_UINT8, BASE_HEX, NULL, 0xc0,
2772 "Reserved bits", HFILL
2775 { &hf_pdcp_lte_rohc_dynamic_rtp_x,
2777 "pdcp-lte.rohc.dynamic.rtp.x", FT_UINT8, BASE_DEC, NULL, 0x10,
2781 { &hf_pdcp_lte_rohc_dynamic_rtp_mode,
2783 "pdcp-lte.rohc.dynamic.rtp.mode", FT_UINT8, BASE_HEX, VALS(rohc_mode_vals), 0x0c,
2787 { &hf_pdcp_lte_rohc_dynamic_rtp_tis,
2789 "pdcp-lte.rohc.dynamic.rtp.tis", FT_UINT8, BASE_HEX, NULL, 0x02,
2790 "Dynamic RTP chain TIS (indicates time_stride present)", HFILL
2793 { &hf_pdcp_lte_rohc_dynamic_rtp_tss,
2795 "pdcp-lte.rohc.dynamic.rtp.tss", FT_UINT8, BASE_HEX, NULL, 0x01,
2796 "Dynamic RTP chain TSS (indicates TS_stride present)", HFILL
2799 { &hf_pdcp_lte_rohc_dynamic_rtp_ts_stride,
2801 "pdcp-lte.rohc.dynamic.rtp.ts-stride", FT_UINT32, BASE_DEC, NULL, 0x0,
2802 "Dynamic RTP chain TS Stride", HFILL
2805 { &hf_pdcp_lte_rohc_ts,
2807 "pdcp-lte.rohc.ts", FT_UINT8, BASE_DEC, NULL, 0x0,
2811 { &hf_pdcp_lte_rohc_m,
2813 "pdcp-lte.rohc.m", FT_UINT8, BASE_DEC, NULL, 0x40,
2817 { &hf_pdcp_lte_rohc_uor2_sn,
2819 "pdcp-lte.rohc.uor2.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2823 { &hf_pdcp_lte_rohc_uor2_x,
2825 "pdcp-lte.rohc.uor2.x", FT_UINT8, BASE_DEC, NULL, 0x80,
2830 { &hf_pdcp_lte_rohc_add_cid,
2832 "pdcp-lte.rohc.add-cid", FT_UINT8, BASE_DEC, NULL, 0x0f,
2836 { &hf_pdcp_lte_rohc_large_cid,
2838 "pdcp-lte.rohc.large-cid", FT_UINT16, BASE_DEC, NULL, 0x07ff,
2842 { &hf_pdcp_lte_rohc_uo0_sn,
2844 "pdcp-lte.rohc.uo0.sn", FT_UINT8, BASE_DEC, NULL, 0x78,
2848 { &hf_pdcp_lte_rohc_uo0_crc,
2850 "pdcp-lte.rohc.uo0.crc", FT_UINT8, BASE_DEC, NULL, 0x07,
2854 { &hf_pdcp_lte_rohc_r0_sn,
2856 "pdcp-lte.rohc.r0.sn", FT_UINT8, BASE_DEC, NULL, 0x3f,
2860 { &hf_pdcp_lte_rohc_r0_crc_sn,
2862 "pdcp-lte.rohc.r0-crc.sn", FT_UINT16, BASE_DEC, NULL, 0x0,
2866 { &hf_pdcp_lte_rohc_r0_crc_crc,
2868 "pdcp-lte.rohc.r0-crc.crc", FT_UINT8, BASE_DEC, NULL, 0x7f,
2872 { &hf_pdcp_lte_rohc_feedback_code,
2874 "pdcp-lte.rohc.feedback-code", FT_UINT8, BASE_DEC, NULL, 0x07,
2875 "Feedback options length (if > 0)", HFILL
2878 { &hf_pdcp_lte_rohc_feedback_size,
2880 "pdcp-lte.rohc.feedback-size", FT_UINT8, BASE_DEC, NULL, 0x0,
2881 "Feedback options length", HFILL
2884 { &hf_pdcp_lte_rohc_feedback_feedback1,
2885 { "FEEDBACK-1 (SN)",
2886 "pdcp-lte.rohc.feedback.feedback1", FT_UINT8, BASE_DEC, NULL, 0x0,
2890 { &hf_pdcp_lte_rohc_feedback_feedback2,
2892 "pdcp-lte.rohc.feedback.feedback2", FT_NONE, BASE_NONE, NULL, 0x0,
2897 { &hf_pdcp_lte_rohc_feedback_ack_type,
2899 "pdcp-lte.rohc.feedback-acktype", FT_UINT8, BASE_DEC, VALS(feedback_ack_vals), 0xc0,
2900 "Feedback-2 ack type", HFILL
2903 { &hf_pdcp_lte_rohc_feedback_mode,
2905 "pdcp-lte.rohc.feedback-mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x30,
2906 "Feedback mode", HFILL
2909 { &hf_pdcp_lte_rohc_feedback_sn,
2911 "pdcp-lte.rohc.feedback-sn", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2912 "Feedback sequence number", HFILL
2916 { &hf_pdcp_lte_rohc_feedback_option,
2918 "pdcp-lte.rohc.feedback-option", FT_UINT8, BASE_DEC, VALS(feedback_option_vals), 0xf0,
2919 "Feedback option", HFILL
2922 { &hf_pdcp_lte_rohc_feedback_length,
2924 "pdcp-lte.rohc.feedback-length", FT_UINT8, BASE_DEC, NULL, 0x0f,
2925 "Feedback length", HFILL
2928 { &hf_pdcp_lte_rohc_feedback_crc,
2930 "pdcp-lte.rohc.feedback-crc", FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
2931 "Feedback CRC", HFILL
2934 { &hf_pdcp_lte_rohc_feedback_option_sn,
2936 "pdcp-lte.rohc.feedback-option-sn", FT_UINT8, BASE_DEC, NULL, 0x0,
2937 "Feedback Option SN", HFILL
2940 { &hf_pdcp_lte_rohc_feedback_option_clock,
2942 "pdcp-lte.rohc.feedback-option-clock", FT_UINT8, BASE_DEC, NULL, 0x0,
2943 "Feedback Option Clock", HFILL
2947 { &hf_pdcp_lte_rohc_ip_id,
2949 "pdcp-lte.rohc.ip-id", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2953 { &hf_pdcp_lte_rohc_udp_checksum,
2955 "pdcp-lte.rohc.udp-checksum", FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
2959 { &hf_pdcp_lte_rohc_payload,
2961 "pdcp-lte.rohc.payload", FT_BYTES, BASE_NONE, NULL, 0x0,
2968 static gint *ett[] =
2971 &ett_pdcp_configuration,
2973 &ett_pdcp_lte_sequence_analysis,
2975 &ett_pdcp_rohc_static_ipv4,
2976 &ett_pdcp_rohc_static_udp,
2977 &ett_pdcp_rohc_static_rtp,
2978 &ett_pdcp_rohc_dynamic_ipv4,
2979 &ett_pdcp_rohc_dynamic_udp,
2980 &ett_pdcp_rohc_dynamic_rtp,
2981 &ett_pdcp_rohc_report_bitmap
2984 module_t *pdcp_lte_module;
2986 /* Register protocol. */
2987 proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
2988 proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
2989 proto_register_subtree_array(ett, array_length(ett));
2991 /* Allow other dissectors to find this one by name. */
2992 register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
2994 pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, NULL);
2996 /* Dissect uncompressed user-plane data as IP */
2997 prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
2998 "Show uncompressed User-Plane data as IP",
2999 "Show uncompressed User-Plane data as IP",
3000 &global_pdcp_dissect_user_plane_as_ip);
3002 /* Dissect unciphered signalling data as RRC */
3003 prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
3004 "Show unciphered Signalling-Plane data as RRC",
3005 "Show unciphered Signalling-Plane data as RRC",
3006 &global_pdcp_dissect_signalling_plane_as_rrc);
3008 /* Check for missing sequence numbers */
3009 prefs_register_bool_preference(pdcp_lte_module, "check_sequence_numbers",
3010 "Do sequence number analysis",
3011 "Do sequence number analysis",
3012 &global_pdcp_check_sequence_numbers);
3014 /* Attempt to dissect ROHC headers */
3015 prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
3016 "Attempt to decode ROHC data",
3017 "Attempt to decode ROHC data",
3018 &global_pdcp_dissect_rohc);
3020 prefs_register_bool_preference(pdcp_lte_module, "show_feedback_option_tag_length",
3021 "Show ROHC feedback option tag & length",
3022 "Show ROHC feedback option tag & length",
3023 &global_pdcp_show_feedback_option_tag_length);
3025 prefs_register_bool_preference(pdcp_lte_module, "heuristic_pdcp_lte_over_udp",
3026 "Try Heuristic LTE-PDCP over UDP framing",
3027 "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
3029 &global_pdcp_lte_heur);
3031 register_init_routine(&pdcp_lte_init_protocol);
3034 void proto_reg_handoff_pdcp_lte(void)
3036 dissector_handle_t pdcp_lte_handle;
3038 pdcp_lte_handle = find_dissector("pdcp-lte");
3039 /* Add as a heuristic UDP dissector */
3040 heur_dissector_add("udp", dissect_pdcp_lte_heur, proto_pdcp_lte);
3042 ip_handle = find_dissector("ip");