6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include <epan/prefs.h>
18 #include <epan/expert.h>
20 #include <epan/proto_data.h>
22 #include <wsutil/wsgcrypt.h>
25 #include "packet-rlc-nr.h"
26 #include "packet-pdcp-nr.h"
28 void proto_register_pdcp_nr(void);
29 void proto_reg_handoff_pdcp_nr(void);
32 * 3GPP TS 38.323 Technical Specification Group Radio Access Netowrk; NR;
33 * Packet Data Convergence Protocol (PDCP) specification (Release 15.1.0)
38 - Deciphering, but should refactor and share LTE implementation
42 /* Initialize the protocol and registered fields. */
43 int proto_pdcp_nr = -1;
45 extern int proto_rlc_nr;
47 /* Configuration (info known outside of PDU) */
48 static int hf_pdcp_nr_configuration = -1;
49 static int hf_pdcp_nr_direction = -1;
50 static int hf_pdcp_nr_ueid = -1;
51 static int hf_pdcp_nr_bearer_type = -1;
52 static int hf_pdcp_nr_bearer_id = -1;
53 static int hf_pdcp_nr_plane = -1;
54 static int hf_pdcp_nr_seqnum_length = -1;
56 static int hf_pdcp_nr_rohc_compression = -1;
57 static int hf_pdcp_nr_rohc_mode = -1;
58 static int hf_pdcp_nr_rohc_rnd = -1;
59 static int hf_pdcp_nr_rohc_udp_checksum_present = -1;
60 static int hf_pdcp_nr_rohc_profile = -1;
61 static int hf_pdcp_nr_cid_inclusion_info = -1;
62 static int hf_pdcp_nr_large_cid_present = -1;
64 /* PDCP header fields */
65 static int hf_pdcp_nr_control_plane_reserved = -1;
66 static int hf_pdcp_nr_reserved3 = -1;
67 static int hf_pdcp_nr_seq_num_12 = -1;
68 static int hf_pdcp_nr_reserved5 = -1;
69 static int hf_pdcp_nr_seq_num_18 = -1;
70 static int hf_pdcp_nr_signalling_data = -1;
71 static int hf_pdcp_nr_mac = -1;
72 static int hf_pdcp_nr_data_control = -1;
73 static int hf_pdcp_nr_user_plane_data = -1;
74 static int hf_pdcp_nr_control_pdu_type = -1;
75 static int hf_pdcp_nr_fmc = -1;
76 static int hf_pdcp_nr_reserved4 = -1;
77 static int hf_pdcp_nr_bitmap = -1;
78 static int hf_pdcp_nr_bitmap_byte = -1;
80 /* Sequence Analysis */
81 static int hf_pdcp_nr_sequence_analysis = -1;
82 static int hf_pdcp_nr_sequence_analysis_ok = -1;
83 static int hf_pdcp_nr_sequence_analysis_previous_frame = -1;
84 static int hf_pdcp_nr_sequence_analysis_next_frame = -1;
85 static int hf_pdcp_nr_sequence_analysis_expected_sn = -1;
86 static int hf_pdcp_nr_sequence_analysis_repeated = -1;
87 static int hf_pdcp_nr_sequence_analysis_skipped = -1;
90 /* Protocol subtree. */
91 static int ett_pdcp = -1;
92 static int ett_pdcp_configuration = -1;
93 static int ett_pdcp_packet = -1;
94 static int ett_pdcp_nr_sequence_analysis = -1;
95 static int ett_pdcp_report_bitmap = -1;
97 static expert_field ei_pdcp_nr_sequence_analysis_wrong_sequence_number = EI_INIT;
98 static expert_field ei_pdcp_nr_reserved_bits_not_zero = EI_INIT;
99 static expert_field ei_pdcp_nr_sequence_analysis_sn_repeated = EI_INIT;
100 static expert_field ei_pdcp_nr_sequence_analysis_sn_missing = EI_INIT;
101 static expert_field ei_pdcp_nr_unknown_udp_framing_tag = EI_INIT;
102 static expert_field ei_pdcp_nr_missing_udp_framing_tag = EI_INIT;
106 static const value_string direction_vals[] =
108 { PDCP_NR_DIRECTION_UPLINK, "Uplink"},
109 { PDCP_NR_DIRECTION_DOWNLINK, "Downlink"},
114 static const value_string pdcp_plane_vals[] = {
115 { NR_SIGNALING_PLANE, "Signalling" },
116 { NR_USER_PLANE, "User" },
120 static const value_string bearer_type_vals[] = {
121 { Bearer_DCCH, "DCCH"},
122 { Bearer_BCCH_BCH, "BCCH_BCH"},
123 { Bearer_BCCH_DL_SCH, "BCCH_DL_SCH"},
124 { Bearer_CCCH, "CCCH"},
125 { Bearer_PCCH, "PCCH"},
129 static const value_string rohc_mode_vals[] = {
130 { UNIDIRECTIONAL, "Unidirectional" },
131 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
132 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
137 /* Entries taken from Table 5.7.1-1.
138 Descriptions from http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
139 static const value_string rohc_profile_vals[] = {
140 { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
141 { 0x0001, "ROHC RTP" }, /* [RFC3095] */
142 { 0x0002, "ROHC UDP" }, /* [RFC3095] */
143 { 0x0003, "ROHC ESP" }, /* [RFC3095] */
144 { 0x0004, "ROHC IP" }, /* [RFC3843] */
145 { 0x0006, "ROHC TCP" }, /* [RFC4996] */
147 { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
148 { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
149 { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
150 { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
154 static const true_false_string pdu_type_bit = {
160 static const value_string control_pdu_type_vals[] = {
161 { 0, "PDCP status report" },
162 { 1, "Interspersed ROHC feedback packet" },
167 static const value_string integrity_algorithm_vals[] = {
175 static const value_string ciphering_algorithm_vals[] = {
185 /* SDAP header fields and tree */
186 static int proto_sdap = -1;
187 static int hf_sdap_rdi = -1;
188 static int hf_sdap_rqi = -1;
189 static int hf_sdap_qfi = -1;
190 static int hf_sdap_data_control = -1;
191 static int hf_sdap_reserved = -1;
192 static gint ett_sdap = -1;
194 static const true_false_string sdap_rdi = {
195 "To store QoS flow to DRB mapping rule",
199 static const true_false_string sdap_rqi = {
200 "To inform NAS that RQI bit is set to 1",
205 static dissector_handle_t ip_handle;
206 static dissector_handle_t ipv6_handle;
207 static dissector_handle_t rohc_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_nr_layer_to_show = (gint)ShowRLCLayer;
226 /* Function to be called from outside this module (e.g. in a plugin) to get per-packet data */
227 pdcp_nr_info *get_pdcp_nr_proto_data(packet_info *pinfo)
229 return (pdcp_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0);
232 /* Function to be called from outside this module (e.g. in a plugin) to set per-packet data */
233 void set_pdcp_nr_proto_data(packet_info *pinfo, pdcp_nr_info *p_pdcp_nr_info)
235 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0, p_pdcp_nr_info);
240 /**************************************************/
241 /* Sequence number analysis */
246 /* Using bit fields to fit into 32 bits, so avoiding the need to allocate
247 heap memory for these structs */
253 } pdcp_bearer_hash_key;
258 guint32 previousSequenceNumber;
259 guint32 previousFrameNum;
261 } pdcp_bearer_status;
263 /* The sequence analysis bearer hash table.
264 Maps key -> status */
265 static wmem_map_t *pdcp_sequence_analysis_bearer_hash = NULL;
268 /* Hash table types & functions for frame reports */
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: This is a bit random. */
294 return val1->frameNumber + (val1->bearerId<<7) +
297 (val1->direction<<6);
300 /* pdcp_bearer_hash_key fits into the pointer, so just copy the value into
301 a guint, cast to a pointer and return that as the key */
302 static gpointer get_bearer_hash_key(pdcp_bearer_hash_key *key)
305 /* TODO: assert that sizeof(pdcp_bearer_hash_key) <= sizeof(guint) ? */
306 memcpy(&asInt, key, sizeof(pdcp_bearer_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(guint32 SN, guint32 frameNumber,
312 pdcp_nr_info *p_pdcp_nr_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_nr_info->plane;
331 p_key->bearerId = p_pdcp_nr_info->bearerId;
332 p_key->direction = p_pdcp_nr_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 guint32 sequenceExpected;
348 guint32 previousFrameNum;
349 guint32 nextFrameNum;
355 sequence_state state;
356 } pdcp_sequence_report_in_frame;
358 /* The sequence analysis frame report hash table.
359 Maps pdcp_result_hash_key* -> pdcp_sequence_report_in_frame* */
360 static wmem_map_t *pdcp_nr_sequence_analysis_report_hash = NULL;
363 /* Add to the tree values associated with sequence analysis for this frame */
364 static void addBearerSequenceInfo(pdcp_sequence_report_in_frame *p,
365 pdcp_nr_info *p_pdcp_nr_info,
366 guint32 sequenceNumber,
367 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
369 proto_tree *seqnum_tree;
370 proto_item *seqnum_ti;
371 proto_item *ti_expected_sn;
375 seqnum_ti = proto_tree_add_string_format(tree,
376 hf_pdcp_nr_sequence_analysis,
378 "", "Sequence Analysis");
379 seqnum_tree = proto_item_add_subtree(seqnum_ti,
380 ett_pdcp_nr_sequence_analysis);
381 PROTO_ITEM_SET_GENERATED(seqnum_ti);
384 /* Previous bearer frame */
385 if (p->previousFrameNum != 0) {
386 proto_tree_add_uint(seqnum_tree, hf_pdcp_nr_sequence_analysis_previous_frame,
387 tvb, 0, 0, p->previousFrameNum);
390 /* Expected sequence number */
391 ti_expected_sn = proto_tree_add_uint(seqnum_tree, hf_pdcp_nr_sequence_analysis_expected_sn,
392 tvb, 0, 0, p->sequenceExpected);
393 PROTO_ITEM_SET_GENERATED(ti_expected_sn);
395 /* Make sure we have recognised SN length */
396 switch (p_pdcp_nr_info->seqnum_length) {
397 case PDCP_NR_SN_LENGTH_12_BITS:
398 case PDCP_NR_SN_LENGTH_18_BITS:
401 DISSECTOR_ASSERT_NOT_REACHED();
407 PROTO_ITEM_SET_HIDDEN(ti_expected_sn);
408 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_nr_sequence_analysis_ok,
410 PROTO_ITEM_SET_GENERATED(ti);
411 proto_item_append_text(seqnum_ti, " - OK");
413 /* Link to next SN in bearer (if known) */
414 if (p->nextFrameNum != 0) {
415 proto_tree_add_uint(seqnum_tree, hf_pdcp_nr_sequence_analysis_next_frame,
416 tvb, 0, 0, p->nextFrameNum);
422 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_nr_sequence_analysis_ok,
424 PROTO_ITEM_SET_GENERATED(ti);
425 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_nr_sequence_analysis_skipped,
427 PROTO_ITEM_SET_GENERATED(ti);
428 if (p->lastSN != p->firstSN) {
429 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_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_nr_info->direction, direction_vals, "Unknown"),
433 p_pdcp_nr_info->ueid,
434 val_to_str_const(p_pdcp_nr_info->bearerType, bearer_type_vals, "Unknown"),
435 p_pdcp_nr_info->bearerId);
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_nr_sequence_analysis_sn_missing,
441 "PDCP SN (%u) missing for %s on UE %u (%s-%u)",
443 val_to_str_const(p_pdcp_nr_info->direction, direction_vals, "Unknown"),
444 p_pdcp_nr_info->ueid,
445 val_to_str_const(p_pdcp_nr_info->bearerType, bearer_type_vals, "Unknown"),
446 p_pdcp_nr_info->bearerId);
447 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
453 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_nr_sequence_analysis_ok,
455 PROTO_ITEM_SET_GENERATED(ti);
456 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_nr_sequence_analysis_repeated,
458 PROTO_ITEM_SET_GENERATED(ti);
459 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_sequence_analysis_sn_repeated,
460 "PDCP SN (%u) repeated for %s for UE %u (%s-%u)",
462 val_to_str_const(p_pdcp_nr_info->direction, direction_vals, "Unknown"),
463 p_pdcp_nr_info->ueid,
464 val_to_str_const(p_pdcp_nr_info->bearerType, bearer_type_vals, "Unknown"),
465 p_pdcp_nr_info->bearerId);
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_nr_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_nr_info->direction, direction_vals, "Unknown"),
475 p_pdcp_nr_info->ueid,
476 val_to_str_const(p_pdcp_nr_info->bearerType, bearer_type_vals, "Unknown"),
477 p_pdcp_nr_info->bearerId,
478 sequenceNumber, p->sequenceExpected);
484 /* Update the bearer status and set report for this frame */
485 static void checkBearerSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
486 pdcp_nr_info *p_pdcp_nr_info,
487 guint32 sequenceNumber,
490 pdcp_bearer_hash_key bearer_key;
491 pdcp_bearer_status *p_bearer_status;
492 pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
493 gboolean createdBearer = FALSE;
494 guint32 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*)wmem_map_lookup(pdcp_nr_sequence_analysis_report_hash,
501 get_report_hash_key(sequenceNumber,
503 p_pdcp_nr_info, FALSE));
504 if (p_report_in_frame != NULL) {
505 addBearerSequenceInfo(p_report_in_frame, p_pdcp_nr_info,
511 /* Give up - we must have tried already... */
517 /**************************************************/
518 /* Create or find an entry for this bearer state */
519 bearer_key.ueId = p_pdcp_nr_info->ueid;
520 bearer_key.plane = p_pdcp_nr_info->plane;
521 bearer_key.bearerId = p_pdcp_nr_info->bearerId;
522 bearer_key.direction = p_pdcp_nr_info->direction;
523 bearer_key.notUsed = 0;
525 /* Do the table lookup */
526 p_bearer_status = (pdcp_bearer_status*)wmem_map_lookup(pdcp_sequence_analysis_bearer_hash,
527 get_bearer_hash_key(&bearer_key));
529 /* Create table entry if necessary */
530 if (p_bearer_status == NULL) {
531 createdBearer = TRUE;
533 /* Allocate a new value and duplicate key contents */
534 p_bearer_status = wmem_new0(wmem_file_scope(), pdcp_bearer_status);
537 wmem_map_insert(pdcp_sequence_analysis_bearer_hash,
538 get_bearer_hash_key(&bearer_key), p_bearer_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_nr_info->seqnum_length) {
546 case PDCP_NR_SN_LENGTH_12_BITS:
549 case PDCP_NR_SN_LENGTH_18_BITS:
553 DISSECTOR_ASSERT_NOT_REACHED();
557 /* Work out expected sequence number */
558 if (!createdBearer) {
559 expectedSequenceNumber = (p_bearer_status->previousSequenceNumber + 1) % snLimit;
562 expectedSequenceNumber = sequenceNumber;
565 /* Set report for this frame */
566 /* For PDCP, sequence number is always expectedSequence number */
567 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
568 p_report_in_frame->hfn = p_bearer_status->hfn;
570 /* For wrong sequence number... */
571 if (!p_report_in_frame->sequenceExpectedCorrect) {
573 /* Frames are not missing if we get an earlier sequence number again */
574 if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
575 p_report_in_frame->state = SN_Missing;
576 p_report_in_frame->firstSN = expectedSequenceNumber;
577 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
579 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
580 p_report_in_frame->previousFrameNum = p_bearer_status->previousFrameNum;
582 /* Update Bearer status to remember *this* frame */
583 p_bearer_status->previousFrameNum = pinfo->num;
584 p_bearer_status->previousSequenceNumber = sequenceNumber;
587 /* An SN has been repeated */
588 p_report_in_frame->state = SN_Repeated;
589 p_report_in_frame->firstSN = sequenceNumber;
591 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
592 p_report_in_frame->previousFrameNum = p_bearer_status->previousFrameNum;
597 p_report_in_frame->state = SN_OK;
598 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
599 p_report_in_frame->previousFrameNum = p_bearer_status->previousFrameNum;
600 /* SN has rolled around, inc hfn! */
601 if (!createdBearer && (sequenceNumber == 0)) {
602 /* TODO: not worrying about HFN rolling over for now! */
603 p_bearer_status->hfn++;
604 p_report_in_frame->hfn = p_bearer_status->hfn;
607 /* Update Bearer status to remember *this* frame */
608 p_bearer_status->previousFrameNum = pinfo->num;
609 p_bearer_status->previousSequenceNumber = sequenceNumber;
611 if (p_report_in_frame->previousFrameNum != 0) {
612 /* Get report for previous frame */
613 pdcp_sequence_report_in_frame *p_previous_report;
614 p_previous_report = (pdcp_sequence_report_in_frame*)wmem_map_lookup(pdcp_nr_sequence_analysis_report_hash,
615 get_report_hash_key((sequenceNumber+262144) % 262144,
616 p_report_in_frame->previousFrameNum,
619 /* It really shouldn't be NULL... */
620 if (p_previous_report != NULL) {
621 /* Point it forward to this one */
622 p_previous_report->nextFrameNum = pinfo->num;
627 /* Associate with this frame number */
628 wmem_map_insert(pdcp_nr_sequence_analysis_report_hash,
629 get_report_hash_key(sequenceNumber, pinfo->num,
630 p_pdcp_nr_info, TRUE),
633 /* Add state report for this frame into tree */
634 addBearerSequenceInfo(p_report_in_frame, p_pdcp_nr_info, sequenceNumber,
641 /* Result is (ueid, framenum) -> pdcp_security_info_t* */
642 typedef struct ueid_frame_t {
649 /* Write the given formatted text to:
651 - the top-level RLC PDU item */
652 static void write_pdu_label_and_info(proto_item *pdu_ti,
653 packet_info *pinfo, const char *format, ...)
655 #define MAX_INFO_BUFFER 256
656 static char info_buffer[MAX_INFO_BUFFER];
660 va_start(ap, format);
661 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
664 /* Add to indicated places */
665 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
666 /* TODO: gets called a lot, so a shame there isn't a proto_item_append_string() */
667 proto_item_append_text(pdu_ti, "%s", info_buffer);
672 /***************************************************************/
676 /* Show in the tree the config info attached to this frame, as generated fields */
677 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
678 pdcp_nr_info *p_pdcp_info)
681 proto_tree *configuration_tree;
682 proto_item *configuration_ti = proto_tree_add_item(tree,
683 hf_pdcp_nr_configuration,
684 tvb, 0, 0, ENC_ASCII|ENC_NA);
685 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
688 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_direction, tvb, 0, 0,
689 p_pdcp_info->direction);
690 PROTO_ITEM_SET_GENERATED(ti);
693 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_plane, tvb, 0, 0,
695 PROTO_ITEM_SET_GENERATED(ti);
698 if (p_pdcp_info->ueid != 0) {
699 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_ueid, tvb, 0, 0,
701 PROTO_ITEM_SET_GENERATED(ti);
702 write_pdu_label_and_info(configuration_ti, pinfo, "UEId=%3u", p_pdcp_info->ueid);
706 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_bearer_type, tvb, 0, 0,
707 p_pdcp_info->bearerType);
708 PROTO_ITEM_SET_GENERATED(ti);
709 if (p_pdcp_info->bearerId != 0) {
711 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_bearer_id, tvb, 0, 0,
712 p_pdcp_info->bearerId);
713 PROTO_ITEM_SET_GENERATED(ti);
716 /* Show channel type in root/Info */
717 if (p_pdcp_info->bearerType == Bearer_DCCH) {
718 write_pdu_label_and_info(configuration_ti, pinfo, " %s-%u ",
719 (p_pdcp_info->plane == NR_SIGNALING_PLANE) ? "SRB" : "DRB",
720 p_pdcp_info->bearerId);
723 write_pdu_label_and_info(configuration_ti, pinfo, " %s",
724 val_to_str_const(p_pdcp_info->bearerType, bearer_type_vals, "Unknown"));
727 if (p_pdcp_info->plane == NR_USER_PLANE) {
729 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_seqnum_length, tvb, 0, 0,
730 p_pdcp_info->seqnum_length);
731 PROTO_ITEM_SET_GENERATED(ti);
733 /* ROHC compression */
734 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_nr_rohc_compression, tvb, 0, 0,
735 p_pdcp_info->rohc.rohc_compression);
736 PROTO_ITEM_SET_GENERATED(ti);
738 /* ROHC-specific settings */
739 if (p_pdcp_info->rohc.rohc_compression) {
742 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_rohc_mode, tvb, 0, 0,
743 p_pdcp_info->rohc.mode);
744 PROTO_ITEM_SET_GENERATED(ti);
747 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_nr_rohc_rnd, tvb, 0, 0,
748 p_pdcp_info->rohc.rnd);
749 PROTO_ITEM_SET_GENERATED(ti);
752 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_nr_rohc_udp_checksum_present, tvb, 0, 0,
753 p_pdcp_info->rohc.udp_checksum_present);
754 PROTO_ITEM_SET_GENERATED(ti);
757 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_nr_rohc_profile, tvb, 0, 0,
758 p_pdcp_info->rohc.profile);
759 PROTO_ITEM_SET_GENERATED(ti);
761 /* CID Inclusion Info */
762 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_nr_cid_inclusion_info, tvb, 0, 0,
763 p_pdcp_info->rohc.cid_inclusion_info);
764 PROTO_ITEM_SET_GENERATED(ti);
767 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_nr_large_cid_present, tvb, 0, 0,
768 p_pdcp_info->rohc.large_cid_present);
769 PROTO_ITEM_SET_GENERATED(ti);
773 /* Append summary to configuration root */
774 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
775 val_to_str_const(p_pdcp_info->direction, direction_vals, "Unknown"),
776 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
778 if (p_pdcp_info->rohc.rohc_compression) {
779 const char *mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
780 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
782 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
784 proto_item_append_text(configuration_ti, ")");
785 PROTO_ITEM_SET_GENERATED(configuration_ti);
787 /* Show plane in info column */
788 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
789 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
794 /* Look for an RRC dissector for signalling data (using Bearer type and direction) */
795 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_nr_info *p_pdcp_info)
797 dissector_handle_t rrc_handle = 0;
799 /* TODO: add as they become available */
800 switch (p_pdcp_info->bearerType)
806 case Bearer_BCCH_BCH:
808 case Bearer_BCCH_DL_SCH:
821 /* Forwad declarations */
822 static int dissect_pdcp_nr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
824 static void report_heur_error(proto_tree *tree, packet_info *pinfo, expert_field *eiindex,
825 tvbuff_t *tvb, gint start, gint length)
830 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-NR");
831 col_clear(pinfo->cinfo, COL_INFO);
832 ti = proto_tree_add_item(tree, proto_pdcp_nr, tvb, 0, -1, ENC_NA);
833 subtree = proto_item_add_subtree(ti, ett_pdcp);
834 proto_tree_add_expert(subtree, pinfo, eiindex, tvb, start, length);
837 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
838 static gboolean dissect_pdcp_nr_heur(tvbuff_t *tvb, packet_info *pinfo,
839 proto_tree *tree, void *data _U_)
842 struct pdcp_nr_info *p_pdcp_nr_info;
845 gboolean seqnumLengthTagPresent = FALSE;
847 /* Needs to be at least as long as:
848 - the signature string
849 - fixed header byte(s)
851 - at least one byte of PDCP PDU payload.
852 However, let attempted dissection show if there are any tags at all. */
853 gint min_length = (gint)(strlen(PDCP_NR_START_STRING) + 3); /* signature */
855 if (tvb_captured_length_remaining(tvb, offset) < min_length) {
859 /* OK, compare with signature string */
860 if (tvb_strneql(tvb, offset, PDCP_NR_START_STRING, strlen(PDCP_NR_START_STRING)) != 0) {
863 offset += (gint)strlen(PDCP_NR_START_STRING);
866 /* If redissecting, use previous info struct (if available) */
867 p_pdcp_nr_info = (pdcp_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0);
868 if (p_pdcp_nr_info == NULL) {
869 /* Allocate new info struct for this frame */
870 p_pdcp_nr_info = wmem_new0(wmem_file_scope(), pdcp_nr_info);
872 /* Read fixed fields */
873 p_pdcp_nr_info->plane = (enum pdcp_nr_plane)tvb_get_guint8(tvb, offset++);
874 if (p_pdcp_nr_info->plane == NR_SIGNALING_PLANE) {
875 /* Signalling plane always has 12 SN bits */
876 p_pdcp_nr_info->seqnum_length = PDCP_NR_SN_LENGTH_12_BITS;
879 /* Read tagged fields */
880 while (tag != PDCP_NR_PAYLOAD_TAG) {
881 /* Process next tag */
882 tag = tvb_get_guint8(tvb, offset++);
884 case PDCP_NR_SEQNUM_LENGTH_TAG:
885 p_pdcp_nr_info->seqnum_length = tvb_get_guint8(tvb, offset);
887 seqnumLengthTagPresent = TRUE;
889 case PDCP_NR_DIRECTION_TAG:
890 p_pdcp_nr_info->direction = tvb_get_guint8(tvb, offset);
893 case PDCP_NR_BEARER_TYPE_TAG:
894 p_pdcp_nr_info->bearerType = (NRBearerType)tvb_get_guint8(tvb, offset);
897 case PDCP_NR_BEARER_ID_TAG:
898 p_pdcp_nr_info->bearerId = tvb_get_guint8(tvb, offset);
901 case PDCP_NR_UEID_TAG:
902 p_pdcp_nr_info->ueid = tvb_get_ntohs(tvb, offset);
905 case PDCP_NR_ROHC_COMPRESSION_TAG:
906 p_pdcp_nr_info->rohc.rohc_compression = TRUE;
908 case PDCP_NR_ROHC_IP_VERSION_TAG:
909 p_pdcp_nr_info->rohc.rohc_ip_version = tvb_get_guint8(tvb, offset);
912 case PDCP_NR_ROHC_CID_INC_INFO_TAG:
913 p_pdcp_nr_info->rohc.cid_inclusion_info = TRUE;
915 case PDCP_NR_ROHC_LARGE_CID_PRES_TAG:
916 p_pdcp_nr_info->rohc.large_cid_present = TRUE;
918 case PDCP_NR_ROHC_MODE_TAG:
919 p_pdcp_nr_info->rohc.mode = (enum rohc_mode)tvb_get_guint8(tvb, offset);
922 case PDCP_NR_ROHC_RND_TAG:
923 p_pdcp_nr_info->rohc.rnd = TRUE;
925 case PDCP_NR_ROHC_UDP_CHECKSUM_PRES_TAG:
926 p_pdcp_nr_info->rohc.udp_checksum_present = TRUE;
928 case PDCP_NR_ROHC_PROFILE_TAG:
929 p_pdcp_nr_info->rohc.profile = tvb_get_ntohs(tvb, offset);
932 case PDCP_NR_MACI_PRES_TAG:
933 p_pdcp_nr_info->maci_present = TRUE;
935 case PDCP_NR_SDAP_HEADER_TAG:
936 p_pdcp_nr_info->sdap_header = tvb_get_guint8(tvb, offset) & 0x03;
940 case PDCP_NR_PAYLOAD_TAG:
941 /* Have reached data, so get out of loop */
942 p_pdcp_nr_info->pdu_length = tvb_reported_length_remaining(tvb, offset);
946 /* It must be a recognised tag */
947 report_heur_error(tree, pinfo, &ei_pdcp_nr_unknown_udp_framing_tag, tvb, offset-1, 1);
948 wmem_free(wmem_file_scope(), p_pdcp_nr_info);
953 if ((p_pdcp_nr_info->plane == NR_USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
954 /* Conditional field is not present */
955 report_heur_error(tree, pinfo, &ei_pdcp_nr_missing_udp_framing_tag, tvb, 0, offset);
956 wmem_free(wmem_file_scope(), p_pdcp_nr_info);
960 /* Store info in packet */
961 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0, p_pdcp_nr_info);
964 offset = tvb_reported_length(tvb) - p_pdcp_nr_info->pdu_length;
967 /**************************************/
968 /* OK, now dissect as PDCP nr */
970 /* Create tvb that starts at actual PDCP PDU */
971 pdcp_tvb = tvb_new_subset_remaining(tvb, offset);
972 dissect_pdcp_nr(pdcp_tvb, pinfo, tree, data);
977 /******************************/
978 /* Main dissection function. */
979 static int dissect_pdcp_nr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
982 proto_tree *pdcp_tree = NULL;
983 proto_item *root_ti = NULL;
986 struct pdcp_nr_info *p_pdcp_info;
987 tvbuff_t *rohc_tvb = NULL;
989 tvbuff_t *payload_tvb;
991 /* Set protocol name. */
992 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-NR");
994 /* Look for attached packet info! */
995 p_pdcp_info = (struct pdcp_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0);
996 /* Can't dissect anything without it... */
997 if (p_pdcp_info == NULL) {
1001 p_pdcp_info = (struct pdcp_nr_info *)data;
1004 /* Don't want to overwrite the RLC Info column if configured not to */
1005 if ((global_pdcp_nr_layer_to_show == ShowRLCLayer) &&
1006 (p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0) != NULL)) {
1008 col_set_writable(pinfo->cinfo, COL_INFO, FALSE);
1011 /* TODO: won't help with multiple PDCP-or-traffic PDUs / frame... */
1012 col_clear(pinfo->cinfo, COL_INFO);
1013 col_set_writable(pinfo->cinfo, COL_INFO, TRUE);
1016 /* Create pdcp tree. */
1018 root_ti = proto_tree_add_item(tree, proto_pdcp_nr, tvb, offset, -1, ENC_NA);
1019 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1022 /* Set mode string */
1023 mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
1025 /*****************************************************/
1026 /* Show configuration (attached packet) info in tree */
1028 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1031 /* Show ROHC mode */
1032 if (p_pdcp_info->rohc.rohc_compression) {
1033 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1037 /***********************************/
1038 /* Handle PDCP header */
1041 gboolean seqnum_set = FALSE;
1043 guint8 first_byte = tvb_get_guint8(tvb, offset);
1045 /*****************************/
1046 /* Signalling plane messages */
1047 if (p_pdcp_info->plane == NR_SIGNALING_PLANE) {
1048 /* Always 12 bits SN */
1049 /* Verify 4 reserved bits are 0 */
1050 guint8 reserved = (first_byte & 0xf0) >> 4;
1051 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_nr_control_plane_reserved,
1052 tvb, offset, 1, ENC_BIG_ENDIAN);
1053 if (reserved != 0) {
1054 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_reserved_bits_not_zero,
1055 "PDCP signalling header reserved bits not zero");
1058 /* 12-bit sequence number */
1059 proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_seq_num_12, tvb, offset, 2, ENC_BIG_ENDIAN, &seqnum);
1061 write_pdu_label_and_info(root_ti, pinfo, " (SN=%-4u)", seqnum);
1064 if (tvb_captured_length_remaining(tvb, offset) == 0) {
1065 /* Only PDCP header was captured, stop dissection here */
1069 else if (p_pdcp_info->plane == NR_USER_PLANE) {
1071 /**********************************/
1072 /* User-plane messages */
1073 gboolean is_user_plane;
1075 /* Data/Control flag */
1076 proto_tree_add_item_ret_boolean(pdcp_tree, hf_pdcp_nr_data_control, tvb, offset, 1, ENC_BIG_ENDIAN, &is_user_plane);
1078 if (is_user_plane) {
1079 /*****************************/
1080 /* User-plane Data */
1081 guint32 reserved_value;
1083 /* Number of sequence number bits depends upon config */
1084 switch (p_pdcp_info->seqnum_length) {
1085 case PDCP_NR_SN_LENGTH_12_BITS:
1086 /* 3 reserved bits */
1087 ti = proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_reserved3, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved_value);
1089 /* Complain if not 0 */
1090 if (reserved_value != 0) {
1091 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_reserved_bits_not_zero,
1092 "Reserved bits have value 0x%x - should be 0x0",
1096 /* 12-bit sequence number */
1097 proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_seq_num_12, tvb, offset, 2, ENC_BIG_ENDIAN, &seqnum);
1101 case PDCP_NR_SN_LENGTH_18_BITS:
1102 /* 5 reserved bits */
1103 ti = proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_reserved5, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved_value);
1105 /* Complain if not 0 */
1106 if (reserved_value != 0) {
1107 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_reserved_bits_not_zero,
1108 "Reserved bits have value 0x%x - should be 0x0",
1112 /* 18-bit sequence number */
1113 proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_seq_num_18, tvb, offset, 3, ENC_BIG_ENDIAN, &seqnum);
1118 /* Not a recognised data format!!!!! */
1122 write_pdu_label_and_info(root_ti, pinfo, " (SN=%-6u)", seqnum);
1125 /*******************************/
1126 /* User-plane Control messages */
1127 guint32 control_pdu_type;
1128 proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_control_pdu_type, tvb, offset, 1, ENC_BIG_ENDIAN, &control_pdu_type);
1130 switch (control_pdu_type) {
1131 case 0: /* PDCP status report */
1134 guint not_received = 0;
1136 guint32 len, bit_offset;
1137 proto_tree *bitmap_tree;
1138 proto_item *bitmap_ti = NULL;
1140 #define BUFF_SIZE 89
1141 guint32 reserved_value;
1143 /* 4 bits reserved */
1144 ti = proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_reserved4, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved_value);
1146 /* Complain if not 0 */
1147 if (reserved_value != 0) {
1148 expert_add_info_format(pinfo, ti, &ei_pdcp_nr_reserved_bits_not_zero,
1149 "Reserved bits have value 0x%x - should be 0x0",
1154 /* First-Missing-Count */
1155 proto_tree_add_item_ret_uint(pdcp_tree, hf_pdcp_nr_fmc, tvb, offset, 4, ENC_BIG_ENDIAN, &fmc);
1160 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1161 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_nr_bitmap, tvb,
1162 offset, -1, ENC_NA);
1163 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_report_bitmap);
1165 buff = (gchar *)wmem_alloc(wmem_packet_scope(), BUFF_SIZE);
1166 len = tvb_reported_length_remaining(tvb, offset);
1167 bit_offset = offset<<3;
1169 /* For each byte... */
1170 for (i=0; i<len; i++) {
1171 guint8 bits = tvb_get_bits8(tvb, bit_offset, 8);
1172 for (l=0, j=0; l<8; l++) {
1173 if ((bits << l) & 0x80) {
1175 // TODO: better to do mod and show as SN instead?
1176 j += g_snprintf(&buff[j], BUFF_SIZE-j, "%10u,", (unsigned)(fmc+(8*i)+l+1));
1180 j += (guint)g_strlcpy(&buff[j], " ,", BUFF_SIZE-j);
1186 proto_tree_add_uint_format(bitmap_tree, hf_pdcp_nr_bitmap_byte, tvb, bit_offset/8, 1, bits, "%s", buff);
1192 if (bitmap_ti != NULL) {
1193 proto_item_append_text(bitmap_ti, " (%u SNs not received)", not_received);
1195 write_pdu_label_and_info(root_ti, pinfo, " Status Report (fmc=%u) not-received=%u",
1200 case 1: /* ROHC Feedback */
1202 break; /* Drop-through to dissect feedback */
1207 /* Invalid plane setting...! */
1208 write_pdu_label_and_info(root_ti, pinfo, " - INVALID PLANE (%u)",
1209 p_pdcp_info->plane);
1213 /* Do sequence analysis if configured to. */
1215 gboolean do_analysis = FALSE;
1217 switch (global_pdcp_check_sequence_numbers) {
1220 case SEQUENCE_ANALYSIS_RLC_ONLY:
1221 if ((p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0) != NULL) &&
1222 !p_pdcp_info->is_retx) {
1226 case SEQUENCE_ANALYSIS_PDCP_ONLY:
1227 if (p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0) == NULL) {
1234 checkBearerSequenceInfo(pinfo, tvb, p_pdcp_info,
1240 /*******************************************************/
1241 /* Now deal with the payload */
1242 /*******************************************************/
1246 if (p_pdcp_info->plane == NR_SIGNALING_PLANE) {
1247 guint32 data_length;
1249 /* Compute payload length (no MAC on common control Bearers) */
1250 data_length = tvb_reported_length_remaining(payload_tvb, offset)-4;
1253 /* RRC data is all but last 4 bytes.
1254 Call nr-rrc dissector (according to direction and Bearer type) if we have valid data */
1255 if (global_pdcp_dissect_signalling_plane_as_rrc) {
1256 /* Get appropriate dissector handle */
1257 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1259 if (rrc_handle != 0) {
1260 /* Call RRC dissector if have one */
1261 tvbuff_t *rrc_payload_tvb = tvb_new_subset_length(payload_tvb, offset, data_length);
1262 gboolean was_writable = col_get_writable(pinfo->cinfo, COL_INFO);
1264 /* We always want to see this in the info column */
1265 col_set_writable(pinfo->cinfo, COL_INFO, TRUE);
1267 call_dissector_only(rrc_handle, rrc_payload_tvb, pinfo, pdcp_tree, NULL);
1269 /* Restore to whatever it was */
1270 col_set_writable(pinfo->cinfo, COL_INFO, was_writable);
1273 /* Just show data */
1274 proto_tree_add_item(pdcp_tree, hf_pdcp_nr_signalling_data, payload_tvb, offset,
1275 data_length, ENC_NA);
1279 /* Just show as unparsed data */
1280 proto_tree_add_item(pdcp_tree, hf_pdcp_nr_signalling_data, payload_tvb, offset,
1281 data_length, ENC_NA);
1284 if (p_pdcp_info->bearerType == Bearer_DCCH) {
1285 p_pdcp_info->maci_present = TRUE;
1287 col_append_fstr(pinfo->cinfo, COL_INFO, " (%u bytes data)", data_length);
1290 else if (tvb_captured_length_remaining(payload_tvb, offset)) {
1291 /* User-plane payload here. */
1292 gint payload_length = tvb_reported_length_remaining(payload_tvb, offset) - ((p_pdcp_info->maci_present) ? 4 : 0);
1294 if ((p_pdcp_info->direction == PDCP_NR_DIRECTION_UPLINK &&
1295 p_pdcp_info->sdap_header & PDCP_NR_UL_SDAP_HEADER_PRESENT) ||
1296 (p_pdcp_info->direction == PDCP_NR_DIRECTION_DOWNLINK &&
1297 p_pdcp_info->sdap_header & PDCP_NR_DL_SDAP_HEADER_PRESENT)) {
1298 proto_item *sdap_ti;
1299 proto_tree *sdap_tree;
1301 sdap_ti = proto_tree_add_item(pdcp_tree, proto_sdap, payload_tvb, offset, 1, ENC_NA);
1302 sdap_tree = proto_item_add_subtree(sdap_ti, ett_sdap);
1303 if (p_pdcp_info->direction == PDCP_NR_DIRECTION_UPLINK) {
1304 proto_tree_add_item(sdap_tree, hf_sdap_data_control, payload_tvb, offset, 1, ENC_NA);
1305 proto_tree_add_item(sdap_tree, hf_sdap_reserved, payload_tvb, offset, 1, ENC_NA);
1307 proto_tree_add_item(sdap_tree, hf_sdap_rdi, payload_tvb, offset, 1, ENC_NA);
1308 proto_tree_add_item(sdap_tree, hf_sdap_rqi, payload_tvb, offset, 1, ENC_NA);
1310 proto_tree_add_item(sdap_tree, hf_sdap_qfi, payload_tvb, offset, 1, ENC_NA);
1315 if (payload_length > 0) {
1316 /* If not compressed with ROHC, show as user-plane data */
1317 if (!p_pdcp_info->rohc.rohc_compression) {
1318 /* Not attempting to decode payload if ciphering is enabled
1319 (and NULL ciphering is not being used) */
1320 if (global_pdcp_dissect_user_plane_as_ip) {
1321 tvbuff_t *ip_payload_tvb = tvb_new_subset_length(payload_tvb, offset, payload_length);
1323 /* Don't update info column for ROHC unless configured to */
1324 if (global_pdcp_nr_layer_to_show != ShowTrafficLayer) {
1325 col_set_writable(pinfo->cinfo, COL_INFO, FALSE);
1328 switch (tvb_get_guint8(ip_payload_tvb, 0) & 0xf0) {
1330 call_dissector_only(ip_handle, ip_payload_tvb, pinfo, pdcp_tree, NULL);
1333 call_dissector_only(ipv6_handle, ip_payload_tvb, pinfo, pdcp_tree, NULL);
1336 call_data_dissector(ip_payload_tvb, pinfo, pdcp_tree);
1340 /* Freeze the columns again because we don't want other layers writing to info */
1341 if (global_pdcp_nr_layer_to_show == ShowTrafficLayer) {
1342 col_set_writable(pinfo->cinfo, COL_INFO, FALSE);
1347 proto_tree_add_item(pdcp_tree, hf_pdcp_nr_user_plane_data, payload_tvb, offset, payload_length, ENC_NA);
1351 /***************************/
1353 /***************************/
1355 /* Only attempt ROHC if configured to */
1356 if (!global_pdcp_dissect_rohc) {
1357 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
1358 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
1359 proto_tree_add_item(pdcp_tree, hf_pdcp_nr_user_plane_data, payload_tvb, offset, payload_length, ENC_NA);
1362 rohc_tvb = tvb_new_subset_length(payload_tvb, offset, payload_length);
1364 /* Only enable writing to column if configured to show ROHC */
1365 if (global_pdcp_nr_layer_to_show != ShowTrafficLayer) {
1366 col_set_writable(pinfo->cinfo, COL_INFO, FALSE);
1369 col_clear(pinfo->cinfo, COL_INFO);
1372 /* Call the ROHC dissector */
1373 call_dissector_with_data(rohc_handle, rohc_tvb, pinfo, tree, &p_pdcp_info->rohc);
1380 if (p_pdcp_info->maci_present) {
1381 /* Last 4 bytes are MAC */
1382 gint mac_offset = tvb_reported_length(tvb)-4;
1383 guint32 mac = tvb_get_ntohl(payload_tvb, mac_offset);
1384 proto_tree_add_item(pdcp_tree, hf_pdcp_nr_mac, payload_tvb, mac_offset, 4, ENC_BIG_ENDIAN);
1386 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x", mac);
1389 /* Let RLC write to columns again */
1390 col_set_writable(pinfo->cinfo, COL_INFO, global_pdcp_nr_layer_to_show == ShowRLCLayer);
1392 return tvb_captured_length(tvb);
1396 void proto_register_pdcp_nr(void)
1398 static hf_register_info hf_pdcp[] =
1400 { &hf_pdcp_nr_configuration,
1402 "pdcp-nr.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
1403 "Configuration info passed into dissector", HFILL
1406 { &hf_pdcp_nr_direction,
1408 "pdcp-nr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1409 "Direction of message", HFILL
1414 "pdcp-nr.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
1415 "UE Identifier", HFILL
1418 { &hf_pdcp_nr_bearer_type,
1420 "pdcp-nr.Bearer-type", FT_UINT8, BASE_DEC, VALS(bearer_type_vals), 0x0,
1424 { &hf_pdcp_nr_bearer_id,
1426 "pdcp-nr.bearer-id", FT_UINT8, BASE_DEC, 0, 0x0,
1430 { &hf_pdcp_nr_plane,
1432 "pdcp-nr.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
1436 { &hf_pdcp_nr_seqnum_length,
1438 "pdcp-nr.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
1439 "Sequence Number Length", HFILL
1443 { &hf_pdcp_nr_rohc_compression,
1444 { "ROHC Compression",
1445 "pdcp-nr.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1449 { &hf_pdcp_nr_rohc_mode,
1451 "pdcp-nr.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
1455 { &hf_pdcp_nr_rohc_rnd,
1457 "pdcp-nr.rohc.rnd", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1458 "RND of outer ip header", HFILL
1461 { &hf_pdcp_nr_rohc_udp_checksum_present,
1463 "pdcp-nr.rohc.checksum-present", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1464 "UDP Checksum present", HFILL
1467 { &hf_pdcp_nr_rohc_profile,
1469 "pdcp-nr.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
1473 { &hf_pdcp_nr_cid_inclusion_info,
1474 { "CID Inclusion Info",
1475 "pdcp-nr.cid-inclusion-info", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1479 { &hf_pdcp_nr_large_cid_present,
1480 { "Large CID Present",
1481 "pdcp-nr.large-cid-present", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1486 { &hf_pdcp_nr_control_plane_reserved,
1488 "pdcp-nr.reserved", FT_UINT8, BASE_DEC, NULL, 0xf0,
1492 { &hf_pdcp_nr_reserved3,
1494 "pdcp-nr.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
1495 "3 reserved bits", HFILL
1498 { &hf_pdcp_nr_seq_num_12,
1500 "pdcp-nr.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
1501 "PDCP Seq num", HFILL
1504 { &hf_pdcp_nr_reserved5,
1506 "pdcp-nr.reserved5", FT_UINT8, BASE_HEX, NULL, 0x7c,
1507 "5 reserved bits", HFILL
1510 { &hf_pdcp_nr_seq_num_18,
1512 "pdcp-nr.seq-num", FT_UINT24, BASE_DEC, NULL, 0x3ffff,
1513 "PDCP Seq num", HFILL
1516 { &hf_pdcp_nr_signalling_data,
1517 { "Signalling Data",
1518 "pdcp-nr.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1524 "pdcp-nr.mac", FT_UINT32, BASE_HEX, NULL, 0x0,
1528 { &hf_pdcp_nr_data_control,
1530 "pdcp-nr.pdu-type", FT_BOOLEAN, 8, TFS(&pdu_type_bit), 0x80,
1534 { &hf_pdcp_nr_user_plane_data,
1535 { "User-Plane Data",
1536 "pdcp-nr.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1540 { &hf_pdcp_nr_control_pdu_type,
1541 { "Control PDU Type",
1542 "pdcp-nr.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
1547 { "First Missing Count",
1548 "pdcp-nr.fmc", FT_UINT32, BASE_DEC, NULL, 0x0,
1552 { &hf_pdcp_nr_reserved4,
1554 "pdcp-nr.reserved4", FT_UINT8, BASE_HEX, NULL, 0x0f,
1555 "4 reserved bits", HFILL
1558 { &hf_pdcp_nr_bitmap,
1560 "pdcp-nr.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
1561 "Status report bitmap (0=error, 1=OK)", HFILL
1564 { &hf_pdcp_nr_bitmap_byte,
1566 "pdcp-nr.bitmap.byte", FT_UINT8, BASE_HEX, NULL, 0x0,
1571 { &hf_pdcp_nr_sequence_analysis,
1572 { "Sequence Analysis",
1573 "pdcp-nr.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
1577 { &hf_pdcp_nr_sequence_analysis_ok,
1579 "pdcp-nr.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1583 { &hf_pdcp_nr_sequence_analysis_previous_frame,
1584 { "Previous frame for Bearer",
1585 "pdcp-nr.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1589 { &hf_pdcp_nr_sequence_analysis_next_frame,
1590 { "Next frame for Bearer",
1591 "pdcp-nr.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1595 { &hf_pdcp_nr_sequence_analysis_expected_sn,
1597 "pdcp-nr.sequence-analysis.expected-sn", FT_UINT32, BASE_DEC, 0, 0x0,
1601 { &hf_pdcp_nr_sequence_analysis_skipped,
1603 "pdcp-nr.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1607 { &hf_pdcp_nr_sequence_analysis_repeated,
1609 "pdcp-nr.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1615 static hf_register_info hf_sdap[] =
1619 "sdap.rdi", FT_BOOLEAN, 8, TFS(&sdap_rdi), 0x80,
1625 "sdap.rqi", FT_BOOLEAN, 8, TFS(&sdap_rqi), 0x40,
1631 "sdap.qfi", FT_UINT8, BASE_DEC, NULL, 0x3f,
1635 { &hf_sdap_data_control,
1637 "sdap.reserved", FT_BOOLEAN, 8, TFS(&pdu_type_bit), 0x80,
1641 { &hf_sdap_reserved,
1643 "sdap.reserved", FT_UINT8, BASE_HEX, NULL, 0x40,
1649 static gint *ett[] =
1652 &ett_pdcp_configuration,
1654 &ett_pdcp_nr_sequence_analysis,
1655 &ett_pdcp_report_bitmap,
1659 static ei_register_info ei[] = {
1660 { &ei_pdcp_nr_sequence_analysis_sn_missing, { "pdcp-nr.sequence-analysis.sn-missing", PI_SEQUENCE, PI_WARN, "PDCP SN missing", EXPFILL }},
1661 { &ei_pdcp_nr_sequence_analysis_sn_repeated, { "pdcp-nr.sequence-analysis.sn-repeated", PI_SEQUENCE, PI_WARN, "PDCP SN repeated", EXPFILL }},
1662 { &ei_pdcp_nr_sequence_analysis_wrong_sequence_number, { "pdcp-nr.sequence-analysis.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
1663 { &ei_pdcp_nr_reserved_bits_not_zero, { "pdcp-nr.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
1664 { &ei_pdcp_nr_unknown_udp_framing_tag, { "pdcp-nr.unknown-udp-framing-tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }},
1665 { &ei_pdcp_nr_missing_udp_framing_tag, { "pdcp-nr.missing-udp-framing-tag", PI_UNDECODED, PI_WARN, "Missing UDP framing conditional tag, aborting dissection", EXPFILL }}
1668 static const enum_val_t sequence_analysis_vals[] = {
1669 {"no-analysis", "No-Analysis", FALSE},
1670 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
1671 {"pdcp-only", "Only-PDCP-frames", SEQUENCE_ANALYSIS_PDCP_ONLY},
1675 static const enum_val_t show_info_col_vals[] = {
1676 {"show-rlc", "RLC Info", ShowRLCLayer},
1677 {"show-pdcp", "PDCP Info", ShowPDCPLayer},
1678 {"show-traffic", "Traffic Info", ShowTrafficLayer},
1682 module_t *pdcp_nr_module;
1683 expert_module_t* expert_pdcp_nr;
1685 /* Register protocol. */
1686 proto_pdcp_nr = proto_register_protocol("PDCP-NR", "PDCP-NR", "pdcp-nr");
1687 proto_register_field_array(proto_pdcp_nr, hf_pdcp, array_length(hf_pdcp));
1688 proto_register_subtree_array(ett, array_length(ett));
1689 expert_pdcp_nr = expert_register_protocol(proto_pdcp_nr);
1690 expert_register_field_array(expert_pdcp_nr, ei, array_length(ei));
1691 proto_sdap = proto_register_protocol("SDAP", "SDAP", "sdap");
1692 proto_register_field_array(proto_sdap, hf_sdap, array_length(hf_sdap));
1694 /* Allow other dissectors to find this one by name. */
1695 register_dissector("pdcp-nr", dissect_pdcp_nr, proto_pdcp_nr);
1697 pdcp_nr_module = prefs_register_protocol(proto_pdcp_nr, NULL);
1699 /* Dissect uncompressed user-plane data as IP */
1700 prefs_register_bool_preference(pdcp_nr_module, "show_user_plane_as_ip",
1701 "Show uncompressed User-Plane data as IP",
1702 "Show uncompressed User-Plane data as IP",
1703 &global_pdcp_dissect_user_plane_as_ip);
1705 /* Dissect unciphered signalling data as RRC */
1706 prefs_register_bool_preference(pdcp_nr_module, "show_signalling_plane_as_rrc",
1707 "Show unciphered Signalling-Plane data as RRC",
1708 "Show unciphered Signalling-Plane data as RRC",
1709 &global_pdcp_dissect_signalling_plane_as_rrc);
1711 /* Check for missing sequence numbers */
1712 prefs_register_enum_preference(pdcp_nr_module, "check_sequence_numbers",
1713 "Do sequence number analysis",
1714 "Do sequence number analysis",
1715 &global_pdcp_check_sequence_numbers, sequence_analysis_vals, FALSE);
1717 /* Attempt to dissect ROHC messages */
1718 prefs_register_bool_preference(pdcp_nr_module, "dissect_rohc",
1719 "Attempt to decode ROHC data",
1720 "Attempt to decode ROHC data",
1721 &global_pdcp_dissect_rohc);
1723 prefs_register_obsolete_preference(pdcp_nr_module, "heuristic_pdcp_nr_over_udp");
1725 prefs_register_enum_preference(pdcp_nr_module, "layer_to_show",
1726 "Which layer info to show in Info column",
1727 "Can show RLC, PDCP or Traffic layer info in Info column",
1728 &global_pdcp_nr_layer_to_show, show_info_col_vals, FALSE);
1731 pdcp_sequence_analysis_bearer_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1732 pdcp_nr_sequence_analysis_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), pdcp_result_hash_func, pdcp_result_hash_equal);
1735 void proto_reg_handoff_pdcp_nr(void)
1737 /* Add as a heuristic UDP dissector */
1738 heur_dissector_add("udp", dissect_pdcp_nr_heur, "PDCP-NR over UDP", "pdcp_nr_udp", proto_pdcp_nr, HEURISTIC_DISABLE);
1740 ip_handle = find_dissector_add_dependency("ip", proto_pdcp_nr);
1741 ipv6_handle = find_dissector_add_dependency("ipv6", proto_pdcp_nr);
1742 rohc_handle = find_dissector_add_dependency("rohc", proto_pdcp_nr);
1751 * indent-tabs-mode: nil
1754 * ex: set shiftwidth=4 tabstop=8 expandtab:
1755 * :indentSize=4:tabSize=8:noTabs=true: