Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rlc-nr.c
blob1f4447840e660a93aa6cbbcc2d13755af9b6178b
1 /* Routines for NR RLC disassembly
3 * Pascal Quantin
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
12 #include "config.h"
14 #include <epan/packet.h>
15 #include <epan/exceptions.h>
16 #include <epan/expert.h>
17 #include <epan/prefs.h>
18 #include <epan/tap.h>
19 #include <epan/proto_data.h>
20 #include <epan/reassemble.h>
21 #include <epan/tfs.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"
28 /* Described in:
29 * 3GPP TS 38.322 NR; Radio Link Control (RLC) protocol specification v15.0.0
32 /* TODO:
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},
53 {NULL, NULL, -1}
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. */
82 int proto_rlc_nr;
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;
134 /* Control fields */
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;
162 /* Subtrees. */
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,
175 &hf_rlc_nr_fragment,
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,
185 "RLC PDU fragments"
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;
206 /* Value-strings */
207 static const value_string direction_vals[] =
209 { DIRECTION_UPLINK, "Uplink" },
210 { DIRECTION_DOWNLINK, "Downlink" },
211 { 0, NULL }
214 static const value_string rlc_mode_short_vals[] =
216 { RLC_TM_MODE, "TM" },
217 { RLC_UM_MODE, "UM" },
218 { RLC_AM_MODE, "AM" },
219 { 0, NULL }
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" },
227 { 0, NULL }
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" },
238 { 0, NULL }
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" },
247 { 0, NULL }
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[] =
258 { 0, "STATUS PDU" },
259 { 0, NULL }
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)
296 return k1 == k2;
299 static void *pdu_temporary_key(const packet_info *pinfo _U_, const uint32_t id _U_, const void *data)
301 return (void *)data;
304 static void *pdu_persistent_key(const packet_info *pinfo _U_, const uint32_t id _U_,
305 const void *data)
307 return (void *)data;
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 =
320 pdu_hash,
321 pdu_equal,
322 pdu_temporary_key,
323 pdu_persistent_key,
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:
335 - the info column
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];
346 va_list ap;
348 va_start(ap, format);
349 vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
350 va_end(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
361 - the info column
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 */
381 if (length > 0) {
382 write_pdu_label_and_info(top_ti, NULL, pinfo,
383 " %s%u-byte%s%s",
384 (seg_info & 0x02) ? ".." : "[",
385 length,
386 (length > 1) ? "s" : "",
387 (seg_info & 0x01) ? ".." : "]");
388 } else {
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];
402 uint32_t id;
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;
435 int seqnum_len;
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;
442 break;
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) {
452 case PDCP_drb_SN_12:
453 p_pdcp_nr_info->seqnum_length = 12;
454 break;
455 case PDCP_drb_SN_18:
456 p_pdcp_nr_info->seqnum_length = 18;
457 break;
458 case PDCP_drb_SN_signalled:
459 /* Use whatever was signalled (i.e. in RRC) */
460 id = (rlc_info->bearerId << 16) | rlc_info->ueid;
461 key[0].length = 1;
462 key[0].key = &id;
463 key[1].length = 0;
464 key[1].key = NULL;
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)) {
469 params = NULL;
471 if (params) {
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;
478 else {
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;
487 break;
490 break;
492 default:
493 /* Shouldn't get here */
494 return;
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;
502 TRY {
503 call_dissector_only(pdcp_nr_handle, pdcp_tvb, pinfo, tree, NULL);
505 CATCH_ALL {
507 ENDTRY
512 /***************************************************/
513 /* Transparent mode PDU. Call RRC if configured to */
514 static void dissect_rlc_nr_tm(tvbuff_t *tvb, packet_info *pinfo,
515 proto_tree *tree,
516 int offset,
517 rlc_nr_info *p_rlc_nr_info,
518 proto_item *top_ti)
520 proto_item *raw_tm_ti;
521 proto_item *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;
542 break;
543 case BEARER_TYPE_BCCH_DL_SCH:
544 protocol_handle = nr_rrc_bcch_dl_sch;
545 break;
546 case BEARER_TYPE_PCCH:
547 protocol_handle = nr_rrc_pcch;
548 break;
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;
553 } else {
554 protocol_handle = nr_rrc_dl_ccch;
556 break;
557 case BEARER_TYPE_SRB:
558 case BEARER_TYPE_DRB:
559 default:
560 /* Shouldn't happen, just return... */
561 return;
564 /* Hide raw view of bytes */
565 proto_item_set_hidden(raw_tm_ti);
567 /* Call it (catch exceptions) */
568 TRY {
569 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
571 CATCH_ALL {
573 ENDTRY
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,
589 pinfo->num
592 /* Is this the first segment of SN? */
593 bool first_segment = (seg_info & 0x2) == 0;
595 /* Set Key. */
596 wmem_tree_key_t key[2];
597 key[0].length = 5; /* Ignoring this frame num */
598 key[0].key = key_values;
599 key[1].length = 0;
600 key[1].key = NULL;
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);
611 if (first_segment) {
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;
616 else {
617 if (p_frame_id) {
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. */
624 if (frame_id) {
625 key[0].length = 6;
626 wmem_tree_insert32_array(reassembly_start_table_stored, key, GUINT_TO_POINTER(frame_id));
629 else {
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);
633 if (p_frame_id) {
634 /* Use found value */
635 frame_id = GPOINTER_TO_UINT(p_frame_id);
639 return 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,
654 /* Set Key. */
655 wmem_tree_key_t key[2];
656 key[0].length = 5;
657 key[0].key = key_values;
658 key[1].length = 0;
659 key[1].key = NULL;
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;
675 uint64_t reserved;
676 proto_item *um_ti;
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;
682 uint32_t so = 0;
684 /* Hidden UM root */
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,
691 tvb, offset, 0,
692 "", "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);
698 if (seg_info == 0) {
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);
702 offset++;
703 if (reserved) {
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, " ");
707 } else {
708 /* Add sequence number */
709 if (p_rlc_nr_info->sequenceNumberLength == UM_SN_LENGTH_6_BITS) {
710 /* SN */
711 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_sn6, tvb, offset, 1, ENC_BIG_ENDIAN, &sn);
712 offset++;
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);
717 if (reserved) {
718 expert_add_info(pinfo, reserved_ti, &ei_rlc_nr_reserved_bits_not_zero);
720 /* SN */
721 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_sn12, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
722 offset += 2;
723 tap_info->sequenceNumberGiven = true;
724 } else {
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);
729 return;
732 tap_info->sequenceNumber = sn;
734 if (seg_info >= 2) {
735 /* Segment offset */
736 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_so, tvb, offset, 2, ENC_BIG_ENDIAN, &so);
737 offset += 2;
738 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " SN=%-6u SO=%-4u", sn, so);
739 } else {
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);
744 /* End of header */
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,
751 is_truncated);
752 if (is_truncated) {
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);
756 return;
757 } else {
758 proto_item_set_hidden(truncated_ti);
762 /* Data */
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;
770 fragment_head *fh;
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 */
773 if (id != 0) {
774 fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
775 id, /* id */
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 */
796 if (next_tvb) {
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,
814 packet_info *pinfo,
815 proto_tree *tree,
816 proto_item *status_ti,
817 int offset,
818 proto_item *top_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;
828 proto_item *ti;
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);
835 if (cpt != 0) {
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);
839 return;
842 if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_12_BITS) {
843 sn_size = 12;
844 sn_limit = 4096;
845 reserved_bits1 = 7;
846 reserved_bits2 = 1;
847 } else if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_18_BITS) {
848 sn_size = 18;
849 sn_limit = 262044;
850 reserved_bits1 = 1;
851 reserved_bits2 = 3;
852 } else {
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);
856 return;
859 /* The Status PDU itself starts 4 bits into the byte */
860 bit_offset += 4;
862 /* ACK SN */
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;
869 /* E1 */
870 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e1, tvb,
871 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
872 bit_offset++;
874 /* Reserved bits */
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;
878 if (reserved) {
879 expert_add_info(pinfo, ti, &ei_rlc_nr_reserved_bits_not_zero);
882 /* Optional, extra fields */
883 while (e1) {
884 proto_item *nack_ti;
886 /****************************/
887 /* Read NACK_SN, E1, E2, E3 */
889 /* NACK_SN */
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 ")",
899 ack_sn);
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;
911 else {
912 /* Let it get bigger than the array for accurate stats... */
913 nack_count++;
917 /* E1 */
918 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e1, tvb,
919 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
920 bit_offset++;
922 /* E2 */
923 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e2, tvb,
924 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
925 bit_offset++;
927 /* Report as expert info */
928 if (e2) {
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);
933 } else {
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);
940 /* E3 */
941 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e3, tvb,
942 bit_offset, 1, &e3, ENC_BIG_ENDIAN);
943 bit_offset++;
945 /* Reserved bits */
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;
949 if (reserved) {
950 expert_add_info(pinfo, ti, &ei_rlc_nr_reserved_bits_not_zero);
953 if (e2) {
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);
957 bit_offset += 16;
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);
962 bit_offset += 16;
965 if (so_end == 0xffff) {
966 write_pdu_label_and_info(top_ti, NULL, pinfo,
967 " (SOstart=%u SOend=<END-OF_SDU>)",
968 so_start);
969 } else {
970 write_pdu_label_and_info(top_ti, NULL, pinfo,
971 " (SOstart=%u SOend=%u)",
972 so_start, so_end);
976 if (e3) {
977 /* NACK range */
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);
981 bit_offset += 8;
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);
985 return;
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_)
1032 bool dc, polling;
1033 uint32_t seg_info, sn;
1034 uint64_t reserved;
1035 proto_item *am_ti;
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;
1041 uint32_t so = 0;
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,
1050 tvb, offset, 0,
1051 "", "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;
1060 if (dc == 0) {
1061 /**********************/
1062 /* Status PDU */
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,
1067 offset, top_ti,
1068 p_rlc_nr_info, tap_info);
1069 return;
1072 /**********************/
1073 /* Data PDU */
1074 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [DATA]");
1076 /* Polling bit */
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) " : " ");
1081 if (polling) {
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);
1093 offset += 2;
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);
1097 if (reserved) {
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);
1102 offset += 3;
1103 } else {
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);
1108 return;
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);
1118 offset += 2;
1119 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "SN=%-6u SO=%-4u",sn, so);
1120 } else {
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,
1131 is_truncated);
1132 if (is_truncated) {
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);
1136 return;
1137 } else {
1138 proto_item_set_hidden(truncated_ti);
1142 /* Data */
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;
1150 fragment_head *fh;
1151 bool more_frags = seg_info & 0x01;
1152 uint32_t id = get_reassembly_start_frame(pinfo, seg_info, p_rlc_nr_info, sn);
1153 if (id != 0) {
1154 fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
1155 id, /* id */
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 */
1177 if (next_tvb) {
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_)
1193 int offset = 0;
1194 rlc_nr_info *p_rlc_nr_info;
1195 tvbuff_t *rlc_tvb;
1196 uint8_t tag;
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
1203 - tag for data
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)) {
1206 return false;
1209 /* OK, compare with signature string */
1210 if (tvb_strneql(tvb, offset, RLC_NR_START_STRING, (int)strlen(RLC_NR_START_STRING)) != 0) {
1211 return false;
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 */
1227 do {
1228 /* Process next tag */
1229 tag = tvb_get_uint8(tvb, offset++);
1230 switch (tag) {
1231 case RLC_NR_DIRECTION_TAG:
1232 p_rlc_nr_info->direction = tvb_get_uint8(tvb, offset);
1233 offset++;
1234 break;
1235 case RLC_NR_UEID_TAG:
1236 p_rlc_nr_info->ueid = tvb_get_ntohs(tvb, offset);
1237 offset += 2;
1238 break;
1239 case RLC_NR_BEARER_TYPE_TAG:
1240 p_rlc_nr_info->bearerType = tvb_get_uint8(tvb, offset);
1241 offset++;
1242 break;
1243 case RLC_NR_BEARER_ID_TAG:
1244 p_rlc_nr_info->bearerId = tvb_get_uint8(tvb, offset);
1245 offset++;
1246 break;
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);
1250 break;
1251 default:
1252 /* It must be a recognised tag */
1254 proto_item *ti;
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,
1262 tvb, offset-1, 1);
1264 wmem_free(wmem_file_scope(), p_rlc_nr_info);
1265 return true;
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);
1271 } else {
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 */);
1281 return true;
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;
1298 proto_item *top_ti;
1299 proto_item *context_ti;
1300 proto_item *ti;
1301 proto_item *mode_ti;
1302 int offset = 0;
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);
1323 return;
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,
1383 " [%s] [%s] ",
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"));
1390 } else {
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) {
1413 case RLC_TM_MODE:
1414 dissect_rlc_nr_tm(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti);
1415 break;
1417 case RLC_UM_MODE:
1418 dissect_rlc_nr_um(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti, tap_info);
1419 break;
1421 case RLC_AM_MODE:
1422 dissect_rlc_nr_am(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti, tap_info);
1423 break;
1425 default:
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);
1429 break;
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];
1442 uint32_t id;
1443 pdcp_bearer_parameters *params;
1445 if (PINFO_FD_VISITED(pinfo)) {
1446 return;
1449 id = (drb_mapping->drbid << 16) | drb_mapping->ueid;
1450 key[0].length = 1;
1451 key[0].key = &id;
1452 key[1].length = 0;
1453 key[1].key = NULL;
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)) {
1458 params = NULL;
1460 if (params == NULL) {
1461 /* Not found so create new entry */
1462 params = (pdcp_bearer_parameters *)wmem_new(wmem_file_scope(), pdcp_bearer_parameters);
1463 params->id = id;
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];
1479 uint32_t id;
1480 pdcp_bearer_parameters *params;
1482 id = (drb_id << 16) | ue_id;
1483 key[0].length = 1;
1484 key[0].key = &id;
1485 key[1].length = 0;
1486 key[1].key = NULL;
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)) {
1491 params = NULL;
1494 return params;
1498 void proto_register_rlc_nr(void)
1500 static hf_register_info hf[] =
1502 /**********************************/
1503 /* Items for decoding context */
1504 { &hf_rlc_nr_context,
1505 { "Context",
1506 "rlc-nr.context", FT_STRING, BASE_NONE, NULL, 0x0,
1507 NULL, HFILL
1510 { &hf_rlc_nr_context_mode,
1511 { "RLC Mode",
1512 "rlc-nr.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
1513 NULL, HFILL
1516 { &hf_rlc_nr_context_direction,
1517 { "Direction",
1518 "rlc-nr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1519 "Direction of message", HFILL
1522 { &hf_rlc_nr_context_ueid,
1523 { "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,
1529 { "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,
1535 { "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,
1541 { "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 */
1554 { &hf_rlc_nr_tm,
1555 { "TM",
1556 "rlc-nr.tm", FT_STRING, BASE_NONE, NULL, 0x0,
1557 "Transparent Mode", HFILL
1560 { &hf_rlc_nr_tm_data,
1561 { "TM Data",
1562 "rlc-nr.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
1563 "Transparent Mode Data", HFILL
1567 /* Unacknowledged mode fields */
1568 { &hf_rlc_nr_um,
1569 { "UM",
1570 "rlc-nr.um", FT_STRING, BASE_NONE, NULL, 0x0,
1571 "Unacknowledged Mode", HFILL
1574 { &hf_rlc_nr_um_header,
1575 { "UM Header",
1576 "rlc-nr.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
1577 "Unacknowledged Mode Header", HFILL
1580 { &hf_rlc_nr_um_si,
1581 { "Segmentation Info",
1582 "rlc-nr.um.si", FT_UINT8, BASE_HEX, VALS(seg_info_vals), 0xc0,
1583 NULL, HFILL
1586 { &hf_rlc_nr_um_reserved,
1587 { "Reserved",
1588 "rlc-nr.um.reserved", FT_UINT8, BASE_HEX, 0, 0x0,
1589 NULL, HFILL
1592 { &hf_rlc_nr_um_sn6,
1593 { "Sequence Number",
1594 "rlc-nr.um.sn", FT_UINT8, BASE_DEC, 0, 0x3f,
1595 NULL, HFILL
1598 { &hf_rlc_nr_um_sn12,
1599 { "Sequence Number",
1600 "rlc-nr.um.sn", FT_UINT16, BASE_DEC, 0, 0x0fff,
1601 NULL, HFILL
1604 { &hf_rlc_nr_um_so,
1605 { "Segment Offset",
1606 "rlc-nr.um.so", FT_UINT16, BASE_DEC, 0, 0x0,
1607 NULL, HFILL
1610 { &hf_rlc_nr_um_data,
1611 { "UM Data",
1612 "rlc-nr.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
1613 "Unacknowledged Mode Data", HFILL
1617 /* Acknowledged mode fields */
1618 { &hf_rlc_nr_am,
1619 { "AM",
1620 "rlc-nr.am", FT_STRING, BASE_NONE, NULL, 0x0,
1621 "Acknowledged Mode", HFILL
1624 { &hf_rlc_nr_am_header,
1625 { "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,
1631 { "Data/Control",
1632 "rlc-nr.am.dc", FT_BOOLEAN, 8, TFS(&tfs_data_pdu_control_pdu), 0x80,
1633 NULL, HFILL
1636 { &hf_rlc_nr_am_p,
1637 { "Polling Bit",
1638 "rlc-nr.am.p", FT_BOOLEAN, 8, TFS(&polling_bit_vals), 0x40,
1639 NULL, HFILL
1642 { &hf_rlc_nr_am_si,
1643 { "Segmentation Info",
1644 "rlc-nr.am.si", FT_UINT8, BASE_HEX, VALS(seg_info_vals), 0x30,
1645 NULL, HFILL
1648 { &hf_rlc_nr_am_sn12,
1649 { "Sequence Number",
1650 "rlc-nr.am.sn", FT_UINT16, BASE_DEC, 0, 0x0fff,
1651 NULL, HFILL
1654 { &hf_rlc_nr_am_sn18,
1655 { "Sequence Number",
1656 "rlc-nr.am.sn", FT_UINT24, BASE_DEC, 0, 0x03ffff,
1657 NULL, HFILL
1660 { &hf_rlc_nr_am_reserved,
1661 { "Reserved",
1662 "rlc-nr.am.reserved", FT_UINT8, BASE_HEX, 0, 0x0,
1663 NULL, HFILL
1666 { &hf_rlc_nr_am_so,
1667 { "Segment Offset",
1668 "rlc-nr.am.so", FT_UINT16, BASE_DEC, 0, 0x0,
1669 NULL, HFILL
1672 { &hf_rlc_nr_am_data,
1673 { "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
1690 { &hf_rlc_nr_am_e1,
1691 { "Extension bit 1",
1692 "rlc-nr.am.e1", FT_BOOLEAN, BASE_NONE, TFS(&am_e1_vals), 0x0,
1693 NULL, HFILL
1696 { &hf_rlc_nr_am_e2,
1697 { "Extension bit 2",
1698 "rlc-nr.am.e2", FT_BOOLEAN, BASE_NONE, TFS(&am_e2_vals), 0x0,
1699 NULL, HFILL
1702 { &hf_rlc_nr_am_e3,
1703 { "Extension bit 3",
1704 "rlc-nr.am.e3", FT_BOOLEAN, BASE_NONE, TFS(&am_e3_vals), 0x0,
1705 NULL, HFILL
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,
1721 { "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,
1727 { "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,
1733 { "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,
1742 NULL, HFILL
1746 { &hf_rlc_nr_fragment,
1747 { "RLC-NR fragment",
1748 "rlc-nr.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1749 NULL, HFILL }
1751 { &hf_rlc_nr_fragments,
1752 { "RLC-NR fragments",
1753 "rlc-nr.fragments", FT_BYTES, BASE_NONE, NULL, 0x0,
1754 NULL, HFILL }
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,
1786 { "Fragment count",
1787 "rlc-nr.fragment.count",
1788 FT_UINT32, BASE_DEC, NULL, 0x0,
1789 NULL, HFILL }
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 }
1811 static int *ett[] =
1813 &ett_rlc_nr,
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");
1856 /* Preferences */
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
1925 * Local variables:
1926 * c-basic-offset: 4
1927 * tab-width: 8
1928 * indent-tabs-mode: nil
1929 * End:
1931 * vi: set shiftwidth=4 tabstop=8 expandtab:
1932 * :indentSize=4:tabSize=8:noTabs=true: