1 /* Routines for LTE PDCP
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/expert.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/wmem/wmem.h>
37 #include "packet-rlc-lte.h"
38 #include "packet-pdcp-lte.h"
41 * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
42 * Packet Data Convergence Protocol (PDCP) specification v11.0.0
47 - Support for deciphering
48 - Verify MAC authentication bytes
49 - Add Relay Node user plane data PDU dissection
53 /* Initialize the protocol and registered fields. */
54 int proto_pdcp_lte
= -1;
56 extern int proto_rlc_lte
;
58 /* Configuration (info known outside of PDU) */
59 static int hf_pdcp_lte_configuration
= -1;
60 static int hf_pdcp_lte_direction
= -1;
61 static int hf_pdcp_lte_ueid
= -1;
62 static int hf_pdcp_lte_channel_type
= -1;
63 static int hf_pdcp_lte_channel_id
= -1;
65 static int hf_pdcp_lte_rohc_compression
= -1;
66 static int hf_pdcp_lte_rohc_mode
= -1;
67 static int hf_pdcp_lte_rohc_rnd
= -1;
68 static int hf_pdcp_lte_rohc_udp_checksum_present
= -1;
69 static int hf_pdcp_lte_rohc_profile
= -1;
71 static int hf_pdcp_lte_no_header_pdu
= -1;
72 static int hf_pdcp_lte_plane
= -1;
73 static int hf_pdcp_lte_seqnum_length
= -1;
74 static int hf_pdcp_lte_cid_inclusion_info
= -1;
75 static int hf_pdcp_lte_large_cid_present
= -1;
77 /* PDCP header fields */
78 static int hf_pdcp_lte_control_plane_reserved
= -1;
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_seq_num_15
= -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_reserved4
= -1;
91 static int hf_pdcp_lte_fms2
= -1;
92 static int hf_pdcp_lte_bitmap
= -1;
95 /* Sequence Analysis */
96 static int hf_pdcp_lte_sequence_analysis
= -1;
97 static int hf_pdcp_lte_sequence_analysis_ok
= -1;
98 static int hf_pdcp_lte_sequence_analysis_previous_frame
= -1;
99 static int hf_pdcp_lte_sequence_analysis_next_frame
= -1;
100 static int hf_pdcp_lte_sequence_analysis_expected_sn
= -1;
102 static int hf_pdcp_lte_sequence_analysis_repeated
= -1;
103 static int hf_pdcp_lte_sequence_analysis_skipped
= -1;
105 /* Security Settings */
106 static int hf_pdcp_lte_security
= -1;
107 static int hf_pdcp_lte_security_setup_frame
= -1;
108 static int hf_pdcp_lte_security_integrity_algorithm
= -1;
109 static int hf_pdcp_lte_security_ciphering_algorithm
= -1;
112 /* Protocol subtree. */
113 static int ett_pdcp
= -1;
114 static int ett_pdcp_configuration
= -1;
115 static int ett_pdcp_packet
= -1;
116 static int ett_pdcp_lte_sequence_analysis
= -1;
117 static int ett_pdcp_report_bitmap
= -1;
118 static int ett_pdcp_security
= -1;
120 static expert_field ei_pdcp_lte_sequence_analysis_wrong_sequence_number
= EI_INIT
;
121 static expert_field ei_pdcp_lte_reserved_bits_not_zero
= EI_INIT
;
122 static expert_field ei_pdcp_lte_sequence_analysis_sn_repeated
= EI_INIT
;
123 static expert_field ei_pdcp_lte_sequence_analysis_sn_missing
= EI_INIT
;
125 static const value_string direction_vals
[] =
127 { DIRECTION_UPLINK
, "Uplink"},
128 { DIRECTION_DOWNLINK
, "Downlink"},
133 static const value_string pdcp_plane_vals
[] = {
134 { SIGNALING_PLANE
, "Signalling" },
135 { USER_PLANE
, "User" },
139 static const value_string logical_channel_vals
[] = {
140 { Channel_DCCH
, "DCCH"},
141 { Channel_BCCH
, "BCCH"},
142 { Channel_CCCH
, "CCCH"},
143 { Channel_PCCH
, "PCCH"},
147 static const value_string rohc_mode_vals
[] = {
148 { UNIDIRECTIONAL
, "Unidirectional" },
149 { OPTIMISTIC_BIDIRECTIONAL
, "Optimistic Bidirectional" },
150 { RELIABLE_BIDIRECTIONAL
, "Reliable Bidirectional" },
155 /* Values taken from:
156 http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
157 static const value_string rohc_profile_vals
[] = {
158 { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
159 { 0x0001, "ROHC RTP" }, /* [RFC3095] */
160 { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
161 { 0x0002, "ROHC UDP" }, /* [RFC3095] */
162 { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
163 { 0x0003, "ROHC ESP" }, /* [RFC3095] */
164 { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
165 { 0x0004, "ROHC IP" }, /* [RFC3843] */
166 { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
167 { 0x0005, "ROHC LLA" }, /* [RFC4362] */
168 { 0x0105, "ROHC LLA with R-mode" }, /* [RFC3408] */
169 { 0x0006, "ROHC TCP" }, /* [RFC4996] */
170 { 0x0007, "ROHC RTP/UDP-Lite" }, /* [RFC4019] */
171 { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /* [RFC5225] */
172 { 0x0008, "ROHC UDP-Lite" }, /* [RFC4019] */
173 { 0x0108, "ROHCv2 UDP-Lite" }, /* [RFC5225] */
177 static const value_string pdu_type_vals
[] = {
178 { 0, "Control PDU" },
183 static const value_string control_pdu_type_vals
[] = {
184 { 0, "PDCP Status report" },
185 { 1, "Header Compression Feedback Information" },
189 static const value_string integrity_algorithm_vals
[] = {
196 static const value_string ciphering_algorithm_vals
[] = {
204 static dissector_handle_t ip_handle
;
205 static dissector_handle_t ipv6_handle
;
206 static dissector_handle_t rohc_handle
;
207 static dissector_handle_t data_handle
;
210 #define SEQUENCE_ANALYSIS_RLC_ONLY 1
211 #define SEQUENCE_ANALYSIS_PDCP_ONLY 2
213 /* Preference variables */
214 static gboolean global_pdcp_dissect_user_plane_as_ip
= TRUE
;
215 static gboolean global_pdcp_dissect_signalling_plane_as_rrc
= TRUE
;
216 static gint global_pdcp_check_sequence_numbers
= TRUE
;
217 static gboolean global_pdcp_dissect_rohc
= FALSE
;
219 /* Which layer info to show in the info column */
221 ShowRLCLayer
, ShowPDCPLayer
, ShowTrafficLayer
223 static gint global_pdcp_lte_layer_to_show
= (gint
)ShowRLCLayer
;
227 /**************************************************/
228 /* Sequence number analysis */
233 /* Using bit fields to fit into 32 bits, so avoiding the need to allocate
234 heap memory for these structs */
240 } pdcp_channel_hash_key
;
245 guint16 previousSequenceNumber
;
246 guint32 previousFrameNum
;
247 } pdcp_channel_status
;
249 /* The sequence analysis channel hash table.
250 Maps key -> status */
251 static GHashTable
*pdcp_sequence_analysis_channel_hash
= NULL
;
254 static gint
pdcp_channel_equal(gconstpointer v
, gconstpointer v2
)
256 /* Key fits in 4 bytes, so just compare pointers! */
260 /* Compute a hash value for a given key. */
261 static guint
pdcp_channel_hash_func(gconstpointer v
)
263 /* Just use pointer, as the fields are all in this value */
264 return GPOINTER_TO_UINT(v
);
268 /* Hash table types & functions for frame reports */
274 guint32 channelId
: 5;
275 guint32 direction
: 1;
277 } pdcp_result_hash_key
;
279 static gint
pdcp_result_hash_equal(gconstpointer v
, gconstpointer v2
)
281 const pdcp_result_hash_key
* val1
= (const pdcp_result_hash_key
*)v
;
282 const pdcp_result_hash_key
* val2
= (const pdcp_result_hash_key
*)v2
;
284 /* All fields must match */
285 return (memcmp(val1
, val2
, sizeof(pdcp_result_hash_key
)) == 0);
288 /* Compute a hash value for a given key. */
289 static guint
pdcp_result_hash_func(gconstpointer v
)
291 const pdcp_result_hash_key
* val1
= (const pdcp_result_hash_key
*)v
;
293 /* TODO: check collision-rate / execution-time of these multipliers? */
294 return val1
->frameNumber
+ (val1
->channelId
<<13) +
297 (val1
->direction
<<9);
300 /* pdcp_channel_hash_key fits into the pointer, so just copy the value into
301 a guint, cast to apointer and return that as the key */
302 static gpointer
get_channel_hash_key(pdcp_channel_hash_key
*key
)
305 /* TODO: assert that sizeof(pdcp_channel_hash_key) <= sizeof(guint) ? */
306 memcpy(&asInt
, key
, sizeof(pdcp_channel_hash_key
));
307 return GUINT_TO_POINTER(asInt
);
310 /* Convenience function to get a pointer for the hash_func to work with */
311 static gpointer
get_report_hash_key(guint16 SN
, guint32 frameNumber
,
312 pdcp_lte_info
*p_pdcp_lte_info
,
315 static pdcp_result_hash_key key
;
316 pdcp_result_hash_key
*p_key
;
318 /* Only allocate a struct when will be adding entry */
320 p_key
= wmem_new(wmem_file_scope(), pdcp_result_hash_key
);
323 memset(&key
, 0, sizeof(pdcp_result_hash_key
));
327 /* Fill in details, and return pointer */
328 p_key
->frameNumber
= frameNumber
;
330 p_key
->plane
= (guint8
)p_pdcp_lte_info
->plane
;
331 p_key
->channelId
= p_pdcp_lte_info
->channelId
;
332 p_key
->direction
= p_pdcp_lte_info
->direction
;
339 /* Info to attach to frame when first read, recording what to show about sequence */
342 SN_OK
, SN_Repeated
, SN_MAC_Retx
, SN_Retx
, SN_Missing
346 gboolean sequenceExpectedCorrect
;
347 guint16 sequenceExpected
;
348 guint32 previousFrameNum
;
349 guint32 nextFrameNum
;
354 sequence_state state
;
355 } pdcp_sequence_report_in_frame
;
357 /* The sequence analysis frame report hash table instance itself */
358 static GHashTable
*pdcp_lte_sequence_analysis_report_hash
= NULL
;
362 /* Add to the tree values associated with sequence analysis for this frame */
363 static void addChannelSequenceInfo(pdcp_sequence_report_in_frame
*p
,
364 pdcp_lte_info
*p_pdcp_lte_info
,
365 guint16 sequenceNumber
,
366 packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
)
368 proto_tree
*seqnum_tree
;
369 proto_item
*seqnum_ti
;
370 proto_item
*ti_expected_sn
;
374 seqnum_ti
= proto_tree_add_string_format(tree
,
375 hf_pdcp_lte_sequence_analysis
,
377 "", "Sequence Analysis");
378 seqnum_tree
= proto_item_add_subtree(seqnum_ti
,
379 ett_pdcp_lte_sequence_analysis
);
380 PROTO_ITEM_SET_GENERATED(seqnum_ti
);
383 /* Previous channel frame */
384 if (p
->previousFrameNum
!= 0) {
385 proto_tree_add_uint(seqnum_tree
, hf_pdcp_lte_sequence_analysis_previous_frame
,
386 tvb
, 0, 0, p
->previousFrameNum
);
389 /* Expected sequence number */
390 ti_expected_sn
= proto_tree_add_uint(seqnum_tree
, hf_pdcp_lte_sequence_analysis_expected_sn
,
391 tvb
, 0, 0, p
->sequenceExpected
);
392 PROTO_ITEM_SET_GENERATED(ti_expected_sn
);
394 /* Make sure we have recognised SN length */
395 switch (p_pdcp_lte_info
->seqnum_length
) {
396 case PDCP_SN_LENGTH_5_BITS
:
397 case PDCP_SN_LENGTH_7_BITS
:
398 case PDCP_SN_LENGTH_12_BITS
:
399 case PDCP_SN_LENGTH_15_BITS
:
402 DISSECTOR_ASSERT_NOT_REACHED();
408 PROTO_ITEM_SET_HIDDEN(ti_expected_sn
);
409 ti
= proto_tree_add_boolean(seqnum_tree
, hf_pdcp_lte_sequence_analysis_ok
,
411 PROTO_ITEM_SET_GENERATED(ti
);
412 proto_item_append_text(seqnum_ti
, " - OK");
414 /* Link to next SN in channel (if known) */
415 if (p
->nextFrameNum
!= 0) {
416 proto_tree_add_uint(seqnum_tree
, hf_pdcp_lte_sequence_analysis_next_frame
,
417 tvb
, 0, 0, p
->nextFrameNum
);
422 ti
= proto_tree_add_boolean(seqnum_tree
, hf_pdcp_lte_sequence_analysis_ok
,
424 PROTO_ITEM_SET_GENERATED(ti
);
425 ti
= proto_tree_add_boolean(seqnum_tree
, hf_pdcp_lte_sequence_analysis_skipped
,
427 PROTO_ITEM_SET_GENERATED(ti
);
428 if (p
->lastSN
!= p
->firstSN
) {
429 expert_add_info_format(pinfo
, ti
, &ei_pdcp_lte_sequence_analysis_sn_missing
,
430 "PDCP SNs (%u to %u) missing for %s on UE %u (%s-%u)",
431 p
->firstSN
, p
->lastSN
,
432 val_to_str_const(p_pdcp_lte_info
->direction
, direction_vals
, "Unknown"),
433 p_pdcp_lte_info
->ueid
,
434 val_to_str_const(p_pdcp_lte_info
->channelType
, logical_channel_vals
, "Unknown"),
435 p_pdcp_lte_info
->channelId
);
436 proto_item_append_text(seqnum_ti
, " - SNs missing (%u to %u)",
437 p
->firstSN
, p
->lastSN
);
440 expert_add_info_format(pinfo
, ti
, &ei_pdcp_lte_sequence_analysis_sn_missing
,
441 "PDCP SN (%u) missing for %s on UE %u (%s-%u)",
443 val_to_str_const(p_pdcp_lte_info
->direction
, direction_vals
, "Unknown"),
444 p_pdcp_lte_info
->ueid
,
445 val_to_str_const(p_pdcp_lte_info
->channelType
, logical_channel_vals
, "Unknown"),
446 p_pdcp_lte_info
->channelId
);
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
, &ei_pdcp_lte_sequence_analysis_sn_repeated
,
460 "PDCP SN (%u) repeated for %s for UE %u (%s-%u)",
462 val_to_str_const(p_pdcp_lte_info
->direction
, direction_vals
, "Unknown"),
463 p_pdcp_lte_info
->ueid
,
464 val_to_str_const(p_pdcp_lte_info
->channelType
, logical_channel_vals
, "Unknown"),
465 p_pdcp_lte_info
->channelId
);
466 proto_item_append_text(seqnum_ti
, "- SN %u Repeated",
471 /* Incorrect sequence number */
472 expert_add_info_format(pinfo
, ti_expected_sn
, &ei_pdcp_lte_sequence_analysis_wrong_sequence_number
,
473 "Wrong Sequence Number for %s on UE %u (%s-%u) - got %u, expected %u",
474 val_to_str_const(p_pdcp_lte_info
->direction
, direction_vals
, "Unknown"),
475 p_pdcp_lte_info
->ueid
,
476 val_to_str_const(p_pdcp_lte_info
->channelType
, logical_channel_vals
, "Unknown"),
477 p_pdcp_lte_info
->channelId
,
478 sequenceNumber
, p
->sequenceExpected
);
484 /* Update the channel status and set report for this frame */
485 static void checkChannelSequenceInfo(packet_info
*pinfo
, tvbuff_t
*tvb
,
486 pdcp_lte_info
*p_pdcp_lte_info
,
487 guint16 sequenceNumber
,
490 pdcp_channel_hash_key channel_key
;
491 pdcp_channel_status
*p_channel_status
;
492 pdcp_sequence_report_in_frame
*p_report_in_frame
= NULL
;
493 gboolean createdChannel
= FALSE
;
494 guint16 expectedSequenceNumber
= 0;
497 /* If find stat_report_in_frame already, use that and get out */
498 if (pinfo
->fd
->flags
.visited
) {
500 (pdcp_sequence_report_in_frame
*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash
,
501 get_report_hash_key(sequenceNumber
,
503 p_pdcp_lte_info
, FALSE
));
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 channel_key
.ueId
= p_pdcp_lte_info
->ueid
;
520 channel_key
.plane
= p_pdcp_lte_info
->plane
;
521 channel_key
.channelId
= p_pdcp_lte_info
->channelId
;
522 channel_key
.direction
= p_pdcp_lte_info
->direction
;
523 channel_key
.notUsed
= 0;
525 /* Do the table lookup */
526 p_channel_status
= (pdcp_channel_status
*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash
,
527 get_channel_hash_key(&channel_key
));
529 /* Create table entry if necessary */
530 if (p_channel_status
== NULL
) {
531 createdChannel
= TRUE
;
533 /* Allocate a new value and duplicate key contents */
534 p_channel_status
= wmem_new0(wmem_file_scope(), pdcp_channel_status
);
537 g_hash_table_insert(pdcp_sequence_analysis_channel_hash
,
538 get_channel_hash_key(&channel_key
), p_channel_status
);
541 /* Create space for frame state_report */
542 p_report_in_frame
= wmem_new(wmem_file_scope(), pdcp_sequence_report_in_frame
);
543 p_report_in_frame
->nextFrameNum
= 0;
545 switch (p_pdcp_lte_info
->seqnum_length
) {
546 case PDCP_SN_LENGTH_5_BITS
:
549 case PDCP_SN_LENGTH_7_BITS
:
552 case PDCP_SN_LENGTH_12_BITS
:
555 case PDCP_SN_LENGTH_15_BITS
:
559 DISSECTOR_ASSERT_NOT_REACHED();
563 /* Work out expected sequence number */
564 if (!createdChannel
) {
565 expectedSequenceNumber
= (p_channel_status
->previousSequenceNumber
+ 1) % snLimit
;
568 expectedSequenceNumber
= sequenceNumber
;
571 /* Set report for this frame */
572 /* For PDCP, sequence number is always expectedSequence number */
573 p_report_in_frame
->sequenceExpectedCorrect
= (sequenceNumber
== expectedSequenceNumber
);
575 /* For wrong sequence number... */
576 if (!p_report_in_frame
->sequenceExpectedCorrect
) {
578 /* Frames are not missing if we get an earlier sequence number again */
579 if (((snLimit
+ expectedSequenceNumber
- sequenceNumber
) % snLimit
) > 15) {
580 p_report_in_frame
->state
= SN_Missing
;
581 p_report_in_frame
->firstSN
= expectedSequenceNumber
;
582 p_report_in_frame
->lastSN
= (snLimit
+ sequenceNumber
- 1) % snLimit
;
584 p_report_in_frame
->sequenceExpected
= expectedSequenceNumber
;
585 p_report_in_frame
->previousFrameNum
= p_channel_status
->previousFrameNum
;
587 /* Update channel status to remember *this* frame */
588 p_channel_status
->previousFrameNum
= pinfo
->fd
->num
;
589 p_channel_status
->previousSequenceNumber
= sequenceNumber
;
592 /* An SN has been repeated */
593 p_report_in_frame
->state
= SN_Repeated
;
594 p_report_in_frame
->firstSN
= sequenceNumber
;
596 p_report_in_frame
->sequenceExpected
= expectedSequenceNumber
;
597 p_report_in_frame
->previousFrameNum
= p_channel_status
->previousFrameNum
;
602 p_report_in_frame
->state
= SN_OK
;
603 p_report_in_frame
->sequenceExpected
= expectedSequenceNumber
;
604 p_report_in_frame
->previousFrameNum
= p_channel_status
->previousFrameNum
;
606 /* Update channel status to remember *this* frame */
607 p_channel_status
->previousFrameNum
= pinfo
->fd
->num
;
608 p_channel_status
->previousSequenceNumber
= sequenceNumber
;
610 if (p_report_in_frame
->previousFrameNum
!= 0) {
611 /* Get report for previous frame */
612 pdcp_sequence_report_in_frame
*p_previous_report
;
613 p_previous_report
= (pdcp_sequence_report_in_frame
*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash
,
614 get_report_hash_key((sequenceNumber
+32767) % 32768,
615 p_report_in_frame
->previousFrameNum
,
618 /* It really shouldn't be NULL... */
619 if (p_previous_report
!= NULL
) {
620 /* Point it forward to this one */
621 p_previous_report
->nextFrameNum
= pinfo
->fd
->num
;
626 /* Associate with this frame number */
627 g_hash_table_insert(pdcp_lte_sequence_analysis_report_hash
,
628 get_report_hash_key(sequenceNumber
, pinfo
->fd
->num
,
629 p_pdcp_lte_info
, TRUE
),
632 /* Add state report for this frame into tree */
633 addChannelSequenceInfo(p_report_in_frame
, p_pdcp_lte_info
, sequenceNumber
,
639 /* Hash table for security state for a UE
640 Maps UEId -> pdcp_security_info_t* */
641 static gint
pdcp_lte_ueid_hash_equal(gconstpointer v
, gconstpointer v2
)
645 static guint
pdcp_lte_ueid_hash_func(gconstpointer v
)
647 return GPOINTER_TO_UINT(v
);
649 static GHashTable
*pdcp_security_hash
= NULL
;
651 /* Result is (ueid, framenum) -> pdcp_security_info_t* */
652 typedef struct ueid_frame_t
{
657 /* Convenience function to get a pointer for the hash_func to work with */
658 static gpointer
get_ueid_frame_hash_key(guint16 ueid
, guint32 frameNumber
,
661 static ueid_frame_t key
;
664 /* Only allocate a struct when will be adding entry */
666 p_key
= wmem_new(wmem_file_scope(), ueid_frame_t
);
669 memset(&key
, 0, sizeof(ueid_frame_t
));
673 /* Fill in details, and return pointer */
674 p_key
->framenum
= frameNumber
;
680 static gint
pdcp_lte_ueid_frame_hash_equal(gconstpointer v
, gconstpointer v2
)
682 ueid_frame_t
*ueid_frame_1
= (ueid_frame_t
*)v
;
683 ueid_frame_t
*ueid_frame_2
= (ueid_frame_t
*)v2
;
684 return ((ueid_frame_1
->framenum
== ueid_frame_2
->framenum
) && (ueid_frame_1
->ueid
== ueid_frame_2
->ueid
));
686 static guint
pdcp_lte_ueid_frame_hash_func(gconstpointer v
)
688 ueid_frame_t
*ueid_frame
= (ueid_frame_t
*)v
;
689 return ueid_frame
->framenum
+ 100*ueid_frame
->ueid
;
691 static GHashTable
*pdcp_security_result_hash
= NULL
;
696 /* Write the given formatted text to:
698 - the top-level RLC PDU item */
699 static void write_pdu_label_and_info(proto_item
*pdu_ti
,
700 packet_info
*pinfo
, const char *format
, ...)
702 #define MAX_INFO_BUFFER 256
703 static char info_buffer
[MAX_INFO_BUFFER
];
707 va_start(ap
, format
);
708 g_vsnprintf(info_buffer
, MAX_INFO_BUFFER
, format
, ap
);
711 /* Add to indicated places */
712 col_append_str(pinfo
->cinfo
, COL_INFO
, info_buffer
);
713 proto_item_append_text(pdu_ti
, "%s", info_buffer
);
718 /***************************************************************/
722 /* Show in the tree the config info attached to this frame, as generated fields */
723 static void show_pdcp_config(packet_info
*pinfo
, tvbuff_t
*tvb
, proto_tree
*tree
,
724 pdcp_lte_info
*p_pdcp_info
)
727 proto_tree
*configuration_tree
;
728 proto_item
*configuration_ti
= proto_tree_add_item(tree
,
729 hf_pdcp_lte_configuration
,
730 tvb
, 0, 0, ENC_ASCII
|ENC_NA
);
731 configuration_tree
= proto_item_add_subtree(configuration_ti
, ett_pdcp_configuration
);
734 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_direction
, tvb
, 0, 0,
735 p_pdcp_info
->direction
);
736 PROTO_ITEM_SET_GENERATED(ti
);
739 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_plane
, tvb
, 0, 0,
741 PROTO_ITEM_SET_GENERATED(ti
);
744 if (p_pdcp_info
->ueid
!= 0) {
745 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_ueid
, tvb
, 0, 0,
747 PROTO_ITEM_SET_GENERATED(ti
);
751 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_channel_type
, tvb
, 0, 0,
752 p_pdcp_info
->channelType
);
753 PROTO_ITEM_SET_GENERATED(ti
);
754 if (p_pdcp_info
->channelId
!= 0) {
756 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_channel_id
, tvb
, 0, 0,
757 p_pdcp_info
->channelId
);
758 PROTO_ITEM_SET_GENERATED(ti
);
762 /* User-plane-specific fields */
763 if (p_pdcp_info
->plane
== USER_PLANE
) {
766 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_no_header_pdu
, tvb
, 0, 0,
767 p_pdcp_info
->no_header_pdu
);
768 PROTO_ITEM_SET_GENERATED(ti
);
770 if (!p_pdcp_info
->no_header_pdu
) {
773 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_seqnum_length
, tvb
, 0, 0,
774 p_pdcp_info
->seqnum_length
);
775 PROTO_ITEM_SET_GENERATED(ti
);
779 /* ROHC compression */
780 ti
= proto_tree_add_boolean(configuration_tree
, hf_pdcp_lte_rohc_compression
, tvb
, 0, 0,
781 p_pdcp_info
->rohc
.rohc_compression
);
782 PROTO_ITEM_SET_GENERATED(ti
);
784 /* ROHC-specific settings */
785 if (p_pdcp_info
->rohc
.rohc_compression
) {
788 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_rohc_mode
, tvb
, 0, 0,
789 p_pdcp_info
->rohc
.mode
);
790 PROTO_ITEM_SET_GENERATED(ti
);
793 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_rohc_rnd
, tvb
, 0, 0,
794 p_pdcp_info
->rohc
.rnd
);
795 PROTO_ITEM_SET_GENERATED(ti
);
798 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_rohc_udp_checksum_present
, tvb
, 0, 0,
799 p_pdcp_info
->rohc
.udp_checksum_present
);
800 PROTO_ITEM_SET_GENERATED(ti
);
803 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_rohc_profile
, tvb
, 0, 0,
804 p_pdcp_info
->rohc
.profile
);
805 PROTO_ITEM_SET_GENERATED(ti
);
807 /* CID Inclusion Info */
808 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_cid_inclusion_info
, tvb
, 0, 0,
809 p_pdcp_info
->rohc
.cid_inclusion_info
);
810 PROTO_ITEM_SET_GENERATED(ti
);
813 ti
= proto_tree_add_uint(configuration_tree
, hf_pdcp_lte_large_cid_present
, tvb
, 0, 0,
814 p_pdcp_info
->rohc
.large_cid_present
);
815 PROTO_ITEM_SET_GENERATED(ti
);
818 /* Append summary to configuration root */
819 proto_item_append_text(configuration_ti
, "(direction=%s, plane=%s",
820 val_to_str_const(p_pdcp_info
->direction
, direction_vals
, "Unknown"),
821 val_to_str_const(p_pdcp_info
->plane
, pdcp_plane_vals
, "Unknown"));
823 if (p_pdcp_info
->rohc
.rohc_compression
) {
824 const char *mode
= val_to_str_const(p_pdcp_info
->rohc
.mode
, rohc_mode_vals
, "Error");
825 proto_item_append_text(configuration_ti
, ", mode=%c, profile=%s",
827 val_to_str_const(p_pdcp_info
->rohc
.profile
, rohc_profile_vals
, "Unknown"));
829 proto_item_append_text(configuration_ti
, ")");
830 PROTO_ITEM_SET_GENERATED(configuration_ti
);
832 /* Show plane in info column */
833 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s: ",
834 val_to_str_const(p_pdcp_info
->plane
, pdcp_plane_vals
, "Unknown"));
839 /* Look for an RRC dissector for signalling data (using channel type and direction) */
840 static dissector_handle_t
lookup_rrc_dissector_handle(struct pdcp_lte_info
*p_pdcp_info
)
842 dissector_handle_t rrc_handle
= 0;
844 switch (p_pdcp_info
->channelType
)
847 if (p_pdcp_info
->direction
== DIRECTION_UPLINK
) {
848 rrc_handle
= find_dissector("lte_rrc.ul_ccch");
851 rrc_handle
= find_dissector("lte_rrc.dl_ccch");
855 rrc_handle
= find_dissector("lte_rrc.pcch");
858 switch (p_pdcp_info
->BCCHTransport
) {
860 rrc_handle
= find_dissector("lte_rrc.bcch_bch");
862 case DLSCH_TRANSPORT
:
863 rrc_handle
= find_dissector("lte_rrc.bcch_dl_sch");
868 if (p_pdcp_info
->direction
== DIRECTION_UPLINK
) {
869 rrc_handle
= find_dissector("lte_rrc.ul_dcch");
872 rrc_handle
= find_dissector("lte_rrc.dl_dcch");
885 /* Forwad declarations */
886 static void dissect_pdcp_lte(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
);
888 /* Heuristic dissection */
889 static gboolean global_pdcp_lte_heur
= FALSE
;
891 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
892 static gboolean
dissect_pdcp_lte_heur(tvbuff_t
*tvb
, packet_info
*pinfo
,
893 proto_tree
*tree
, void *data _U_
)
896 struct pdcp_lte_info
*p_pdcp_lte_info
;
899 gboolean infoAlreadySet
= FALSE
;
900 gboolean seqnumLengthTagPresent
= FALSE
;
902 /* This is a heuristic dissector, which means we get all the UDP
903 * traffic not sent to a known dissector and not claimed by
904 * a heuristic dissector called before us!
907 if (!global_pdcp_lte_heur
) {
911 /* Do this again on re-dissection to re-discover offset of actual PDU */
913 /* Needs to be at least as long as:
914 - the signature string
917 - at least one byte of PDCP PDU payload */
918 if (tvb_length_remaining(tvb
, offset
) < (gint
)(strlen(PDCP_LTE_START_STRING
)+3+2)) {
922 /* OK, compare with signature string */
923 if (tvb_strneql(tvb
, offset
, PDCP_LTE_START_STRING
, strlen(PDCP_LTE_START_STRING
)) != 0) {
926 offset
+= (gint
)strlen(PDCP_LTE_START_STRING
);
929 /* If redissecting, use previous info struct (if available) */
930 p_pdcp_lte_info
= (pdcp_lte_info
*)p_get_proto_data(pinfo
->fd
, proto_pdcp_lte
, 0);
931 if (p_pdcp_lte_info
== NULL
) {
932 /* Allocate new info struct for this frame */
933 p_pdcp_lte_info
= wmem_new0(wmem_file_scope(), pdcp_lte_info
);
934 infoAlreadySet
= FALSE
;
937 infoAlreadySet
= TRUE
;
941 /* Read fixed fields */
942 p_pdcp_lte_info
->no_header_pdu
= (gboolean
)tvb_get_guint8(tvb
, offset
++);
943 p_pdcp_lte_info
->plane
= (enum pdcp_plane
)tvb_get_guint8(tvb
, offset
++);
944 p_pdcp_lte_info
->rohc
.rohc_compression
= (gboolean
)tvb_get_guint8(tvb
, offset
++);
946 /* Read optional fields */
947 while (tag
!= PDCP_LTE_PAYLOAD_TAG
) {
948 /* Process next tag */
949 tag
= tvb_get_guint8(tvb
, offset
++);
951 case PDCP_LTE_SEQNUM_LENGTH_TAG
:
952 p_pdcp_lte_info
->seqnum_length
= tvb_get_guint8(tvb
, offset
);
954 seqnumLengthTagPresent
= TRUE
;
956 case PDCP_LTE_DIRECTION_TAG
:
957 p_pdcp_lte_info
->direction
= tvb_get_guint8(tvb
, offset
);
960 case PDCP_LTE_LOG_CHAN_TYPE_TAG
:
961 p_pdcp_lte_info
->channelType
= (LogicalChannelType
)tvb_get_guint8(tvb
, offset
);
964 case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG
:
965 p_pdcp_lte_info
->BCCHTransport
= (BCCHTransportType
)tvb_get_guint8(tvb
, offset
);
968 case PDCP_LTE_ROHC_IP_VERSION_TAG
:
969 p_pdcp_lte_info
->rohc
.rohc_ip_version
= tvb_get_ntohs(tvb
, offset
);
972 case PDCP_LTE_ROHC_CID_INC_INFO_TAG
:
973 p_pdcp_lte_info
->rohc
.cid_inclusion_info
= tvb_get_guint8(tvb
, offset
);
976 case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG
:
977 p_pdcp_lte_info
->rohc
.large_cid_present
= tvb_get_guint8(tvb
, offset
);
980 case PDCP_LTE_ROHC_MODE_TAG
:
981 p_pdcp_lte_info
->rohc
.mode
= (enum rohc_mode
)tvb_get_guint8(tvb
, offset
);
984 case PDCP_LTE_ROHC_RND_TAG
:
985 p_pdcp_lte_info
->rohc
.rnd
= tvb_get_guint8(tvb
, offset
);
988 case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG
:
989 p_pdcp_lte_info
->rohc
.udp_checksum_present
= tvb_get_guint8(tvb
, offset
);
992 case PDCP_LTE_ROHC_PROFILE_TAG
:
993 p_pdcp_lte_info
->rohc
.profile
= tvb_get_ntohs(tvb
, offset
);
996 case PDCP_LTE_CHANNEL_ID_TAG
:
997 p_pdcp_lte_info
->channelId
= tvb_get_ntohs(tvb
, offset
);
1000 case PDCP_LTE_UEID_TAG
:
1001 p_pdcp_lte_info
->ueid
= tvb_get_ntohs(tvb
, offset
);
1005 case PDCP_LTE_PAYLOAD_TAG
:
1006 /* Have reached data, so get out of loop */
1010 /* It must be a recognised tag */
1015 if ((p_pdcp_lte_info
->plane
== USER_PLANE
) && (seqnumLengthTagPresent
== FALSE
)) {
1016 /* Conditional field is not present */
1020 if (!infoAlreadySet
) {
1021 /* Store info in packet */
1022 p_add_proto_data(pinfo
->fd
, proto_pdcp_lte
, 0, p_pdcp_lte_info
);
1025 /**************************************/
1026 /* OK, now dissect as PDCP LTE */
1028 /* Create tvb that starts at actual PDCP PDU */
1029 pdcp_tvb
= tvb_new_subset_remaining(tvb
, offset
);
1030 dissect_pdcp_lte(pdcp_tvb
, pinfo
, tree
);
1034 /* Called from control protocol to configure security algorithms for the given UE */
1035 void set_pdcp_lte_security_algorithms(guint16 ueid
, pdcp_security_info_t
*security_info
)
1037 /* Copy security struct */
1038 pdcp_security_info_t
*p_security
= wmem_new(wmem_file_scope(), pdcp_security_info_t
);
1039 *p_security
= *security_info
;
1041 /* And add into security table */
1042 g_hash_table_insert(pdcp_security_hash
, GUINT_TO_POINTER((guint
)ueid
), p_security
);
1046 /******************************/
1047 /* Main dissection function. */
1048 static void dissect_pdcp_lte(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1051 proto_tree
*pdcp_tree
= NULL
;
1052 proto_item
*root_ti
= NULL
;
1055 struct pdcp_lte_info
*p_pdcp_info
;
1056 rohc_info
*p_rohc_info
;
1057 tvbuff_t
*rohc_tvb
= NULL
;
1058 pdcp_security_info_t
*current_security
= NULL
; /* current security for this UE */
1059 pdcp_security_info_t
*pdu_security
; /* security in place for this PDU */
1062 /* Set protocol name. */
1063 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PDCP-LTE");
1065 /* Look for attached packet info! */
1066 p_pdcp_info
= (struct pdcp_lte_info
*)p_get_proto_data(pinfo
->fd
, proto_pdcp_lte
, 0);
1067 /* Can't dissect anything without it... */
1068 if (p_pdcp_info
== NULL
) {
1072 /* Don't want to overwrite the RLC Info column if configured not to */
1073 if ((global_pdcp_lte_layer_to_show
== ShowRLCLayer
) &&
1074 (p_get_proto_data(pinfo
->fd
, proto_rlc_lte
, 0) != NULL
)) {
1076 col_set_writable(pinfo
->cinfo
, FALSE
);
1079 /* TODO: won't help with multiple PDCP-or-traffic PDUs / frame... */
1080 col_clear(pinfo
->cinfo
, COL_INFO
);
1081 col_set_writable(pinfo
->cinfo
, TRUE
);
1084 /* Create pdcp tree. */
1086 root_ti
= proto_tree_add_item(tree
, proto_pdcp_lte
, tvb
, offset
, -1, ENC_NA
);
1087 pdcp_tree
= proto_item_add_subtree(root_ti
, ett_pdcp
);
1090 /* Set mode string */
1091 mode
= val_to_str_const(p_pdcp_info
->rohc
.mode
, rohc_mode_vals
, "Error");
1093 /*****************************************************/
1094 /* Show configuration (attached packet) info in tree */
1096 show_pdcp_config(pinfo
, tvb
, pdcp_tree
, p_pdcp_info
);
1099 /* Show ROHC mode */
1100 if (p_pdcp_info
->rohc
.rohc_compression
) {
1101 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (mode=%c)", mode
[0]);
1104 /***************************************/
1105 /* UE security algorithms */
1106 if (!pinfo
->fd
->flags
.visited
) {
1107 /* Look up current state by UEID */
1108 current_security
= (pdcp_security_info_t
*)g_hash_table_lookup(pdcp_security_hash
,
1109 GUINT_TO_POINTER((guint
)p_pdcp_info
->ueid
));
1110 if (current_security
!= NULL
) {
1111 /* Store any result for this frame in the result table */
1112 pdcp_security_info_t
*security_to_store
= wmem_new(wmem_file_scope(), pdcp_security_info_t
);
1113 *security_to_store
= *current_security
;
1114 g_hash_table_insert(pdcp_security_result_hash
,
1115 get_ueid_frame_hash_key(p_pdcp_info
->ueid
, pinfo
->fd
->num
, TRUE
),
1119 /* Show security settings for this PDU */
1120 pdu_security
= (pdcp_security_info_t
*)g_hash_table_lookup(pdcp_security_result_hash
, get_ueid_frame_hash_key(p_pdcp_info
->ueid
, pinfo
->fd
->num
, FALSE
));
1121 if (pdu_security
!= NULL
) {
1122 proto_tree
*security_tree
;
1123 proto_item
*security_ti
, *ti
;
1125 /* Create subtree */
1126 security_ti
= proto_tree_add_string_format(pdcp_tree
,
1127 hf_pdcp_lte_security
,
1130 security_tree
= proto_item_add_subtree(security_ti
,
1132 PROTO_ITEM_SET_GENERATED(security_ti
);
1135 ti
= proto_tree_add_uint(security_tree
, hf_pdcp_lte_security_setup_frame
,
1136 tvb
, 0, 0, pdu_security
->configuration_frame
);
1137 PROTO_ITEM_SET_GENERATED(ti
);
1140 ti
= proto_tree_add_uint(security_tree
, hf_pdcp_lte_security_ciphering_algorithm
,
1141 tvb
, 0, 0, pdu_security
->ciphering
);
1142 PROTO_ITEM_SET_GENERATED(ti
);
1145 ti
= proto_tree_add_uint(security_tree
, hf_pdcp_lte_security_integrity_algorithm
,
1146 tvb
, 0, 0, pdu_security
->integrity
);
1147 PROTO_ITEM_SET_GENERATED(ti
);
1149 proto_item_append_text(security_ti
, " (ciphering=%s, integrity=%s)",
1150 val_to_str_const(pdu_security
->ciphering
, ciphering_algorithm_vals
, "Unknown"),
1151 val_to_str_const(pdu_security
->integrity
, integrity_algorithm_vals
, "Unknown"));
1155 /***********************************/
1156 /* Handle PDCP header (if present) */
1157 if (!p_pdcp_info
->no_header_pdu
) {
1159 /* TODO: shouldn't need to initialise this one!! */
1161 gboolean seqnum_set
= FALSE
;
1163 guint8 first_byte
= tvb_get_guint8(tvb
, offset
);
1165 /*****************************/
1166 /* Signalling plane messages */
1167 if (p_pdcp_info
->plane
== SIGNALING_PLANE
) {
1169 guint32 data_length
;
1171 /* Verify 3 reserved bits are 0 */
1172 guint8 reserved
= (first_byte
& 0xe0) >> 5;
1173 proto_item
*ti
= proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_control_plane_reserved
,
1174 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1175 if (reserved
!= 0) {
1176 expert_add_info_format(pinfo
, ti
, &ei_pdcp_lte_reserved_bits_not_zero
,
1177 "PDCP signalling header reserved bits not zero");
1180 /* 5-bit sequence number */
1181 seqnum
= first_byte
& 0x1f;
1183 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_seq_num_5
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1184 write_pdu_label_and_info(root_ti
, pinfo
, " sn=%-2u ", seqnum
);
1187 if (tvb_length_remaining(tvb
, offset
) == 0) {
1188 /* Only PDCP header was captured, stop dissection here */
1192 /* RRC data is all but last 4 bytes.
1193 Call lte-rrc dissector (according to direction and channel type) */
1194 if ((global_pdcp_dissect_signalling_plane_as_rrc
) &&
1195 ((pdu_security
== NULL
) || (pdu_security
->ciphering
== 0) || !pdu_security
->seen_next_ul_pdu
)){
1196 /* Get appropriate dissector handle */
1197 dissector_handle_t rrc_handle
= lookup_rrc_dissector_handle(p_pdcp_info
);
1199 if (rrc_handle
!= 0) {
1200 /* Call RRC dissector if have one */
1201 tvbuff_t
*payload_tvb
= tvb_new_subset(tvb
, offset
,
1202 tvb_length_remaining(tvb
, offset
) - 4,
1203 tvb_length_remaining(tvb
, offset
) - 4);
1204 gboolean was_writable
= col_get_writable(pinfo
->cinfo
);
1206 /* We always want to see this in the info column */
1207 col_set_writable(pinfo
->cinfo
, TRUE
);
1209 call_dissector_only(rrc_handle
, payload_tvb
, pinfo
, pdcp_tree
, NULL
);
1211 /* Restore to whatever it was */
1212 col_set_writable(pinfo
->cinfo
, was_writable
);
1215 /* Just show data */
1216 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_signalling_data
, tvb
, offset
,
1217 tvb_length_remaining(tvb
, offset
) - 4, ENC_NA
);
1220 if (!pinfo
->fd
->flags
.visited
&&
1221 (current_security
!= NULL
) && !current_security
->seen_next_ul_pdu
&&
1222 p_pdcp_info
->direction
== DIRECTION_UPLINK
)
1224 /* i.e. we have already seen SecurityModeResponse! */
1225 current_security
->seen_next_ul_pdu
= TRUE
;
1230 /* Just show as unparsed data */
1231 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_signalling_data
, tvb
, offset
,
1232 tvb_length_remaining(tvb
, offset
) - 4, ENC_NA
);
1235 data_length
= tvb_length_remaining(tvb
, offset
) - 4;
1236 offset
+= data_length
;
1238 /* Last 4 bytes are MAC */
1239 mac
= tvb_get_ntohl(tvb
, offset
);
1240 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_mac
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1243 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " MAC=0x%08x (%u bytes data)",
1246 else if (p_pdcp_info
->plane
== USER_PLANE
) {
1248 /**********************************/
1249 /* User-plane messages */
1250 gboolean pdu_type
= (first_byte
& 0x80) >> 7;
1252 /* Data/Control flag */
1253 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_data_control
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1255 if (pdu_type
== 1) {
1256 /*****************************/
1257 /* Use-plane Data */
1259 /* Number of sequence number bits depends upon config */
1260 switch (p_pdcp_info
->seqnum_length
) {
1261 case PDCP_SN_LENGTH_7_BITS
:
1262 seqnum
= first_byte
& 0x7f;
1264 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_seq_num_7
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1267 case PDCP_SN_LENGTH_12_BITS
:
1270 guint8 reserved_value
;
1272 /* 3 reserved bits */
1273 ti
= proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_reserved3
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1274 reserved_value
= (first_byte
& 0x70) >> 4;
1276 /* Complain if not 0 */
1277 if (reserved_value
!= 0) {
1278 expert_add_info_format(pinfo
, ti
, &ei_pdcp_lte_reserved_bits_not_zero
,
1279 "Reserved bits have value 0x%x - should be 0x0",
1283 /* 12-bit sequence number */
1284 seqnum
= tvb_get_ntohs(tvb
, offset
) & 0x0fff;
1286 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_seq_num_12
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1290 case PDCP_SN_LENGTH_15_BITS
:
1291 seqnum
= tvb_get_ntohs(tvb
, offset
) & 0x7fff;
1293 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_seq_num_15
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1297 /* Not a recognised data format!!!!! */
1301 write_pdu_label_and_info(root_ti
, pinfo
, " (SN=%u)", seqnum
);
1304 /*******************************/
1305 /* User-plane Control messages */
1306 guint8 control_pdu_type
= (first_byte
& 0x70) >> 4;
1307 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_control_pdu_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1309 switch (control_pdu_type
) {
1310 case 0: /* PDCP status report */
1315 guint not_received
= 0;
1317 guint32 len
, bit_offset
;
1318 proto_tree
*bitmap_tree
;
1319 proto_item
*bitmap_ti
= NULL
;
1321 #define BUFF_SIZE 49
1323 if (p_pdcp_info
->seqnum_length
== PDCP_SN_LENGTH_12_BITS
) {
1324 /* First-Missing-Sequence SN */
1325 fms
= tvb_get_ntohs(tvb
, offset
) & 0x0fff;
1326 sn
= (fms
+ 1) % 4096;
1327 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_fms
, tvb
,
1328 offset
, 2, ENC_BIG_ENDIAN
);
1333 guint8 reserved_value
;
1335 /* 5 reserved bits */
1336 ti
= proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_reserved4
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1337 reserved_value
= (tvb_get_ntohs(tvb
, offset
) & 0x0f80)>>7;
1340 /* Complain if not 0 */
1341 if (reserved_value
!= 0) {
1342 expert_add_info_format(pinfo
, ti
, &ei_pdcp_lte_reserved_bits_not_zero
,
1343 "Reserved bits have value 0x%x - should be 0x0",
1347 /* First-Missing-Sequence SN */
1348 fms
= tvb_get_ntohs(tvb
, offset
) & 0x7fff;
1349 sn
= (fms
+ 1) % 32768;
1350 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_fms2
, tvb
,
1351 offset
, 2, ENC_BIG_ENDIAN
);
1357 if (tvb_length_remaining(tvb
, offset
) > 0) {
1358 bitmap_ti
= proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_bitmap
, tvb
,
1359 offset
, -1, ENC_NA
);
1360 bitmap_tree
= proto_item_add_subtree(bitmap_ti
, ett_pdcp_report_bitmap
);
1362 buff
= (gchar
*)wmem_alloc(wmem_packet_scope(), BUFF_SIZE
);
1363 len
= tvb_length_remaining(tvb
, offset
);
1364 bit_offset
= offset
<<3;
1365 /* For each byte... */
1366 for (i
=0; i
<len
; i
++) {
1367 bits
= tvb_get_bits8(tvb
, bit_offset
, 8);
1368 for (l
=0, j
=0; l
<8; l
++) {
1369 if ((bits
<< l
) & 0x80) {
1370 j
+= g_snprintf(&buff
[j
], BUFF_SIZE
-j
, "%5u,", (unsigned)(sn
+(8*i
)+l
)%modulo
);
1372 j
+= g_snprintf(&buff
[j
], BUFF_SIZE
-j
, " ,");
1376 proto_tree_add_text(bitmap_tree
, tvb
, bit_offset
/8, 1, "%s", buff
);
1381 if (bitmap_ti
!= NULL
) {
1382 proto_item_append_text(bitmap_ti
, " (%u SNs not received)", not_received
);
1384 write_pdu_label_and_info(root_ti
, pinfo
, " Status Report (fms=%u) not-received=%u",
1389 case 1: /* ROHC Feedback */
1391 break; /* Drop-through to dissect feedback */
1393 default: /* Reserved */
1399 /* Invalid plane setting...! */
1400 write_pdu_label_and_info(root_ti
, pinfo
, " - INVALID PLANE (%u)",
1401 p_pdcp_info
->plane
);
1405 /* Do sequence analysis if configured to. */
1407 gboolean do_analysis
= FALSE
;
1409 switch (global_pdcp_check_sequence_numbers
) {
1412 case SEQUENCE_ANALYSIS_RLC_ONLY
:
1413 if ((p_get_proto_data(pinfo
->fd
, proto_rlc_lte
, 0) != NULL
) &&
1414 !p_pdcp_info
->is_retx
) {
1418 case SEQUENCE_ANALYSIS_PDCP_ONLY
:
1419 if (p_get_proto_data(pinfo
->fd
, proto_rlc_lte
, 0) == NULL
) {
1426 checkChannelSequenceInfo(pinfo
, tvb
, p_pdcp_info
,
1427 (guint16
)seqnum
, pdcp_tree
);
1432 /* Show that it's a no-header PDU */
1433 write_pdu_label_and_info(root_ti
, pinfo
, " No-Header ");
1436 /* If not compressed with ROHC, show as user-plane data */
1437 if (!p_pdcp_info
->rohc
.rohc_compression
) {
1438 gint payload_length
= tvb_length_remaining(tvb
, offset
);
1439 if (payload_length
> 0) {
1440 if (p_pdcp_info
->plane
== USER_PLANE
) {
1442 /* Not attempting to decode payload if ciphering is enabled
1443 (and NULL ciphering is not being used) */
1444 if (global_pdcp_dissect_user_plane_as_ip
&&
1445 ((pdu_security
== NULL
) || (pdu_security
->ciphering
== 0)))
1447 tvbuff_t
*payload_tvb
= tvb_new_subset_remaining(tvb
, offset
);
1449 /* Don't update info column for ROHC unless configured to */
1450 if (global_pdcp_lte_layer_to_show
!= ShowTrafficLayer
) {
1451 col_set_writable(pinfo
->cinfo
, FALSE
);
1454 switch (tvb_get_guint8(tvb
, offset
) & 0xf0) {
1456 call_dissector_only(ip_handle
, payload_tvb
, pinfo
, pdcp_tree
, NULL
);
1459 call_dissector_only(ipv6_handle
, payload_tvb
, pinfo
, pdcp_tree
, NULL
);
1462 call_dissector_only(data_handle
, payload_tvb
, pinfo
, pdcp_tree
, NULL
);
1466 /* Freeze the columns again because we don't want other layers writing to info */
1467 if (global_pdcp_lte_layer_to_show
== ShowTrafficLayer
) {
1468 col_set_writable(pinfo
->cinfo
, FALSE
);
1473 proto_tree_add_item(pdcp_tree
, hf_pdcp_lte_user_plane_data
, tvb
, offset
, -1, ENC_NA
);
1477 write_pdu_label_and_info(root_ti
, pinfo
, "(%u bytes data)",
1481 /* (there will be no signalling data left at this point) */
1483 /* Let RLC write to columns again */
1484 col_set_writable(pinfo
->cinfo
, global_pdcp_lte_layer_to_show
== ShowRLCLayer
);
1486 /* DROPPING OUT HERE IF NOT DOING ROHC! */
1491 /***************************/
1493 /***************************/
1496 /* Only attempt ROHC if configured to */
1497 if (!global_pdcp_dissect_rohc
) {
1498 col_append_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "|ROHC(%s)",
1499 val_to_str_const(p_pdcp_info
->rohc
.profile
, rohc_profile_vals
, "Unknown"));
1503 rohc_offset
= offset
;
1504 rohc_tvb
= tvb_new_subset_remaining(tvb
, rohc_offset
);
1507 p_rohc_info
= wmem_new(wmem_packet_scope(), rohc_info
);
1509 /* Copy struct. TODO: could just pass pdcp_info->rohc ?? */
1510 *p_rohc_info
= p_pdcp_info
->rohc
;
1512 /* Only enable writing to column if configured to show ROHC */
1513 if (global_pdcp_lte_layer_to_show
!= ShowTrafficLayer
) {
1514 col_set_writable(pinfo
->cinfo
, FALSE
);
1517 col_clear(pinfo
->cinfo
, COL_INFO
);
1520 /* Call the ROHC dissector */
1521 call_dissector_with_data(rohc_handle
, rohc_tvb
, pinfo
, tree
, p_rohc_info
);
1523 /* Let RLC write to columns again */
1524 col_set_writable(pinfo
->cinfo
, global_pdcp_lte_layer_to_show
== ShowRLCLayer
);
1527 /* Initializes the hash tables each time a new
1528 * file is loaded or re-loaded in wireshark */
1529 static void pdcp_lte_init_protocol(void)
1531 /* Destroy any existing hashes. */
1532 if (pdcp_sequence_analysis_channel_hash
) {
1533 g_hash_table_destroy(pdcp_sequence_analysis_channel_hash
);
1535 if (pdcp_lte_sequence_analysis_report_hash
) {
1536 g_hash_table_destroy(pdcp_lte_sequence_analysis_report_hash
);
1538 if (pdcp_security_hash
) {
1539 g_hash_table_destroy(pdcp_security_hash
);
1541 if (pdcp_security_result_hash
) {
1542 g_hash_table_destroy(pdcp_security_result_hash
);
1545 /* Now create them over */
1546 pdcp_sequence_analysis_channel_hash
= g_hash_table_new(pdcp_channel_hash_func
, pdcp_channel_equal
);
1547 pdcp_lte_sequence_analysis_report_hash
= g_hash_table_new(pdcp_result_hash_func
, pdcp_result_hash_equal
);
1548 pdcp_security_hash
= g_hash_table_new(pdcp_lte_ueid_hash_func
, pdcp_lte_ueid_hash_equal
);
1549 pdcp_security_result_hash
= g_hash_table_new(pdcp_lte_ueid_frame_hash_func
, pdcp_lte_ueid_frame_hash_equal
);
1554 void proto_register_pdcp(void)
1556 static hf_register_info hf
[] =
1558 { &hf_pdcp_lte_configuration
,
1560 "pdcp-lte.configuration", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1561 "Configuration info passed into dissector", HFILL
1565 { &hf_pdcp_lte_rohc_compression
,
1566 { "ROHC Compression",
1567 "pdcp-lte.rohc.compression", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1571 { &hf_pdcp_lte_rohc_mode
,
1573 "pdcp-lte.rohc.mode", FT_UINT8
, BASE_DEC
, VALS(rohc_mode_vals
), 0x0,
1577 { &hf_pdcp_lte_rohc_rnd
,
1578 { "RND", /* TODO: true/false vals? */
1579 "pdcp-lte.rohc.rnd", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1580 "RND of outer ip header", HFILL
1583 { &hf_pdcp_lte_rohc_udp_checksum_present
,
1584 { "UDP Checksum", /* TODO: true/false vals? */
1585 "pdcp-lte.rohc.checksum-present", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1586 "UDP Checksum present", HFILL
1589 { &hf_pdcp_lte_direction
,
1591 "pdcp-lte.direction", FT_UINT8
, BASE_DEC
, VALS(direction_vals
), 0x0,
1592 "Direction of message", HFILL
1595 { &hf_pdcp_lte_ueid
,
1597 "pdcp-lte.ueid", FT_UINT16
, BASE_DEC
, 0, 0x0,
1598 "UE Identifier", HFILL
1601 { &hf_pdcp_lte_channel_type
,
1603 "pdcp-lte.channel-type", FT_UINT8
, BASE_DEC
, VALS(logical_channel_vals
), 0x0,
1607 { &hf_pdcp_lte_channel_id
,
1609 "pdcp-lte.channel-id", FT_UINT8
, BASE_DEC
, 0, 0x0,
1613 { &hf_pdcp_lte_rohc_profile
,
1615 "pdcp-lte.rohc.profile", FT_UINT8
, BASE_DEC
, VALS(rohc_profile_vals
), 0x0,
1619 { &hf_pdcp_lte_no_header_pdu
,
1621 "pdcp-lte.no-header_pdu", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1625 { &hf_pdcp_lte_plane
,
1627 "pdcp-lte.plane", FT_UINT8
, BASE_DEC
, VALS(pdcp_plane_vals
), 0x0,
1631 { &hf_pdcp_lte_seqnum_length
,
1633 "pdcp-lte.seqnum_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1634 "Sequence Number Length", HFILL
1639 { &hf_pdcp_lte_cid_inclusion_info
,
1640 { "CID Inclusion Info",
1641 "pdcp-lte.cid-inclusion-info", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1645 { &hf_pdcp_lte_large_cid_present
,
1646 { "Large CID Present",
1647 "pdcp-lte.large-cid-present", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1652 { &hf_pdcp_lte_control_plane_reserved
,
1654 "pdcp-lte.reserved", FT_UINT8
, BASE_DEC
, NULL
, 0xe0,
1658 { &hf_pdcp_lte_seq_num_5
,
1660 "pdcp-lte.seq-num", FT_UINT8
, BASE_DEC
, NULL
, 0x1f,
1661 "PDCP Seq num", HFILL
1664 { &hf_pdcp_lte_seq_num_7
,
1666 "pdcp-lte.seq-num", FT_UINT8
, BASE_DEC
, NULL
, 0x7f,
1667 "PDCP Seq num", HFILL
1670 { &hf_pdcp_lte_reserved3
,
1672 "pdcp-lte.reserved3", FT_UINT8
, BASE_HEX
, NULL
, 0x70,
1673 "3 reserved bits", HFILL
1676 { &hf_pdcp_lte_seq_num_12
,
1678 "pdcp-lte.seq-num", FT_UINT16
, BASE_DEC
, NULL
, 0x0fff,
1679 "PDCP Seq num", HFILL
1682 { &hf_pdcp_lte_seq_num_15
,
1684 "pdcp-lte.seq-num", FT_UINT16
, BASE_DEC
, NULL
, 0x7fff,
1685 "PDCP Seq num", HFILL
1688 { &hf_pdcp_lte_signalling_data
,
1689 { "Signalling Data",
1690 "pdcp-lte.signalling-data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1696 "pdcp-lte.mac", FT_UINT32
, BASE_HEX_DEC
, NULL
, 0x0,
1700 { &hf_pdcp_lte_data_control
,
1702 "pdcp-lte.pdu-type", FT_UINT8
, BASE_HEX
, VALS(pdu_type_vals
), 0x80,
1706 { &hf_pdcp_lte_user_plane_data
,
1707 { "User-Plane Data",
1708 "pdcp-lte.user-data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1712 { &hf_pdcp_lte_control_pdu_type
,
1713 { "Control PDU Type",
1714 "pdcp-lte.control-pdu-type", FT_UINT8
, BASE_HEX
, VALS(control_pdu_type_vals
), 0x70,
1719 { "First Missing Sequence Number",
1720 "pdcp-lte.fms", FT_UINT16
, BASE_DEC
, NULL
, 0x0fff,
1721 "First Missing PDCP Sequence Number", HFILL
1724 { &hf_pdcp_lte_reserved4
,
1726 "pdcp-lte.reserved4", FT_UINT16
, BASE_HEX
, NULL
, 0x0f80,
1727 "5 reserved bits", HFILL
1730 { &hf_pdcp_lte_fms2
,
1731 { "First Missing Sequence Number",
1732 "pdcp-lte.fms", FT_UINT16
, BASE_DEC
, NULL
, 0x07fff,
1733 "First Missing PDCP Sequence Number", HFILL
1736 { &hf_pdcp_lte_bitmap
,
1738 "pdcp-lte.bitmap", FT_NONE
, BASE_NONE
, NULL
, 0x0,
1739 "Status report bitmap (0=error, 1=OK)", HFILL
1744 { &hf_pdcp_lte_sequence_analysis
,
1745 { "Sequence Analysis",
1746 "pdcp-lte.sequence-analysis", FT_STRING
, BASE_NONE
, 0, 0x0,
1750 { &hf_pdcp_lte_sequence_analysis_ok
,
1752 "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN
, BASE_NONE
, 0, 0x0,
1756 { &hf_pdcp_lte_sequence_analysis_previous_frame
,
1757 { "Previous frame for channel",
1758 "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM
, BASE_NONE
, 0, 0x0,
1762 { &hf_pdcp_lte_sequence_analysis_next_frame
,
1763 { "Next frame for channel",
1764 "pdcp-lte.sequence-analysis.next-frame", FT_FRAMENUM
, BASE_NONE
, 0, 0x0,
1768 { &hf_pdcp_lte_sequence_analysis_expected_sn
,
1770 "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16
, BASE_DEC
, 0, 0x0,
1774 { &hf_pdcp_lte_sequence_analysis_skipped
,
1776 "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN
, BASE_NONE
, 0, 0x0,
1780 { &hf_pdcp_lte_sequence_analysis_repeated
,
1782 "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN
, BASE_NONE
, 0, 0x0,
1787 { &hf_pdcp_lte_security
,
1788 { "Security Config",
1789 "pdcp-lte.security-cofig", FT_STRING
, BASE_NONE
, 0, 0x0,
1793 { &hf_pdcp_lte_security_setup_frame
,
1794 { "Configuration frame",
1795 "pdcp-lte.security-config.setup-frame", FT_FRAMENUM
, BASE_NONE
, 0, 0x0,
1799 { &hf_pdcp_lte_security_integrity_algorithm
,
1800 { "Integrity Algorithm",
1801 "pdcp-lte.security-config.integrity", FT_UINT16
, BASE_DEC
, VALS(integrity_algorithm_vals
), 0x0,
1805 { &hf_pdcp_lte_security_ciphering_algorithm
,
1806 { "Ciphering Algorithm",
1807 "pdcp-lte.security-config.ciphering", FT_UINT16
, BASE_DEC
, VALS(ciphering_algorithm_vals
), 0x0,
1813 static gint
*ett
[] =
1816 &ett_pdcp_configuration
,
1818 &ett_pdcp_lte_sequence_analysis
,
1819 &ett_pdcp_report_bitmap
,
1823 static ei_register_info ei
[] = {
1824 { &ei_pdcp_lte_sequence_analysis_sn_missing
, { "pdcp-lte.sequence-analysis.sn_missing", PI_SEQUENCE
, PI_WARN
, "PDCP SN missing", EXPFILL
}},
1825 { &ei_pdcp_lte_sequence_analysis_sn_repeated
, { "pdcp-lte.sequence-analysis.sn_repeated", PI_SEQUENCE
, PI_WARN
, "PDCP SN repeated", EXPFILL
}},
1826 { &ei_pdcp_lte_sequence_analysis_wrong_sequence_number
, { "pdcp-lte.sequence-analysis.wrong_sequence_number", PI_SEQUENCE
, PI_WARN
, "Wrong Sequence Number", EXPFILL
}},
1827 { &ei_pdcp_lte_reserved_bits_not_zero
, { "pdcp_lte.reserved_bits_not_zero", PI_MALFORMED
, PI_ERROR
, "Reserved bits not zero", EXPFILL
}},
1830 static const enum_val_t sequence_analysis_vals
[] = {
1831 {"no-analysis", "No-Analysis", FALSE
},
1832 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY
},
1833 {"pdcp-only", "Only-PDCP-frames", SEQUENCE_ANALYSIS_PDCP_ONLY
},
1837 static const enum_val_t show_info_col_vals
[] = {
1838 {"show-rlc", "RLC Info", ShowRLCLayer
},
1839 {"show-pdcp", "PDCP Info", ShowPDCPLayer
},
1840 {"show-traffic", "Traffic Info", ShowTrafficLayer
},
1844 module_t
*pdcp_lte_module
;
1845 expert_module_t
* expert_pdcp_lte
;
1847 /* Register protocol. */
1848 proto_pdcp_lte
= proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
1849 proto_register_field_array(proto_pdcp_lte
, hf
, array_length(hf
));
1850 proto_register_subtree_array(ett
, array_length(ett
));
1851 expert_pdcp_lte
= expert_register_protocol(proto_pdcp_lte
);
1852 expert_register_field_array(expert_pdcp_lte
, ei
, array_length(ei
));
1854 /* Allow other dissectors to find this one by name. */
1855 register_dissector("pdcp-lte", dissect_pdcp_lte
, proto_pdcp_lte
);
1857 pdcp_lte_module
= prefs_register_protocol(proto_pdcp_lte
, NULL
);
1859 /* Obsolete preferences */
1860 prefs_register_obsolete_preference(pdcp_lte_module
, "show_feedback_option_tag_length");
1862 /* Dissect uncompressed user-plane data as IP */
1863 prefs_register_bool_preference(pdcp_lte_module
, "show_user_plane_as_ip",
1864 "Show uncompressed User-Plane data as IP",
1865 "Show uncompressed User-Plane data as IP",
1866 &global_pdcp_dissect_user_plane_as_ip
);
1868 /* Dissect unciphered signalling data as RRC */
1869 prefs_register_bool_preference(pdcp_lte_module
, "show_signalling_plane_as_rrc",
1870 "Show unciphered Signalling-Plane data as RRC",
1871 "Show unciphered Signalling-Plane data as RRC",
1872 &global_pdcp_dissect_signalling_plane_as_rrc
);
1874 /* Check for missing sequence numbers */
1875 prefs_register_enum_preference(pdcp_lte_module
, "check_sequence_numbers",
1876 "Do sequence number analysis",
1877 "Do sequence number analysis",
1878 &global_pdcp_check_sequence_numbers
, sequence_analysis_vals
, FALSE
);
1880 /* Attempt to dissect ROHC messages */
1881 prefs_register_bool_preference(pdcp_lte_module
, "dissect_rohc",
1882 "Attempt to decode ROHC data",
1883 "Attempt to decode ROHC data",
1884 &global_pdcp_dissect_rohc
);
1886 prefs_register_bool_preference(pdcp_lte_module
, "heuristic_pdcp_lte_over_udp",
1887 "Try Heuristic LTE-PDCP over UDP framing",
1888 "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
1890 &global_pdcp_lte_heur
);
1892 prefs_register_enum_preference(pdcp_lte_module
, "layer_to_show",
1893 "Which layer info to show in Info column",
1894 "Can show RLC, PDCP or Traffic layer info in Info column",
1895 &global_pdcp_lte_layer_to_show
, show_info_col_vals
, FALSE
);
1897 register_init_routine(&pdcp_lte_init_protocol
);
1900 void proto_reg_handoff_pdcp_lte(void)
1902 /* Add as a heuristic UDP dissector */
1903 heur_dissector_add("udp", dissect_pdcp_lte_heur
, proto_pdcp_lte
);
1905 ip_handle
= find_dissector("ip");
1906 ipv6_handle
= find_dissector("ipv6");
1907 rohc_handle
= find_dissector("rohc");
1908 data_handle
= find_dissector("data");