1 /* Routines for NR RLC disassembly
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/exceptions.h>
16 #include <epan/expert.h>
17 #include <epan/prefs.h>
19 #include <epan/proto_data.h>
20 #include <epan/reassemble.h>
22 #include <wsutil/array.h>
23 #include "packet-rlc-nr.h"
24 #include "packet-rlc-3gpp-common.h"
25 #include "packet-pdcp-nr.h"
29 * 3GPP TS 38.322 NR; Radio Link Control (RLC) protocol specification v15.0.0
33 - add sequence analysis
34 - take configuration of reordering timer, and stop reassembly if timeout exceeded?
35 - add tap info (for stats / SN graph)
38 void proto_register_rlc_nr(void);
39 void proto_reg_handoff_rlc_nr(void);
41 /********************************/
42 /* Preference settings */
44 /* By default do call PDCP/RRC dissectors for SDU data */
45 static bool global_rlc_nr_call_pdcp_for_srb
= true;
47 enum pdcp_for_drb
{ PDCP_drb_off
, PDCP_drb_SN_12
, PDCP_drb_SN_18
, PDCP_drb_SN_signalled
};
48 static const enum_val_t pdcp_drb_col_vals
[] = {
49 {"pdcp-drb-off", "Off", PDCP_drb_off
},
50 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12
},
51 {"pdcp-drb-sn-18", "18-bit SN", PDCP_drb_SN_18
},
52 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled
},
55 /* Separate config for UL/DL */
56 static int global_rlc_nr_call_pdcp_for_ul_drb
= (int)PDCP_drb_off
;
57 static int global_rlc_nr_call_pdcp_for_dl_drb
= (int)PDCP_drb_off
;
60 static bool global_rlc_nr_call_rrc_for_ccch
= true;
62 /* Preference to expect RLC headers without payloads */
63 static bool global_rlc_nr_headers_expected
;
65 /* Attempt reassembly. */
66 static bool global_rlc_nr_reassemble_um_pdus
;
67 static bool global_rlc_nr_reassemble_am_pdus
= true;
69 /* Tree storing UE related parameters (ueid, drbid) -> pdcp_bearer_parameters */
70 static wmem_tree_t
*ue_parameters_tree
;
72 /* Table storing starting frame for reassembly session during first pass */
73 /* Key is (ueId, direction, bearertype, bearerid, sn) */
74 static wmem_tree_t
*reassembly_start_table
;
76 /* Table storing starting frame for reassembly session during subsequent passes */
77 /* Key is (ueId, direction, bearertype, bearerid, sn, frame) */
78 static wmem_tree_t
*reassembly_start_table_stored
;
80 /**************************************************/
81 /* Initialize the protocol and registered fields. */
84 extern int proto_mac_nr
;
85 extern int proto_pdcp_nr
;
87 static dissector_handle_t pdcp_nr_handle
;
88 static dissector_handle_t nr_rrc_bcch_bch
;
89 static dissector_handle_t nr_rrc_bcch_dl_sch
;
90 static dissector_handle_t nr_rrc_pcch
;
91 static dissector_handle_t nr_rrc_ul_ccch
;
92 static dissector_handle_t nr_rrc_ul_ccch1
;
93 static dissector_handle_t nr_rrc_dl_ccch
;
96 static int rlc_nr_tap
= -1;
98 /* Decoding context */
99 static int hf_rlc_nr_context
;
100 static int hf_rlc_nr_context_mode
;
101 static int hf_rlc_nr_context_direction
;
102 static int hf_rlc_nr_context_ueid
;
103 static int hf_rlc_nr_context_bearer_type
;
104 static int hf_rlc_nr_context_bearer_id
;
105 static int hf_rlc_nr_context_pdu_length
;
106 static int hf_rlc_nr_context_sn_length
;
108 /* Transparent mode fields */
109 static int hf_rlc_nr_tm
;
110 static int hf_rlc_nr_tm_data
;
112 /* Unacknowledged mode fields */
113 static int hf_rlc_nr_um
;
114 static int hf_rlc_nr_um_header
;
115 static int hf_rlc_nr_um_si
;
116 static int hf_rlc_nr_um_reserved
;
117 static int hf_rlc_nr_um_sn6
;
118 static int hf_rlc_nr_um_sn12
;
119 static int hf_rlc_nr_um_so
;
120 static int hf_rlc_nr_um_data
;
122 /* Acknowledged mode fields */
123 static int hf_rlc_nr_am
;
124 static int hf_rlc_nr_am_header
;
125 static int hf_rlc_nr_am_data_control
;
126 static int hf_rlc_nr_am_p
;
127 static int hf_rlc_nr_am_si
;
128 static int hf_rlc_nr_am_sn12
;
129 static int hf_rlc_nr_am_sn18
;
130 static int hf_rlc_nr_am_reserved
;
131 static int hf_rlc_nr_am_so
;
132 static int hf_rlc_nr_am_data
;
135 static int hf_rlc_nr_am_cpt
;
136 static int hf_rlc_nr_am_ack_sn
;
137 static int hf_rlc_nr_am_e1
;
138 static int hf_rlc_nr_am_e2
;
139 static int hf_rlc_nr_am_e3
;
140 static int hf_rlc_nr_am_nack_sn
;
141 static int hf_rlc_nr_am_so_start
;
142 static int hf_rlc_nr_am_so_end
;
143 static int hf_rlc_nr_am_nack_range
;
144 static int hf_rlc_nr_am_nacks
;
146 static int hf_rlc_nr_header_only
;
148 static int hf_rlc_nr_fragments
;
149 static int hf_rlc_nr_fragment
;
150 static int hf_rlc_nr_fragment_overlap
;
151 static int hf_rlc_nr_fragment_overlap_conflict
;
152 static int hf_rlc_nr_fragment_multiple_tails
;
153 static int hf_rlc_nr_fragment_too_long_fragment
;
154 static int hf_rlc_nr_fragment_error
;
155 static int hf_rlc_nr_fragment_count
;
156 static int hf_rlc_nr_reassembled_in
;
157 static int hf_rlc_nr_reassembled_length
;
158 static int hf_rlc_nr_reassembled_data
;
163 static int ett_rlc_nr
;
164 static int ett_rlc_nr_context
;
165 static int ett_rlc_nr_um_header
;
166 static int ett_rlc_nr_am_header
;
167 static int ett_rlc_nr_fragments
;
168 static int ett_rlc_nr_fragment
;
171 static const fragment_items rlc_nr_frag_items
= {
172 &ett_rlc_nr_fragment
,
173 &ett_rlc_nr_fragments
,
174 &hf_rlc_nr_fragments
,
176 &hf_rlc_nr_fragment_overlap
,
177 &hf_rlc_nr_fragment_overlap_conflict
,
178 &hf_rlc_nr_fragment_multiple_tails
,
179 &hf_rlc_nr_fragment_too_long_fragment
,
180 &hf_rlc_nr_fragment_error
,
181 &hf_rlc_nr_fragment_count
,
182 &hf_rlc_nr_reassembled_in
,
183 &hf_rlc_nr_reassembled_length
,
184 &hf_rlc_nr_reassembled_data
,
189 static expert_field ei_rlc_nr_context_mode
;
190 static expert_field ei_rlc_nr_am_nack_sn
;
191 static expert_field ei_rlc_nr_am_nack_sn_ahead_ack
;
192 static expert_field ei_rlc_nr_am_nack_sn_ack_same
;
193 static expert_field ei_rlc_nr_am_nack_range
;
194 static expert_field ei_rlc_nr_am_cpt
;
195 static expert_field ei_rlc_nr_um_data_no_data
;
196 static expert_field ei_rlc_nr_am_data_no_data
;
197 static expert_field ei_rlc_nr_am_nack_sn_partial
;
198 static expert_field ei_rlc_nr_bytes_after_status_pdu_complete
;
199 static expert_field ei_rlc_nr_um_sn
;
200 static expert_field ei_rlc_nr_am_sn
;
201 static expert_field ei_rlc_nr_header_only
;
202 static expert_field ei_rlc_nr_reserved_bits_not_zero
;
203 static expert_field ei_rlc_nr_no_per_frame_info
;
204 static expert_field ei_rlc_nr_unknown_udp_framing_tag
;
207 static const value_string direction_vals
[] =
209 { DIRECTION_UPLINK
, "Uplink" },
210 { DIRECTION_DOWNLINK
, "Downlink" },
214 static const value_string rlc_mode_short_vals
[] =
216 { RLC_TM_MODE
, "TM" },
217 { RLC_UM_MODE
, "UM" },
218 { RLC_AM_MODE
, "AM" },
222 static const value_string rlc_mode_vals
[] =
224 { RLC_TM_MODE
, "Transparent Mode" },
225 { RLC_UM_MODE
, "Unacknowledged Mode" },
226 { RLC_AM_MODE
, "Acknowledged Mode" },
230 static const value_string rlc_bearer_type_vals
[] =
232 { BEARER_TYPE_CCCH
, "CCCH" },
233 { BEARER_TYPE_BCCH_BCH
, "BCCH BCH" },
234 { BEARER_TYPE_PCCH
, "PCCH" },
235 { BEARER_TYPE_SRB
, "SRB" },
236 { BEARER_TYPE_DRB
, "DRB" },
237 { BEARER_TYPE_BCCH_DL_SCH
, "BCCH DL-SCH" },
241 static const value_string seg_info_vals
[] =
243 { 0, "Data field contains all bytes of an RLC SDU" },
244 { 1, "Data field contains the first segment of an RLC SDU" },
245 { 2, "Data field contains the last segment of an RLC SDU" },
246 { 3, "Data field contains neither the first nor last segment of an RLC SDU" },
250 static const true_false_string polling_bit_vals
=
252 "Status report is requested",
253 "Status report not requested"
256 static const value_string control_pdu_type_vals
[] =
262 static const true_false_string am_e1_vals
=
264 "A set of NACK_SN, E1, E2 and E3 follows",
265 "A set of NACK_SN, E1, E2 and E3 does not follow"
268 static const true_false_string am_e2_vals
=
270 "A set of SOstart and SOend follows for this NACK_SN",
271 "A set of SOstart and SOend does not follow for this NACK_SN"
274 static const true_false_string am_e3_vals
=
276 "NACK range field follows for this NACK_SN",
277 "NACK range field does not follow for this NACK_SN"
280 static const true_false_string header_only_vals
=
282 "RLC PDU Headers only",
283 "RLC PDU Headers and body present"
286 /* Reassembly state */
287 static reassembly_table pdu_reassembly_table
;
289 static unsigned pdu_hash(const void *k
)
291 return GPOINTER_TO_UINT(k
);
294 static int pdu_equal(const void *k1
, const void *k2
)
299 static void *pdu_temporary_key(const packet_info
*pinfo _U_
, const uint32_t id _U_
, const void *data
)
304 static void *pdu_persistent_key(const packet_info
*pinfo _U_
, const uint32_t id _U_
,
310 static void pdu_free_temporary_key(void *ptr _U_
)
314 static void pdu_free_persistent_key(void *ptr _U_
)
318 static reassembly_table_functions pdu_reassembly_table_functions
=
324 pdu_free_temporary_key
,
325 pdu_free_persistent_key
329 /********************************************************/
330 /* Forward declarations & functions */
331 static void dissect_rlc_nr_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, bool is_udp_framing
);
334 /* Write the given formatted text to:
336 - the top-level RLC PDU item
337 - another subtree item (if supplied) */
338 static void write_pdu_label_and_info(proto_item
*pdu_ti
, proto_item
*sub_ti
,
339 packet_info
*pinfo
, const char *format
, ...) G_GNUC_PRINTF(4, 5);
340 static void write_pdu_label_and_info(proto_item
*pdu_ti
, proto_item
*sub_ti
,
341 packet_info
*pinfo
, const char *format
, ...)
343 #define MAX_INFO_BUFFER 256
344 static char info_buffer
[MAX_INFO_BUFFER
];
348 va_start(ap
, format
);
349 vsnprintf(info_buffer
, MAX_INFO_BUFFER
, format
, ap
);
352 /* Add to indicated places */
353 col_append_str(pinfo
->cinfo
, COL_INFO
, info_buffer
);
354 proto_item_append_text(pdu_ti
, "%s", info_buffer
);
355 if (sub_ti
!= NULL
) {
356 proto_item_append_text(sub_ti
, "%s", info_buffer
);
360 /* Version of function above, where no vsnprintf() call needed
362 - the top-level RLC PDU item
363 - another subtree item (if supplied) */
364 static void write_pdu_label_and_info_literal(proto_item
*pdu_ti
, proto_item
*sub_ti
,
365 packet_info
*pinfo
, const char *info_buffer
)
367 /* Add to indicated places */
368 col_append_str(pinfo
->cinfo
, COL_INFO
, info_buffer
);
369 proto_item_append_text(pdu_ti
, "%s", info_buffer
);
370 if (sub_ti
!= NULL
) {
371 proto_item_append_text(sub_ti
, "%s", info_buffer
);
375 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
376 whether or not the beginning and end are included in this packet */
377 static void show_PDU_in_info(packet_info
*pinfo
, proto_item
*top_ti
,
378 int32_t length
, uint8_t seg_info
)
380 /* Reflect this PDU in the info column */
382 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
384 (seg_info
& 0x02) ? ".." : "[",
386 (length
> 1) ? "s" : "",
387 (seg_info
& 0x01) ? ".." : "]");
389 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
390 " %sunknown-bytes%s",
391 (seg_info
& 0x02) ? ".." : "[",
392 (seg_info
& 0x01) ? ".." : "]");
397 /* Show an SDU. If configured, pass to PDCP/RRC dissector */
398 static void show_PDU_in_tree(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int length
,
399 rlc_nr_info
*rlc_info
, uint32_t seg_info
, bool is_reassembled
)
401 wmem_tree_key_t key
[2];
403 pdcp_bearer_parameters
*params
;
405 /* Add raw data (according to mode) */
406 if (!is_reassembled
) {
407 proto_tree_add_item(tree
, (rlc_info
->rlcMode
== RLC_AM_MODE
) ?
408 hf_rlc_nr_am_data
: hf_rlc_nr_um_data
,
409 tvb
, offset
, length
, ENC_NA
);
412 if ((seg_info
== 0) || is_reassembled
) { /* i.e. contains whole SDU */
413 if ((global_rlc_nr_call_pdcp_for_srb
&& (rlc_info
->bearerType
== BEARER_TYPE_SRB
)) ||
414 ((rlc_info
->bearerType
== BEARER_TYPE_DRB
) &&
415 (((rlc_info
->direction
== PDCP_NR_DIRECTION_UPLINK
) && (global_rlc_nr_call_pdcp_for_ul_drb
!= PDCP_drb_off
)) ||
416 ((rlc_info
->direction
== PDCP_NR_DIRECTION_DOWNLINK
) && (global_rlc_nr_call_pdcp_for_dl_drb
!= PDCP_drb_off
)))))
419 /* Get whole PDU into tvb */
420 tvbuff_t
*pdcp_tvb
= tvb_new_subset_length(tvb
, offset
, length
);
422 /* Reuse or allocate struct */
423 struct pdcp_nr_info
*p_pdcp_nr_info
;
424 p_pdcp_nr_info
= (pdcp_nr_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_pdcp_nr
, 0);
425 if (p_pdcp_nr_info
== NULL
) {
426 p_pdcp_nr_info
= wmem_new0(wmem_file_scope(), pdcp_nr_info
);
427 /* Store info in packet */
428 p_add_proto_data(wmem_file_scope(), pinfo
, proto_pdcp_nr
, 0, p_pdcp_nr_info
);
431 /* Fill in struct params. */
432 p_pdcp_nr_info
->direction
= rlc_info
->direction
;
433 p_pdcp_nr_info
->ueid
= rlc_info
->ueid
;
437 switch (rlc_info
->bearerType
) {
438 case BEARER_TYPE_SRB
:
439 p_pdcp_nr_info
->plane
= NR_SIGNALING_PLANE
;
440 p_pdcp_nr_info
->bearerType
= Bearer_DCCH
;
441 p_pdcp_nr_info
->seqnum_length
= 12;
444 case BEARER_TYPE_DRB
:
445 p_pdcp_nr_info
->plane
= NR_USER_PLANE
;
446 p_pdcp_nr_info
->bearerType
= Bearer_DCCH
;
448 seqnum_len
= (rlc_info
->direction
== PDCP_NR_DIRECTION_UPLINK
) ?
449 global_rlc_nr_call_pdcp_for_ul_drb
:
450 global_rlc_nr_call_pdcp_for_dl_drb
;
451 switch (seqnum_len
) {
453 p_pdcp_nr_info
->seqnum_length
= 12;
456 p_pdcp_nr_info
->seqnum_length
= 18;
458 case PDCP_drb_SN_signalled
:
459 /* Use whatever was signalled (i.e. in RRC) */
460 id
= (rlc_info
->bearerId
<< 16) | rlc_info
->ueid
;
466 /* Look up configured params for this PDCP DRB. */
467 params
= (pdcp_bearer_parameters
*)wmem_tree_lookup32_array_le(ue_parameters_tree
, key
);
468 if (params
&& (params
->id
!= id
)) {
472 if (p_pdcp_nr_info
->direction
== DIRECTION_UPLINK
) {
473 p_pdcp_nr_info
->seqnum_length
= params
->pdcp_sn_bits_ul
;
474 if (params
->pdcp_sdap_ul
) {
475 p_pdcp_nr_info
->sdap_header
&= PDCP_NR_UL_SDAP_HEADER_PRESENT
;
479 p_pdcp_nr_info
->seqnum_length
= params
->pdcp_sn_bits_dl
;
480 if (params
->pdcp_sdap_dl
) {
481 p_pdcp_nr_info
->sdap_header
&= PDCP_NR_DL_SDAP_HEADER_PRESENT
;
484 p_pdcp_nr_info
->maci_present
= params
->pdcp_integrity
;
485 p_pdcp_nr_info
->ciphering_disabled
= params
->pdcp_ciphering_disabled
;
493 /* Shouldn't get here */
496 p_pdcp_nr_info
->bearerId
= rlc_info
->bearerId
;
498 p_pdcp_nr_info
->rohc
.rohc_compression
= false;
499 p_pdcp_nr_info
->is_retx
= false;
500 p_pdcp_nr_info
->pdu_length
= length
;
503 call_dissector_only(pdcp_nr_handle
, pdcp_tvb
, pinfo
, tree
, NULL
);
512 /***************************************************/
513 /* Transparent mode PDU. Call RRC if configured to */
514 static void dissect_rlc_nr_tm(tvbuff_t
*tvb
, packet_info
*pinfo
,
517 rlc_nr_info
*p_rlc_nr_info
,
520 proto_item
*raw_tm_ti
;
523 /* Create hidden TM root */
524 tm_ti
= proto_tree_add_string_format(tree
, hf_rlc_nr_tm
,
525 tvb
, offset
, 0, "", "TM");
526 proto_item_set_hidden(tm_ti
);
528 /* Remaining bytes are all data */
529 raw_tm_ti
= proto_tree_add_item(tree
, hf_rlc_nr_tm_data
, tvb
, offset
, -1, ENC_NA
);
530 if (!global_rlc_nr_call_rrc_for_ccch
) {
531 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
532 " [%u-bytes]", tvb_reported_length_remaining(tvb
, offset
));
535 if (global_rlc_nr_call_rrc_for_ccch
) {
536 tvbuff_t
*rrc_tvb
= tvb_new_subset_remaining(tvb
, offset
);
537 volatile dissector_handle_t protocol_handle
;
539 switch (p_rlc_nr_info
->bearerType
) {
540 case BEARER_TYPE_BCCH_BCH
:
541 protocol_handle
= nr_rrc_bcch_bch
;
543 case BEARER_TYPE_BCCH_DL_SCH
:
544 protocol_handle
= nr_rrc_bcch_dl_sch
;
546 case BEARER_TYPE_PCCH
:
547 protocol_handle
= nr_rrc_pcch
;
549 case BEARER_TYPE_CCCH
:
550 if (p_rlc_nr_info
->direction
== DIRECTION_UPLINK
) {
551 protocol_handle
= (tvb_reported_length(rrc_tvb
) == 8) ?
552 nr_rrc_ul_ccch1
: nr_rrc_ul_ccch
;
554 protocol_handle
= nr_rrc_dl_ccch
;
557 case BEARER_TYPE_SRB
:
558 case BEARER_TYPE_DRB
:
560 /* Shouldn't happen, just return... */
564 /* Hide raw view of bytes */
565 proto_item_set_hidden(raw_tm_ti
);
567 /* Call it (catch exceptions) */
569 call_dissector_only(protocol_handle
, rrc_tvb
, pinfo
, tree
, NULL
);
577 /* Look up / set the frame thought to be the start segment of this RLC PDU. */
578 /* N.B. this algorithm will not be correct in all cases, but is good enough to be useful.. */
579 static uint32_t get_reassembly_start_frame(packet_info
*pinfo
, uint32_t seg_info
,
580 rlc_nr_info
*p_rlc_nr_info
, uint32_t sn
)
582 uint32_t frame_id
= 0;
584 uint32_t key_values
[] = { p_rlc_nr_info
->ueid
,
585 p_rlc_nr_info
->direction
,
586 p_rlc_nr_info
->bearerType
,
587 p_rlc_nr_info
->bearerId
,
592 /* Is this the first segment of SN? */
593 bool first_segment
= (seg_info
& 0x2) == 0;
596 wmem_tree_key_t key
[2];
597 key
[0].length
= 5; /* Ignoring this frame num */
598 key
[0].key
= key_values
;
602 uint32_t *p_frame_id
= NULL
;
604 if (!PINFO_FD_VISITED(pinfo
)) {
605 /* On first pass, maintain reassembly_start_table. */
607 /* Look for existing entry. */
608 p_frame_id
= (uint32_t*)wmem_tree_lookup32_array(reassembly_start_table
, key
);
612 /* Let it start from here */
613 wmem_tree_insert32_array(reassembly_start_table
, key
, GUINT_TO_POINTER(pinfo
->num
));
614 frame_id
= pinfo
->num
;
618 /* Use existing entry (or zero) if not found */
619 frame_id
= GPOINTER_TO_UINT(p_frame_id
);
623 /* Store this result for subsequent passes. Don't store 0 though. */
626 wmem_tree_insert32_array(reassembly_start_table_stored
, key
, GUINT_TO_POINTER(frame_id
));
630 /* For subsequent passes, use stored value */
631 key
[0].length
= 6; /* i.e. include this framenum in key */
632 p_frame_id
= (uint32_t*)wmem_tree_lookup32_array(reassembly_start_table_stored
, key
);
634 /* Use found value */
635 frame_id
= GPOINTER_TO_UINT(p_frame_id
);
642 /* On first pass - if this SN is complete, don't try to add any more fragments to it */
643 static void reassembly_frame_complete(packet_info
*pinfo
,
644 rlc_nr_info
*p_rlc_nr_info
, uint32_t sn
)
646 if (!PINFO_FD_VISITED(pinfo
)) {
647 uint32_t key_values
[] = { p_rlc_nr_info
->ueid
,
648 p_rlc_nr_info
->direction
,
649 p_rlc_nr_info
->bearerType
,
650 p_rlc_nr_info
->bearerId
,
655 wmem_tree_key_t key
[2];
657 key
[0].key
= key_values
;
661 /* Clear entry out */
662 wmem_tree_insert32_array(reassembly_start_table
, key
, GUINT_TO_POINTER(0));
667 /***************************************************/
668 /* Unacknowledged mode PDU */
669 static void dissect_rlc_nr_um(tvbuff_t
*tvb
, packet_info
*pinfo
,
670 proto_tree
*tree
, int offset
,
671 rlc_nr_info
*p_rlc_nr_info
, proto_item
*top_ti
,
672 rlc_3gpp_tap_info
*tap_info
)
674 uint32_t seg_info
, sn
;
677 proto_tree
*um_header_tree
;
678 proto_item
*um_header_ti
;
679 proto_item
*truncated_ti
;
680 proto_item
*reserved_ti
;
681 int start_offset
= offset
;
685 um_ti
= proto_tree_add_string_format(tree
, hf_rlc_nr_um
,
686 tvb
, offset
, 0, "", "UM");
687 proto_item_set_hidden(um_ti
);
689 /* Add UM header subtree */
690 um_header_ti
= proto_tree_add_string_format(tree
, hf_rlc_nr_um_header
,
693 um_header_tree
= proto_item_add_subtree(um_header_ti
,
694 ett_rlc_nr_um_header
);
696 /* Segmentation Info */
697 proto_tree_add_item_ret_uint(um_header_tree
, hf_rlc_nr_um_si
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &seg_info
);
699 /* Have all bytes of SDU, so no SN. */
700 reserved_ti
= proto_tree_add_bits_ret_val(um_header_tree
, hf_rlc_nr_um_reserved
,
701 tvb
, (offset
<<3)+2, 6, &reserved
, ENC_BIG_ENDIAN
);
704 expert_add_info(pinfo
, reserved_ti
, &ei_rlc_nr_reserved_bits_not_zero
);
706 write_pdu_label_and_info(top_ti
, um_header_ti
, pinfo
, " ");
708 /* Add sequence number */
709 if (p_rlc_nr_info
->sequenceNumberLength
== UM_SN_LENGTH_6_BITS
) {
711 proto_tree_add_item_ret_uint(um_header_tree
, hf_rlc_nr_um_sn6
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &sn
);
713 tap_info
->sequenceNumberGiven
= true;
714 } else if (p_rlc_nr_info
->sequenceNumberLength
== UM_SN_LENGTH_12_BITS
) {
715 reserved_ti
= proto_tree_add_bits_ret_val(um_header_tree
, hf_rlc_nr_um_reserved
, tvb
,
716 (offset
<<3)+2, 2, &reserved
, ENC_BIG_ENDIAN
);
718 expert_add_info(pinfo
, reserved_ti
, &ei_rlc_nr_reserved_bits_not_zero
);
721 proto_tree_add_item_ret_uint(um_header_tree
, hf_rlc_nr_um_sn12
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &sn
);
723 tap_info
->sequenceNumberGiven
= true;
725 /* Invalid length of sequence number */
726 proto_tree_add_expert_format(um_header_tree
, pinfo
, &ei_rlc_nr_um_sn
, tvb
, 0, 0,
727 "Invalid sequence number length (%u bits)",
728 p_rlc_nr_info
->sequenceNumberLength
);
732 tap_info
->sequenceNumber
= sn
;
736 proto_tree_add_item_ret_uint(um_header_tree
, hf_rlc_nr_um_so
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &so
);
738 write_pdu_label_and_info(top_ti
, um_header_ti
, pinfo
, " SN=%-6u SO=%-4u", sn
, so
);
740 /* Seg info is 1, so start of SDU - no SO */
741 write_pdu_label_and_info(top_ti
, um_header_ti
, pinfo
, " SN=%-6u ", sn
);
745 proto_item_set_len(um_header_ti
, offset
-start_offset
);
747 if (global_rlc_nr_headers_expected
) {
748 /* There might not be any data, if only headers (plus control data) were logged */
749 bool is_truncated
= (tvb_captured_length_remaining(tvb
, offset
) == 0);
750 truncated_ti
= proto_tree_add_boolean(tree
, hf_rlc_nr_header_only
, tvb
, 0, 0,
753 proto_item_set_generated(truncated_ti
);
754 expert_add_info(pinfo
, truncated_ti
, &ei_rlc_nr_header_only
);
755 show_PDU_in_info(pinfo
, top_ti
, p_rlc_nr_info
->pduLength
- offset
, seg_info
);
758 proto_item_set_hidden(truncated_ti
);
764 /* Handle any reassembly. */
765 tvbuff_t
*next_tvb
= NULL
;
766 if (global_rlc_nr_reassemble_um_pdus
&& seg_info
&& tvb_reported_length_remaining(tvb
, offset
) > 0) {
767 /* Set fragmented flag. */
768 bool save_fragmented
= pinfo
->fragmented
;
769 pinfo
->fragmented
= true;
771 bool more_frags
= seg_info
& 0x01;
772 uint32_t id
= get_reassembly_start_frame(pinfo
, seg_info
, p_rlc_nr_info
, sn
); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
774 fh
= fragment_add(&pdu_reassembly_table
, tvb
, offset
, pinfo
,
776 GUINT_TO_POINTER(id
), /* data */
777 so
, /* frag_offset */
778 tvb_reported_length_remaining(tvb
, offset
), /* frag_data_len */
779 more_frags
/* more_frags */
782 bool update_col_info
= true;
783 next_tvb
= process_reassembled_data(tvb
, offset
, pinfo
, "Reassembled RLC SDU",
784 fh
, &rlc_nr_frag_items
,
785 &update_col_info
, tree
);
786 pinfo
->fragmented
= save_fragmented
;
790 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
791 show_PDU_in_tree(pinfo
, tree
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
),
792 p_rlc_nr_info
, seg_info
, false);
793 show_PDU_in_info(pinfo
, top_ti
, tvb_reported_length_remaining(tvb
, offset
), seg_info
);
795 /* Also add any reassembled PDU */
797 add_new_data_source(pinfo
, next_tvb
, "Reassembled RLC-NR PDU");
798 show_PDU_in_tree(pinfo
, tree
, next_tvb
, 0, tvb_captured_length(next_tvb
),
799 p_rlc_nr_info
, seg_info
, true);
801 /* Note that PDU is now completed (so won't try to add to it) */
802 reassembly_frame_complete(pinfo
, p_rlc_nr_info
, sn
);
804 } else if (!global_rlc_nr_headers_expected
) {
805 /* Report that expected data was missing (unless we know it might happen) */
806 expert_add_info(pinfo
, um_header_ti
, &ei_rlc_nr_um_data_no_data
);
812 /* Dissect an AM STATUS PDU */
813 static void dissect_rlc_nr_am_status_pdu(tvbuff_t
*tvb
,
816 proto_item
*status_ti
,
819 rlc_nr_info
*p_rlc_nr_info
,
820 rlc_3gpp_tap_info
*tap_info
)
822 uint8_t sn_size
, reserved_bits1
, reserved_bits2
;
823 uint32_t cpt
, sn_limit
, nack_count
= 0;
824 uint64_t ack_sn
, nack_sn
;
825 uint64_t e1
, e2
, e3
, reserved
;
826 uint32_t so_start
, so_end
, nack_range
;
827 int bit_offset
= offset
<< 3;
830 /****************************************************************/
831 /* Part of RLC control PDU header */
833 /* Control PDU Type (CPT) */
834 ti
= proto_tree_add_item_ret_uint(tree
, hf_rlc_nr_am_cpt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &cpt
);
836 /* Protest and stop - only know about STATUS PDUs */
837 expert_add_info_format(pinfo
, ti
, &ei_rlc_nr_am_cpt
,
838 "RLC Control frame type %u not handled", cpt
);
842 if (p_rlc_nr_info
->sequenceNumberLength
== AM_SN_LENGTH_12_BITS
) {
847 } else if (p_rlc_nr_info
->sequenceNumberLength
== AM_SN_LENGTH_18_BITS
) {
853 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_nr_am_sn
, tvb
, 0, 0,
854 "Invalid sequence number length (%u bits)",
855 p_rlc_nr_info
->sequenceNumberLength
);
859 /* The Status PDU itself starts 4 bits into the byte */
863 proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_ack_sn
, tvb
,
864 bit_offset
, sn_size
, &ack_sn
, ENC_BIG_ENDIAN
);
865 bit_offset
+= sn_size
;
866 write_pdu_label_and_info(top_ti
, status_ti
, pinfo
, " ACK_SN=%-6u", (uint32_t)ack_sn
);
867 tap_info
->ACKNo
= (uint32_t)ack_sn
;
870 proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_e1
, tvb
,
871 bit_offset
, 1, &e1
, ENC_BIG_ENDIAN
);
875 ti
= proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_reserved
, tvb
, bit_offset
,
876 reserved_bits1
, &reserved
, ENC_BIG_ENDIAN
);
877 bit_offset
+= reserved_bits1
;
879 expert_add_info(pinfo
, ti
, &ei_rlc_nr_reserved_bits_not_zero
);
882 /* Optional, extra fields */
886 /****************************/
887 /* Read NACK_SN, E1, E2, E3 */
890 nack_ti
= proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_nack_sn
, tvb
,
891 bit_offset
, sn_size
, &nack_sn
, ENC_BIG_ENDIAN
);
892 bit_offset
+= sn_size
;
893 write_pdu_label_and_info(top_ti
, NULL
, pinfo
, " NACK_SN=%-6u", (uint32_t)nack_sn
);
895 /* We shouldn't NACK the ACK_SN! */
896 if (nack_sn
== ack_sn
) {
897 expert_add_info_format(pinfo
, nack_ti
, &ei_rlc_nr_am_nack_sn_ack_same
,
898 "Status PDU shouldn't ACK and NACK the same sequence number (%" PRIu64
")",
902 /* NACK should always be 'behind' the ACK */
903 if ((sn_limit
+ ack_sn
- nack_sn
) % sn_limit
> (sn_limit
>>1)) {
904 expert_add_info(pinfo
, nack_ti
, &ei_rlc_nr_am_nack_sn_ahead_ack
);
907 /* Copy single NACK into tap struct, but don't exceed buffer */
908 if (nack_count
< MAX_NACKs
) {
909 tap_info
->NACKs
[nack_count
++] = (uint32_t)nack_sn
;
912 /* Let it get bigger than the array for accurate stats... */
918 proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_e1
, tvb
,
919 bit_offset
, 1, &e1
, ENC_BIG_ENDIAN
);
923 proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_e2
, tvb
,
924 bit_offset
, 1, &e2
, ENC_BIG_ENDIAN
);
927 /* Report as expert info */
929 expert_add_info_format(pinfo
, nack_ti
, &ei_rlc_nr_am_nack_sn_partial
,
930 "Status PDU reports NACK (partial) on %s for UE %u",
931 val_to_str_const(p_rlc_nr_info
->direction
, direction_vals
, "Unknown"),
932 p_rlc_nr_info
->ueid
);
934 expert_add_info_format(pinfo
, nack_ti
, &ei_rlc_nr_am_nack_sn
,
935 "Status PDU reports NACK on %s for UE %u",
936 val_to_str_const(p_rlc_nr_info
->direction
, direction_vals
, "Unknown"),
937 p_rlc_nr_info
->ueid
);
941 proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_e3
, tvb
,
942 bit_offset
, 1, &e3
, ENC_BIG_ENDIAN
);
946 ti
= proto_tree_add_bits_ret_val(tree
, hf_rlc_nr_am_reserved
, tvb
, bit_offset
,
947 reserved_bits2
, &reserved
, ENC_BIG_ENDIAN
);
948 bit_offset
+= reserved_bits2
;
950 expert_add_info(pinfo
, ti
, &ei_rlc_nr_reserved_bits_not_zero
);
954 /* Read SOstart, SOend */
955 proto_tree_add_item_ret_uint(tree
, hf_rlc_nr_am_so_start
, tvb
,
956 bit_offset
>>3, 2, ENC_BIG_ENDIAN
, &so_start
);
959 /* N.B., if E3 is set, this refers to a byte offset within the last PDU of the range.. */
960 proto_tree_add_item_ret_uint(tree
, hf_rlc_nr_am_so_end
, tvb
,
961 bit_offset
>>3, 2, ENC_BIG_ENDIAN
, &so_end
);
965 if (so_end
== 0xffff) {
966 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
967 " (SOstart=%u SOend=<END-OF_SDU>)",
970 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
971 " (SOstart=%u SOend=%u)",
978 proto_item
*nack_range_ti
;
979 nack_range_ti
= proto_tree_add_item_ret_uint(tree
, hf_rlc_nr_am_nack_range
, tvb
,
980 bit_offset
>>3, 1, ENC_BIG_ENDIAN
, &nack_range
);
982 if (nack_range
== 0) {
983 /* It is the number of PDUs not received, so 0 does not make sense */
984 expert_add_info(pinfo
, nack_range_ti
, &ei_rlc_nr_am_nack_range
);
987 proto_item_append_text(nack_range_ti
, " (SNs %" PRIu64
"-%" PRIu64
" missing)",
988 nack_sn
, nack_sn
+nack_range
-1);
990 write_pdu_label_and_info(top_ti
, NULL
, pinfo
," NACK range=%u", nack_range
);
992 /* Copy NACK SNs into tap_info */
993 for (unsigned nack
=0; nack
< nack_range
-1; nack
++) {
994 if (nack_count
+nack
< MAX_NACKs
) {
995 /* Guard against wrapping the SN range */
996 tap_info
->NACKs
[nack_count
+nack
] = (uint32_t)((nack_sn
+nack
+1) % sn_limit
);
999 /* Let it get bigger than the array for accurate stats. Take care not to double-count nack-sn itself. */
1000 nack_count
+= (nack_range
-1);
1004 if (nack_count
> 0) {
1005 proto_item
*count_ti
= proto_tree_add_uint(tree
, hf_rlc_nr_am_nacks
, tvb
, 0, 1, nack_count
);
1006 proto_item_set_generated(count_ti
);
1007 proto_item_append_text(status_ti
, " (%u NACKs)", nack_count
);
1008 tap_info
->noOfNACKs
= nack_count
;
1011 /* Check that we've reached the end of the PDU. If not, show malformed */
1012 offset
= (bit_offset
+7) / 8;
1013 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
1014 expert_add_info_format(pinfo
, status_ti
, &ei_rlc_nr_bytes_after_status_pdu_complete
,
1015 "%cL %u bytes remaining after Status PDU complete",
1016 (p_rlc_nr_info
->direction
== DIRECTION_UPLINK
) ? 'U' : 'D',
1017 tvb_reported_length_remaining(tvb
, offset
));
1020 /* Set selected length of control tree */
1021 proto_item_set_len(status_ti
, offset
);
1025 /***************************************************/
1026 /* Acknowledged mode PDU */
1027 static void dissect_rlc_nr_am(tvbuff_t
*tvb
, packet_info
*pinfo
,
1028 proto_tree
*tree
, int offset
,
1029 rlc_nr_info
*p_rlc_nr_info
, proto_item
*top_ti
,
1030 rlc_3gpp_tap_info
*tap_info _U_
)
1033 uint32_t seg_info
, sn
;
1036 proto_tree
*am_header_tree
;
1037 proto_item
*am_header_ti
;
1038 int start_offset
= offset
;
1039 proto_item
*truncated_ti
;
1040 proto_item
*reserved_ti
;
1043 /* Hidden AM root */
1044 am_ti
= proto_tree_add_string_format(tree
, hf_rlc_nr_am
,
1045 tvb
, offset
, 0, "", "AM");
1046 proto_item_set_hidden(am_ti
);
1048 /* Add AM header subtree */
1049 am_header_ti
= proto_tree_add_string_format(tree
, hf_rlc_nr_am_header
,
1052 am_header_tree
= proto_item_add_subtree(am_header_ti
,
1053 ett_rlc_nr_am_header
);
1055 /* First bit is Data/Control flag */
1056 proto_tree_add_item_ret_boolean(am_header_tree
, hf_rlc_nr_am_data_control
,
1057 tvb
, offset
, 1, ENC_BIG_ENDIAN
, &dc
);
1058 tap_info
->isControlPDU
= !dc
;
1061 /**********************/
1063 write_pdu_label_and_info_literal(top_ti
, NULL
, pinfo
, " [CONTROL]");
1065 /* Control PDUs are a completely separate format */
1066 dissect_rlc_nr_am_status_pdu(tvb
, pinfo
, am_header_tree
, am_header_ti
,
1068 p_rlc_nr_info
, tap_info
);
1072 /**********************/
1074 write_pdu_label_and_info_literal(top_ti
, NULL
, pinfo
, " [DATA]");
1077 proto_tree_add_item_ret_boolean(am_header_tree
, hf_rlc_nr_am_p
, tvb
,
1078 offset
, 1, ENC_BIG_ENDIAN
, &polling
);
1080 write_pdu_label_and_info_literal(top_ti
, NULL
, pinfo
, (polling
) ? " (P) " : " ");
1082 proto_item_append_text(am_header_ti
, " (P) ");
1085 /* Segmentation Info */
1086 proto_tree_add_item_ret_uint(am_header_tree
, hf_rlc_nr_am_si
, tvb
,
1087 offset
, 1, ENC_BIG_ENDIAN
, &seg_info
);
1089 /* Sequence Number */
1090 if (p_rlc_nr_info
->sequenceNumberLength
== AM_SN_LENGTH_12_BITS
) {
1091 proto_tree_add_item_ret_uint(am_header_tree
, hf_rlc_nr_am_sn12
, tvb
,
1092 offset
, 2, ENC_BIG_ENDIAN
, &sn
);
1094 } else if (p_rlc_nr_info
->sequenceNumberLength
== AM_SN_LENGTH_18_BITS
) {
1095 reserved_ti
= proto_tree_add_bits_ret_val(am_header_tree
, hf_rlc_nr_am_reserved
, tvb
,
1096 (offset
<<3)+4, 2, &reserved
, ENC_BIG_ENDIAN
);
1098 expert_add_info(pinfo
, reserved_ti
, &ei_rlc_nr_reserved_bits_not_zero
);
1100 proto_tree_add_item_ret_uint(am_header_tree
, hf_rlc_nr_am_sn18
, tvb
,
1101 offset
, 3, ENC_BIG_ENDIAN
, &sn
);
1104 /* Invalid length of sequence number */
1105 proto_tree_add_expert_format(am_header_tree
, pinfo
, &ei_rlc_nr_am_sn
, tvb
, 0, 0,
1106 "Invalid sequence number length (%u bits)",
1107 p_rlc_nr_info
->sequenceNumberLength
);
1111 tap_info
->sequenceNumberGiven
= true;
1112 tap_info
->sequenceNumber
= sn
;
1114 /* Segment Offset */
1115 if (seg_info
>= 2) {
1116 proto_tree_add_item_ret_uint(am_header_tree
, hf_rlc_nr_am_so
, tvb
,
1117 offset
, 2, ENC_BIG_ENDIAN
, &so
);
1119 write_pdu_label_and_info(top_ti
, am_header_ti
, pinfo
, "SN=%-6u SO=%-4u",sn
, so
);
1121 write_pdu_label_and_info(top_ti
, am_header_ti
, pinfo
, "SN=%-6u ", sn
);
1124 /* Header is now complete */
1125 proto_item_set_len(am_header_ti
, offset
-start_offset
);
1127 /* There might not be any data, if only headers (plus control data) were logged */
1128 if (global_rlc_nr_headers_expected
) {
1129 bool is_truncated
= (tvb_captured_length_remaining(tvb
, offset
) == 0);
1130 truncated_ti
= proto_tree_add_boolean(tree
, hf_rlc_nr_header_only
, tvb
, 0, 0,
1133 proto_item_set_generated(truncated_ti
);
1134 expert_add_info(pinfo
, truncated_ti
, &ei_rlc_nr_header_only
);
1135 show_PDU_in_info(pinfo
, top_ti
, p_rlc_nr_info
->pduLength
- offset
, seg_info
);
1138 proto_item_set_hidden(truncated_ti
);
1144 /* Handle any reassembly. */
1145 tvbuff_t
*next_tvb
= NULL
;
1146 if (global_rlc_nr_reassemble_am_pdus
&& seg_info
&& tvb_reported_length_remaining(tvb
, offset
) > 0) {
1147 /* Set fragmented flag. */
1148 bool save_fragmented
= pinfo
->fragmented
;
1149 pinfo
->fragmented
= true;
1151 bool more_frags
= seg_info
& 0x01;
1152 uint32_t id
= get_reassembly_start_frame(pinfo
, seg_info
, p_rlc_nr_info
, sn
);
1154 fh
= fragment_add(&pdu_reassembly_table
, tvb
, offset
, pinfo
,
1156 GUINT_TO_POINTER(id
), /* data */
1157 so
, /* frag_offset */
1158 tvb_reported_length_remaining(tvb
, offset
), /* frag_data_len */
1159 more_frags
/* more_frags */
1162 bool update_col_info
= true;
1163 next_tvb
= process_reassembled_data(tvb
, offset
, pinfo
, "Reassembled RLC SDU",
1164 fh
, &rlc_nr_frag_items
,
1165 &update_col_info
, tree
);
1166 pinfo
->fragmented
= save_fragmented
;
1171 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
1172 show_PDU_in_tree(pinfo
, tree
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
),
1173 p_rlc_nr_info
, seg_info
, false);
1174 show_PDU_in_info(pinfo
, top_ti
, tvb_reported_length_remaining(tvb
, offset
), seg_info
);
1176 /* Also add any reassembled PDU */
1178 add_new_data_source(pinfo
, next_tvb
, "Reassembled RLC-NR PDU");
1179 show_PDU_in_tree(pinfo
, tree
, next_tvb
, 0, tvb_captured_length(next_tvb
),
1180 p_rlc_nr_info
, seg_info
, true);
1182 } else if (!global_rlc_nr_headers_expected
) {
1183 /* Report that expected data was missing (unless we know it might happen) */
1184 expert_add_info(pinfo
, am_header_ti
, &ei_rlc_nr_am_data_no_data
);
1189 /* Heuristic dissector looks for supported framing protocol (see header file for details) */
1190 static bool dissect_rlc_nr_heur(tvbuff_t
*tvb
, packet_info
*pinfo
,
1191 proto_tree
*tree
, void *data _U_
)
1194 rlc_nr_info
*p_rlc_nr_info
;
1198 /* Do this again on re-dissection to re-discover offset of actual PDU */
1200 /* Needs to be at least as long as:
1201 - the signature string
1202 - fixed header bytes
1204 - at least one byte of RLC PDU payload */
1205 if (tvb_captured_length_remaining(tvb
, offset
) < (int)(strlen(RLC_NR_START_STRING
)+2+2)) {
1209 /* OK, compare with signature string */
1210 if (tvb_strneql(tvb
, offset
, RLC_NR_START_STRING
, (int)strlen(RLC_NR_START_STRING
)) != 0) {
1213 offset
+= (int)strlen(RLC_NR_START_STRING
);
1216 /* If redissecting, use previous info struct (if available) */
1217 p_rlc_nr_info
= (rlc_nr_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_rlc_nr
, 0);
1218 if (p_rlc_nr_info
== NULL
) {
1219 /* Allocate new info struct for this frame */
1220 p_rlc_nr_info
= wmem_new0(wmem_file_scope(), struct rlc_nr_info
);
1222 /* Read fixed fields */
1223 p_rlc_nr_info
->rlcMode
= tvb_get_uint8(tvb
, offset
++);
1224 p_rlc_nr_info
->sequenceNumberLength
= tvb_get_uint8(tvb
, offset
++);
1226 /* Read optional fields */
1228 /* Process next tag */
1229 tag
= tvb_get_uint8(tvb
, offset
++);
1231 case RLC_NR_DIRECTION_TAG
:
1232 p_rlc_nr_info
->direction
= tvb_get_uint8(tvb
, offset
);
1235 case RLC_NR_UEID_TAG
:
1236 p_rlc_nr_info
->ueid
= tvb_get_ntohs(tvb
, offset
);
1239 case RLC_NR_BEARER_TYPE_TAG
:
1240 p_rlc_nr_info
->bearerType
= tvb_get_uint8(tvb
, offset
);
1243 case RLC_NR_BEARER_ID_TAG
:
1244 p_rlc_nr_info
->bearerId
= tvb_get_uint8(tvb
, offset
);
1247 case RLC_NR_PAYLOAD_TAG
:
1248 /* Have reached data, so set payload length and get out of loop */
1249 p_rlc_nr_info
->pduLength
= tvb_reported_length_remaining(tvb
, offset
);
1252 /* It must be a recognised tag */
1255 proto_tree
*subtree
;
1257 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC-NR");
1258 col_clear(pinfo
->cinfo
, COL_INFO
);
1259 ti
= proto_tree_add_item(tree
, proto_rlc_nr
, tvb
, offset
, tvb_reported_length(tvb
), ENC_NA
);
1260 subtree
= proto_item_add_subtree(ti
, ett_rlc_nr
);
1261 proto_tree_add_expert(subtree
, pinfo
, &ei_rlc_nr_unknown_udp_framing_tag
,
1264 wmem_free(wmem_file_scope(), p_rlc_nr_info
);
1267 } while (tag
!= RLC_NR_PAYLOAD_TAG
);
1269 /* Store info in packet */
1270 p_add_proto_data(wmem_file_scope(), pinfo
, proto_rlc_nr
, 0, p_rlc_nr_info
);
1272 offset
= tvb_reported_length(tvb
) - p_rlc_nr_info
->pduLength
;
1275 /**************************************/
1276 /* OK, now dissect as RLC NR */
1278 /* Create tvb that starts at actual RLC PDU */
1279 rlc_tvb
= tvb_new_subset_remaining(tvb
, offset
);
1280 dissect_rlc_nr_common(rlc_tvb
, pinfo
, tree
, true /* udp framing */);
1284 /*****************************/
1285 /* Main dissection function. */
1286 /*****************************/
1288 static int dissect_rlc_nr(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
1290 dissect_rlc_nr_common(tvb
, pinfo
, tree
, false /* not udp framing */);
1291 return tvb_captured_length(tvb
);
1294 static void dissect_rlc_nr_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, bool is_udp_framing
)
1296 proto_tree
*rlc_nr_tree
;
1297 proto_tree
*context_tree
;
1299 proto_item
*context_ti
;
1301 proto_item
*mode_ti
;
1303 struct rlc_nr_info
*p_rlc_nr_info
;
1305 /* Allocate and Zero tap struct */
1306 rlc_3gpp_tap_info
*tap_info
= wmem_new0(pinfo
->pool
, rlc_3gpp_tap_info
);
1307 tap_info
->rat
= RLC_RAT_NR
;
1309 /* Set protocol name */
1310 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC-NR");
1312 /* Create protocol tree. */
1313 top_ti
= proto_tree_add_item(tree
, proto_rlc_nr
, tvb
, offset
, -1, ENC_NA
);
1314 rlc_nr_tree
= proto_item_add_subtree(top_ti
, ett_rlc_nr
);
1317 /* Look for packet info! */
1318 p_rlc_nr_info
= (rlc_nr_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_rlc_nr
, 0);
1320 /* Can't dissect anything without it... */
1321 if (p_rlc_nr_info
== NULL
) {
1322 proto_tree_add_expert(rlc_nr_tree
, pinfo
, &ei_rlc_nr_no_per_frame_info
, tvb
, offset
, -1);
1326 /* Clear info column when using UDP framing */
1327 if (is_udp_framing
) {
1328 col_clear(pinfo
->cinfo
, COL_INFO
);
1331 /*****************************************/
1332 /* Show context information */
1334 /* Create context root */
1335 context_ti
= proto_tree_add_string_format(rlc_nr_tree
, hf_rlc_nr_context
,
1336 tvb
, offset
, 0, "", "Context");
1337 context_tree
= proto_item_add_subtree(context_ti
, ett_rlc_nr_context
);
1338 proto_item_set_generated(context_ti
);
1340 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_direction
,
1341 tvb
, 0, 0, p_rlc_nr_info
->direction
);
1342 proto_item_set_generated(ti
);
1344 mode_ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_mode
,
1345 tvb
, 0, 0, p_rlc_nr_info
->rlcMode
);
1346 proto_item_set_generated(mode_ti
);
1348 if (p_rlc_nr_info
->ueid
!= 0) {
1349 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_ueid
,
1350 tvb
, 0, 0, p_rlc_nr_info
->ueid
);
1351 proto_item_set_generated(ti
);
1354 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_bearer_type
,
1355 tvb
, 0, 0, p_rlc_nr_info
->bearerType
);
1356 proto_item_set_generated(ti
);
1358 if ((p_rlc_nr_info
->bearerType
== BEARER_TYPE_SRB
) ||
1359 (p_rlc_nr_info
->bearerType
== BEARER_TYPE_DRB
)) {
1360 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_bearer_id
,
1361 tvb
, 0, 0, p_rlc_nr_info
->bearerId
);
1362 proto_item_set_generated(ti
);
1365 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_pdu_length
,
1366 tvb
, 0, 0, p_rlc_nr_info
->pduLength
);
1367 proto_item_set_generated(ti
);
1369 if (p_rlc_nr_info
->rlcMode
!= RLC_TM_MODE
) {
1370 ti
= proto_tree_add_uint(context_tree
, hf_rlc_nr_context_sn_length
,
1371 tvb
, 0, 0, p_rlc_nr_info
->sequenceNumberLength
);
1372 proto_item_set_generated(ti
);
1375 /* Append highlights to top-level item */
1376 if (p_rlc_nr_info
->ueid
!= 0) {
1377 proto_item_append_text(top_ti
, " UEId=%u", p_rlc_nr_info
->ueid
);
1378 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "UEId=%-4u ", p_rlc_nr_info
->ueid
);
1381 /* Append context highlights to info column */
1382 write_pdu_label_and_info(top_ti
, NULL
, pinfo
,
1384 (p_rlc_nr_info
->direction
== 0) ? "UL" : "DL",
1385 val_to_str_const(p_rlc_nr_info
->rlcMode
, rlc_mode_short_vals
, "Unknown"));
1387 if (p_rlc_nr_info
->bearerId
== 0) {
1388 write_pdu_label_and_info(top_ti
, NULL
, pinfo
, "%s ",
1389 val_to_str_const(p_rlc_nr_info
->bearerType
, rlc_bearer_type_vals
, "Unknown"));
1391 write_pdu_label_and_info(top_ti
, NULL
, pinfo
, "%s:%-2u",
1392 val_to_str_const(p_rlc_nr_info
->bearerType
, rlc_bearer_type_vals
, "Unknown"),
1393 p_rlc_nr_info
->bearerId
);
1396 /* Set context-info parts of tap struct */
1397 tap_info
->rlcMode
= p_rlc_nr_info
->rlcMode
;
1398 tap_info
->direction
= p_rlc_nr_info
->direction
;
1399 /* TODO: p_rlc_nr_info does not have priority. */
1400 tap_info
->ueid
= p_rlc_nr_info
->ueid
;
1401 tap_info
->channelType
= p_rlc_nr_info
->bearerType
;
1402 tap_info
->channelId
= p_rlc_nr_info
->bearerId
;
1403 tap_info
->pduLength
= p_rlc_nr_info
->pduLength
;
1404 tap_info
->sequenceNumberLength
= p_rlc_nr_info
->sequenceNumberLength
;
1405 tap_info
->loggedInMACFrame
= (p_get_proto_data(wmem_file_scope(), pinfo
, proto_mac_nr
, 0) != NULL
);
1407 tap_info
->rlc_time
= pinfo
->abs_ts
;
1410 /* Dissect the RLC PDU itself. Format depends upon mode... */
1411 switch (p_rlc_nr_info
->rlcMode
) {
1414 dissect_rlc_nr_tm(tvb
, pinfo
, rlc_nr_tree
, offset
, p_rlc_nr_info
, top_ti
);
1418 dissect_rlc_nr_um(tvb
, pinfo
, rlc_nr_tree
, offset
, p_rlc_nr_info
, top_ti
, tap_info
);
1422 dissect_rlc_nr_am(tvb
, pinfo
, rlc_nr_tree
, offset
, p_rlc_nr_info
, top_ti
, tap_info
);
1426 /* Error - unrecognised mode */
1427 expert_add_info_format(pinfo
, mode_ti
, &ei_rlc_nr_context_mode
,
1428 "Unrecognised RLC Mode set (%u)", p_rlc_nr_info
->rlcMode
);
1432 /* Queue tap info */
1433 tap_queue_packet(rlc_nr_tap
, pinfo
, tap_info
);
1437 /* Configure DRB PDCP channel properties. */
1438 void set_rlc_nr_drb_pdcp_mapping(packet_info
*pinfo
,
1439 nr_drb_rlc_pdcp_mapping_t
*drb_mapping
)
1441 wmem_tree_key_t key
[2];
1443 pdcp_bearer_parameters
*params
;
1445 if (PINFO_FD_VISITED(pinfo
)) {
1449 id
= (drb_mapping
->drbid
<< 16) | drb_mapping
->ueid
;
1455 /* Look up entry for this UEId/drbid */
1456 params
= (pdcp_bearer_parameters
*)wmem_tree_lookup32_array_le(ue_parameters_tree
, key
);
1457 if (params
&& (params
->id
!= id
)) {
1460 if (params
== NULL
) {
1461 /* Not found so create new entry */
1462 params
= (pdcp_bearer_parameters
*)wmem_new(wmem_file_scope(), pdcp_bearer_parameters
);
1464 wmem_tree_insert32_array(ue_parameters_tree
, key
, (void *)params
);
1467 /* Populate params */
1468 params
->pdcp_sn_bits_ul
= drb_mapping
->pdcpUlSnLength
;
1469 params
->pdcp_sn_bits_dl
= drb_mapping
->pdcpDlSnLength
;
1470 params
->pdcp_sdap_ul
= drb_mapping
->pdcpUlSdap
;
1471 params
->pdcp_sdap_dl
= drb_mapping
->pdcpDlSdap
;
1472 params
->pdcp_integrity
= drb_mapping
->pdcpIntegrityProtection
;
1473 params
->pdcp_ciphering_disabled
= drb_mapping
->pdcpCipheringDisabled
;
1476 pdcp_bearer_parameters
* get_rlc_nr_drb_pdcp_mapping(uint16_t ue_id
, uint8_t drb_id
)
1478 wmem_tree_key_t key
[2];
1480 pdcp_bearer_parameters
*params
;
1482 id
= (drb_id
<< 16) | ue_id
;
1488 /* Look up configured params for this PDCP DRB. */
1489 params
= (pdcp_bearer_parameters
*)wmem_tree_lookup32_array_le(ue_parameters_tree
, key
);
1490 if (params
&& (params
->id
!= id
)) {
1498 void proto_register_rlc_nr(void)
1500 static hf_register_info hf
[] =
1502 /**********************************/
1503 /* Items for decoding context */
1504 { &hf_rlc_nr_context
,
1506 "rlc-nr.context", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1510 { &hf_rlc_nr_context_mode
,
1512 "rlc-nr.mode", FT_UINT8
, BASE_DEC
, VALS(rlc_mode_vals
), 0x0,
1516 { &hf_rlc_nr_context_direction
,
1518 "rlc-nr.direction", FT_UINT8
, BASE_DEC
, VALS(direction_vals
), 0x0,
1519 "Direction of message", HFILL
1522 { &hf_rlc_nr_context_ueid
,
1524 "rlc-nr.ueid", FT_UINT16
, BASE_DEC
, 0, 0x0,
1525 "User Equipment Identifier associated with message", HFILL
1528 { &hf_rlc_nr_context_bearer_type
,
1530 "rlc-nr.bearer-type", FT_UINT16
, BASE_DEC
, VALS(rlc_bearer_type_vals
), 0x0,
1531 "Bearer Type associated with message", HFILL
1534 { &hf_rlc_nr_context_bearer_id
,
1536 "rlc-nr.bearer-id", FT_UINT16
, BASE_DEC
, 0, 0x0,
1537 "Bearer ID associated with message", HFILL
1540 { &hf_rlc_nr_context_pdu_length
,
1542 "rlc-nr.pdu-length", FT_UINT16
, BASE_DEC
, 0, 0x0,
1543 "Length of PDU (in bytes)", HFILL
1546 { &hf_rlc_nr_context_sn_length
,
1547 { "Sequence Number length",
1548 "rlc-nr.seqnum-length", FT_UINT8
, BASE_DEC
, 0, 0x0,
1549 "Length of sequence number in bits", HFILL
1553 /* Transparent mode fields */
1556 "rlc-nr.tm", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1557 "Transparent Mode", HFILL
1560 { &hf_rlc_nr_tm_data
,
1562 "rlc-nr.tm.data", FT_BYTES
, BASE_NONE
, 0, 0x0,
1563 "Transparent Mode Data", HFILL
1567 /* Unacknowledged mode fields */
1570 "rlc-nr.um", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1571 "Unacknowledged Mode", HFILL
1574 { &hf_rlc_nr_um_header
,
1576 "rlc-nr.um.header", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1577 "Unacknowledged Mode Header", HFILL
1581 { "Segmentation Info",
1582 "rlc-nr.um.si", FT_UINT8
, BASE_HEX
, VALS(seg_info_vals
), 0xc0,
1586 { &hf_rlc_nr_um_reserved
,
1588 "rlc-nr.um.reserved", FT_UINT8
, BASE_HEX
, 0, 0x0,
1592 { &hf_rlc_nr_um_sn6
,
1593 { "Sequence Number",
1594 "rlc-nr.um.sn", FT_UINT8
, BASE_DEC
, 0, 0x3f,
1598 { &hf_rlc_nr_um_sn12
,
1599 { "Sequence Number",
1600 "rlc-nr.um.sn", FT_UINT16
, BASE_DEC
, 0, 0x0fff,
1606 "rlc-nr.um.so", FT_UINT16
, BASE_DEC
, 0, 0x0,
1610 { &hf_rlc_nr_um_data
,
1612 "rlc-nr.um.data", FT_BYTES
, BASE_NONE
, 0, 0x0,
1613 "Unacknowledged Mode Data", HFILL
1617 /* Acknowledged mode fields */
1620 "rlc-nr.am", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1621 "Acknowledged Mode", HFILL
1624 { &hf_rlc_nr_am_header
,
1626 "rlc-nr.am.header", FT_STRING
, BASE_NONE
, NULL
, 0x0,
1627 "Acknowledged Mode Header", HFILL
1630 { &hf_rlc_nr_am_data_control
,
1632 "rlc-nr.am.dc", FT_BOOLEAN
, 8, TFS(&tfs_data_pdu_control_pdu
), 0x80,
1638 "rlc-nr.am.p", FT_BOOLEAN
, 8, TFS(&polling_bit_vals
), 0x40,
1643 { "Segmentation Info",
1644 "rlc-nr.am.si", FT_UINT8
, BASE_HEX
, VALS(seg_info_vals
), 0x30,
1648 { &hf_rlc_nr_am_sn12
,
1649 { "Sequence Number",
1650 "rlc-nr.am.sn", FT_UINT16
, BASE_DEC
, 0, 0x0fff,
1654 { &hf_rlc_nr_am_sn18
,
1655 { "Sequence Number",
1656 "rlc-nr.am.sn", FT_UINT24
, BASE_DEC
, 0, 0x03ffff,
1660 { &hf_rlc_nr_am_reserved
,
1662 "rlc-nr.am.reserved", FT_UINT8
, BASE_HEX
, 0, 0x0,
1668 "rlc-nr.am.so", FT_UINT16
, BASE_DEC
, 0, 0x0,
1672 { &hf_rlc_nr_am_data
,
1674 "rlc-nr.am.data", FT_BYTES
, BASE_NONE
, 0, 0x0,
1675 "Acknowledged Mode Data", HFILL
1678 { &hf_rlc_nr_am_cpt
,
1679 { "Control PDU Type",
1680 "rlc-nr.am.cpt", FT_UINT8
, BASE_HEX
, VALS(control_pdu_type_vals
), 0x70,
1681 "AM Control PDU Type", HFILL
1684 { &hf_rlc_nr_am_ack_sn
,
1685 { "ACK Sequence Number",
1686 "rlc-nr.am.ack-sn", FT_UINT24
, BASE_DEC
, 0, 0x0,
1687 "Sequence Number we expect to receive next", HFILL
1691 { "Extension bit 1",
1692 "rlc-nr.am.e1", FT_BOOLEAN
, BASE_NONE
, TFS(&am_e1_vals
), 0x0,
1697 { "Extension bit 2",
1698 "rlc-nr.am.e2", FT_BOOLEAN
, BASE_NONE
, TFS(&am_e2_vals
), 0x0,
1703 { "Extension bit 3",
1704 "rlc-nr.am.e3", FT_BOOLEAN
, BASE_NONE
, TFS(&am_e3_vals
), 0x0,
1708 { &hf_rlc_nr_am_nacks
,
1709 { "Number of NACKs",
1710 "rlc-nr.am.nacks", FT_UINT32
, BASE_DEC
, 0, 0x0,
1711 "Number of NACKs in this status PDU", HFILL
1714 { &hf_rlc_nr_am_nack_sn
,
1715 { "NACK Sequence Number",
1716 "rlc-nr.am.nack-sn", FT_UINT24
, BASE_DEC
, 0, 0x0,
1717 "Negative Acknowledgement Sequence Number", HFILL
1720 { &hf_rlc_nr_am_so_start
,
1722 "rlc-nr.am.so-start", FT_UINT16
, BASE_DEC
, 0, 0x0,
1723 "Segment Offset Start byte index", HFILL
1726 { &hf_rlc_nr_am_so_end
,
1728 "rlc-nr.am.so-end", FT_UINT16
, BASE_DEC
, 0, 0x0,
1729 "Segment Offset End byte index", HFILL
1732 { &hf_rlc_nr_am_nack_range
,
1734 "rlc-nr.am.nack-range", FT_UINT16
, BASE_DEC
, 0, 0x0,
1735 "Number of consecutively lost RLC SDUs starting from and including NACK_SN", HFILL
1739 { &hf_rlc_nr_header_only
,
1740 { "RLC PDU Header only",
1741 "rlc-nr.header-only", FT_BOOLEAN
, BASE_NONE
, TFS(&header_only_vals
), 0x0,
1746 { &hf_rlc_nr_fragment
,
1747 { "RLC-NR fragment",
1748 "rlc-nr.fragment", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1751 { &hf_rlc_nr_fragments
,
1752 { "RLC-NR fragments",
1753 "rlc-nr.fragments", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1756 { &hf_rlc_nr_fragment_overlap
,
1757 { "Fragment overlap",
1758 "rlc-nr.fragment.overlap", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1759 "Fragment overlaps with other fragments", HFILL
}
1761 { &hf_rlc_nr_fragment_overlap_conflict
,
1762 { "Conflicting data in fragment overlap",
1763 "rlc-nr.fragment.overlap.conflict",
1764 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1765 "Overlapping fragments contained conflicting data", HFILL
}
1767 { &hf_rlc_nr_fragment_multiple_tails
,
1768 { "Multiple tail fragments found",
1769 "rlc-nr.fragment.multipletails",
1770 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1771 "Several tails were found when defragmenting the packet", HFILL
}
1773 { &hf_rlc_nr_fragment_too_long_fragment
,
1774 { "Fragment too long",
1775 "rlc-nr.fragment.toolongfragment",
1776 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1777 "Fragment contained data past end of packet", HFILL
}
1779 { &hf_rlc_nr_fragment_error
,
1780 { "Defragmentation error",
1781 "rlc-nr.fragment.error",
1782 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1783 "Defragmentation error due to illegal fragments", HFILL
}
1785 { &hf_rlc_nr_fragment_count
,
1787 "rlc-nr.fragment.count",
1788 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1791 { &hf_rlc_nr_reassembled_in
,
1792 { "Reassembled RLC-NR in frame",
1793 "rlc-nr.reassembled_in",
1794 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1795 "This RLC-NR packet is reassembled in this frame", HFILL
}
1797 { &hf_rlc_nr_reassembled_length
,
1798 { "Reassembled RLC-NR length",
1799 "rlc-nr.reassembled.length",
1800 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1801 "The total length of the reassembled payload", HFILL
}
1803 { &hf_rlc_nr_reassembled_data
,
1804 { "Reassembled payload",
1805 "rlc-nr.reassembled.data",
1806 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1807 "The reassembled payload", HFILL
}
1814 &ett_rlc_nr_context
,
1815 &ett_rlc_nr_um_header
,
1816 &ett_rlc_nr_am_header
,
1817 &ett_rlc_nr_fragment
,
1818 &ett_rlc_nr_fragments
1821 static ei_register_info ei
[] = {
1822 { &ei_rlc_nr_reserved_bits_not_zero
, { "rlc-nr.reserved-bits-not-zero", PI_MALFORMED
, PI_ERROR
, "Reserved bits not zero", EXPFILL
}},
1823 { &ei_rlc_nr_um_sn
, { "rlc-nr.um.sn.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid UM sequence number length", EXPFILL
}},
1824 { &ei_rlc_nr_am_sn
, { "rlc-nr.am.sn.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid AM sequence number length", EXPFILL
}},
1825 { &ei_rlc_nr_header_only
, { "rlc-nr.header-only.expert", PI_SEQUENCE
, PI_NOTE
, "RLC PDU SDUs have been omitted", EXPFILL
}},
1826 { &ei_rlc_nr_am_cpt
, { "rlc-nr.am.cpt.invalid", PI_MALFORMED
, PI_ERROR
, "RLC Control frame type not handled", EXPFILL
}},
1827 { &ei_rlc_nr_am_nack_sn_ack_same
, { "rlc-nr.am.nack-sn.ack-same", PI_MALFORMED
, PI_ERROR
, "Status PDU shouldn't ACK and NACK the same sequence number", EXPFILL
}},
1828 { &ei_rlc_nr_am_nack_range
, { "rlc-nr.am.nack-sn.nack-range", PI_MALFORMED
, PI_ERROR
, "Status PDU should not contain a NACK range with value 0", EXPFILL
}},
1829 { &ei_rlc_nr_am_nack_sn_ahead_ack
, { "rlc-nr.am.nack-sn.ahead-ack", PI_MALFORMED
, PI_ERROR
, "NACK must not be ahead of ACK in status PDU", EXPFILL
}},
1830 { &ei_rlc_nr_am_nack_sn_partial
, { "rlc-nr.am.nack-sn.partial", PI_SEQUENCE
, PI_WARN
, "Status PDU reports NACK (partial)", EXPFILL
}},
1831 { &ei_rlc_nr_am_nack_sn
, { "rlc-nr.am.nack-sn.expert", PI_SEQUENCE
, PI_WARN
, "Status PDU reports NACK", EXPFILL
}},
1832 { &ei_rlc_nr_bytes_after_status_pdu_complete
, { "rlc-nr.bytes-after-status-pdu-complete", PI_MALFORMED
, PI_ERROR
, "bytes remaining after Status PDU complete", EXPFILL
}},
1833 { &ei_rlc_nr_um_data_no_data
, { "rlc-nr.um-data.no-data", PI_MALFORMED
, PI_ERROR
, "UM data PDU doesn't contain any data", EXPFILL
}},
1834 { &ei_rlc_nr_am_data_no_data
, { "rlc-nr.am-data.no-data", PI_MALFORMED
, PI_ERROR
, "AM data PDU doesn't contain any data", EXPFILL
}},
1835 { &ei_rlc_nr_context_mode
, { "rlc-nr.mode.invalid", PI_MALFORMED
, PI_ERROR
, "Unrecognised RLC Mode set", EXPFILL
}},
1836 { &ei_rlc_nr_no_per_frame_info
, { "rlc-nr.no-per-frame-info", PI_UNDECODED
, PI_ERROR
, "Can't dissect NR RLC frame because no per-frame info was attached!", EXPFILL
}},
1837 { &ei_rlc_nr_unknown_udp_framing_tag
, { "rlc-nr.unknown-udp-framing-tag", PI_UNDECODED
, PI_WARN
, "Unknown UDP framing tag, aborting dissection", EXPFILL
}}
1840 module_t
*rlc_nr_module
;
1841 expert_module_t
* expert_rlc_nr
;
1843 /* Register protocol. */
1844 proto_rlc_nr
= proto_register_protocol("RLC-NR", "RLC-NR", "rlc-nr");
1845 proto_register_field_array(proto_rlc_nr
, hf
, array_length(hf
));
1846 proto_register_subtree_array(ett
, array_length(ett
));
1847 expert_rlc_nr
= expert_register_protocol(proto_rlc_nr
);
1848 expert_register_field_array(expert_rlc_nr
, ei
, array_length(ei
));
1850 /* Allow other dissectors to find this one by name. */
1851 register_dissector("rlc-nr", dissect_rlc_nr
, proto_rlc_nr
);
1853 /* Register the tap name */
1854 rlc_nr_tap
= register_tap("rlc-3gpp");
1857 rlc_nr_module
= prefs_register_protocol(proto_rlc_nr
, NULL
);
1859 prefs_register_bool_preference(rlc_nr_module
, "call_pdcp_for_srb",
1860 "Call PDCP dissector for SRB PDUs",
1861 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
1862 "only be called for complete PDUs (i.e. not segmented over RLC)",
1863 &global_rlc_nr_call_pdcp_for_srb
);
1865 prefs_register_enum_preference(rlc_nr_module
, "call_pdcp_for_ul_drb",
1866 "Call PDCP dissector for UL DRB PDUs",
1867 "Call PDCP dissector for UL user-plane PDUs. Note that without reassembly, it can"
1868 "only be called for complete PDUs (i.e. not segmented over RLC)",
1869 &global_rlc_nr_call_pdcp_for_ul_drb
, pdcp_drb_col_vals
, false);
1871 prefs_register_enum_preference(rlc_nr_module
, "call_pdcp_for_dl_drb",
1872 "Call PDCP dissector for DL DRB PDUs",
1873 "Call PDCP dissector for DL user-plane PDUs. Note that without reassembly, it can"
1874 "only be called for complete PDUs (i.e. not segmented over RLC)",
1875 &global_rlc_nr_call_pdcp_for_dl_drb
, pdcp_drb_col_vals
, false);
1877 prefs_register_bool_preference(rlc_nr_module
, "call_rrc_for_ccch",
1878 "Call RRC dissector for CCCH PDUs",
1879 "Call RRC dissector for CCCH PDUs",
1880 &global_rlc_nr_call_rrc_for_ccch
);
1882 prefs_register_bool_preference(rlc_nr_module
, "header_only_mode",
1883 "May see RLC headers only",
1884 "When enabled, if data is not present, don't report as an error, but instead "
1885 "add expert info to indicate that headers were omitted",
1886 &global_rlc_nr_headers_expected
);
1888 prefs_register_bool_preference(rlc_nr_module
, "reassemble_am_frames",
1889 "Try to reassemble AM frames",
1890 "N.B. This should be considered experimental/incomplete, in that it doesn't try to discard reassembled state "
1891 "when reestablishment happens, or in certain packet-loss cases",
1892 &global_rlc_nr_reassemble_am_pdus
);
1894 prefs_register_bool_preference(rlc_nr_module
, "reassemble_um_frames",
1895 "Try to reassemble UM frames",
1896 "N.B. This should be considered experimental/incomplete, in that it doesn't try to discard reassembled state "
1897 "when reestablishment happens, or in certain packet-loss cases",
1898 &global_rlc_nr_reassemble_um_pdus
);
1900 ue_parameters_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1901 reassembly_start_table
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1902 reassembly_start_table_stored
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1904 /* Register reassembly table. */
1905 reassembly_table_register(&pdu_reassembly_table
, &pdu_reassembly_table_functions
);
1908 void proto_reg_handoff_rlc_nr(void)
1910 /* Add as a heuristic UDP dissector */
1911 heur_dissector_add("udp", dissect_rlc_nr_heur
, "RLC-NR over UDP", "rlc_nr_udp", proto_rlc_nr
, HEURISTIC_DISABLE
);
1913 pdcp_nr_handle
= find_dissector("pdcp-nr");
1914 nr_rrc_bcch_bch
= find_dissector_add_dependency("nr-rrc.bcch.bch", proto_rlc_nr
);
1915 nr_rrc_bcch_dl_sch
= find_dissector_add_dependency("nr-rrc.bcch.dl.sch", proto_rlc_nr
);
1916 nr_rrc_pcch
= find_dissector_add_dependency("nr-rrc.pcch", proto_pdcp_nr
);
1917 nr_rrc_ul_ccch
= find_dissector_add_dependency("nr-rrc.ul.ccch", proto_rlc_nr
);
1918 nr_rrc_ul_ccch1
= find_dissector_add_dependency("nr-rrc.ul.ccch1", proto_rlc_nr
);
1919 nr_rrc_dl_ccch
= find_dissector_add_dependency("nr-rrc.dl.ccch", proto_rlc_nr
);
1923 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1928 * indent-tabs-mode: nil
1931 * vi: set shiftwidth=4 tabstop=8 expandtab:
1932 * :indentSize=4:tabSize=8:noTabs=true: