1 /* Routines for NR RLC disassembly
2 *
3 * Pascal Quantin
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "config.h"
13
14 #include <epan/packet.h>
15 #include <epan/exceptions.h>
16 #include <epan/expert.h>
17 #include <epan/prefs.h>
18 #include <epan/proto_data.h>
19 #include <epan/reassemble.h>
20
21 #include "packet-rlc-nr.h"
22 #include "packet-pdcp-nr.h"
23
24
25 /* Described in:
26 * 3GPP TS 38.322 NR; Radio Link Control (RLC) protocol specification v15.0.0
27 */
28
29 /* TODO:
30 - add sequence analysis
31 - take configuration of reordering timer, and stop reassembly if timeout exceeded?
32 - add tap info
33 - call more upper layer dissectors once they appear
34 */
35
36 void proto_register_rlc_nr(void);
37 void proto_reg_handoff_rlc_nr(void);
38
39 /********************************/
40 /* Preference settings */
41
42 /* By default do call PDCP/RRC dissectors for SDU data */
43 static gboolean global_rlc_nr_call_pdcp_for_srb = TRUE;
44
45 enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_12, PDCP_drb_SN_18, PDCP_drb_SN_signalled};
46 static const enum_val_t pdcp_drb_col_vals[] = {
47 {"pdcp-drb-off", "Off", PDCP_drb_off},
48 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
49 {"pdcp-drb-sn-18", "18-bit SN", PDCP_drb_SN_18},
50 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
51 {NULL, NULL, -1}
52 };
53 /* Separate config for UL/DL */
54 static gint global_rlc_nr_call_pdcp_for_ul_drb = (gint)PDCP_drb_off;
55 static gint global_rlc_nr_call_pdcp_for_dl_drb = (gint)PDCP_drb_off;
56
57
58 static gboolean global_rlc_nr_call_rrc_for_ccch = TRUE;
59
60 /* Preference to expect RLC headers without payloads */
61 static gboolean global_rlc_nr_headers_expected = FALSE;
62
63 /* Attempt reassembly. */
64 static gboolean global_rlc_nr_reassemble_um_pdus = FALSE;
65 static gboolean global_rlc_nr_reassemble_am_pdus = TRUE;
66
67 /* Tree storing UE related parameters (ueid, drbid) -> pdcp_bearer_parameters */
68 static wmem_tree_t *ue_parameters_tree;
69
70
71 /**************************************************/
72 /* Initialize the protocol and registered fields. */
73 int proto_rlc_nr = -1;
74
75 extern int proto_pdcp_nr;
76
77 static dissector_handle_t pdcp_nr_handle;
78 static dissector_handle_t nr_rrc_bcch_bch;
79 static dissector_handle_t nr_rrc_bcch_dl_sch;
80 static dissector_handle_t nr_rrc_pcch;
81 static dissector_handle_t nr_rrc_ul_ccch;
82 static dissector_handle_t nr_rrc_ul_ccch1;
83 static dissector_handle_t nr_rrc_dl_ccch;
84
85
86 /* Decoding context */
87 static int hf_rlc_nr_context = -1;
88 static int hf_rlc_nr_context_mode = -1;
89 static int hf_rlc_nr_context_direction = -1;
90 static int hf_rlc_nr_context_ueid = -1;
91 static int hf_rlc_nr_context_bearer_type = -1;
92 static int hf_rlc_nr_context_bearer_id = -1;
93 static int hf_rlc_nr_context_pdu_length = -1;
94 static int hf_rlc_nr_context_sn_length = -1;
95
96 /* Transparent mode fields */
97 static int hf_rlc_nr_tm = -1;
98 static int hf_rlc_nr_tm_data = -1;
99
100 /* Unacknowledged mode fields */
101 static int hf_rlc_nr_um = -1;
102 static int hf_rlc_nr_um_header = -1;
103 static int hf_rlc_nr_um_si = -1;
104 static int hf_rlc_nr_um_reserved = -1;
105 static int hf_rlc_nr_um_sn6 = -1;
106 static int hf_rlc_nr_um_sn12 = -1;
107 static int hf_rlc_nr_um_so = -1;
108 static int hf_rlc_nr_um_data = -1;
109
110 /* Acknowledged mode fields */
111 static int hf_rlc_nr_am = -1;
112 static int hf_rlc_nr_am_header = -1;
113 static int hf_rlc_nr_am_data_control = -1;
114 static int hf_rlc_nr_am_p = -1;
115 static int hf_rlc_nr_am_si = -1;
116 static int hf_rlc_nr_am_sn12 = -1;
117 static int hf_rlc_nr_am_sn18 = -1;
118 static int hf_rlc_nr_am_reserved = -1;
119 static int hf_rlc_nr_am_so = -1;
120 static int hf_rlc_nr_am_data = -1;
121
122 /* Control fields */
123 static int hf_rlc_nr_am_cpt = -1;
124 static int hf_rlc_nr_am_ack_sn = -1;
125 static int hf_rlc_nr_am_e1 = -1;
126 static int hf_rlc_nr_am_e2 = -1;
127 static int hf_rlc_nr_am_e3 = -1;
128 static int hf_rlc_nr_am_nack_sn = -1;
129 static int hf_rlc_nr_am_so_start = -1;
130 static int hf_rlc_nr_am_so_end = -1;
131 static int hf_rlc_nr_am_nack_range = -1;
132 static int hf_rlc_nr_am_nacks = -1;
133
134 static int hf_rlc_nr_header_only = -1;
135
136 static int hf_rlc_nr_fragments = -1;
137 static int hf_rlc_nr_fragment = -1;
138 static int hf_rlc_nr_fragment_overlap = -1;
139 static int hf_rlc_nr_fragment_overlap_conflict = -1;
140 static int hf_rlc_nr_fragment_multiple_tails = -1;
141 static int hf_rlc_nr_fragment_too_long_fragment = -1;
142 static int hf_rlc_nr_fragment_error = -1;
143 static int hf_rlc_nr_fragment_count = -1;
144 static int hf_rlc_nr_reassembled_in = -1;
145 static int hf_rlc_nr_reassembled_length = -1;
146 static int hf_rlc_nr_reassembled_data = -1;
147
148
149
150 /* Subtrees. */
151 static int ett_rlc_nr = -1;
152 static int ett_rlc_nr_context = -1;
153 static int ett_rlc_nr_um_header = -1;
154 static int ett_rlc_nr_am_header = -1;
155 static int ett_rlc_nr_fragments = -1;
156 static int ett_rlc_nr_fragment = -1;
157
158
159 static const fragment_items rlc_nr_frag_items = {
160 &ett_rlc_nr_fragment,
161 &ett_rlc_nr_fragments,
162 &hf_rlc_nr_fragments,
163 &hf_rlc_nr_fragment,
164 &hf_rlc_nr_fragment_overlap,
165 &hf_rlc_nr_fragment_overlap_conflict,
166 &hf_rlc_nr_fragment_multiple_tails,
167 &hf_rlc_nr_fragment_too_long_fragment,
168 &hf_rlc_nr_fragment_error,
169 &hf_rlc_nr_fragment_count,
170 &hf_rlc_nr_reassembled_in,
171 &hf_rlc_nr_reassembled_length,
172 &hf_rlc_nr_reassembled_data,
173 "RLC PDU fragments"
174 };
175
176
177 static expert_field ei_rlc_nr_context_mode = EI_INIT;
178 static expert_field ei_rlc_nr_am_nack_sn = EI_INIT;
179 static expert_field ei_rlc_nr_am_nack_sn_ahead_ack = EI_INIT;
180 static expert_field ei_rlc_nr_am_nack_sn_ack_same = EI_INIT;
181 static expert_field ei_rlc_nr_am_nack_range = EI_INIT;
182 static expert_field ei_rlc_nr_am_cpt = EI_INIT;
183 static expert_field ei_rlc_nr_um_data_no_data = EI_INIT;
184 static expert_field ei_rlc_nr_am_data_no_data = EI_INIT;
185 static expert_field ei_rlc_nr_am_nack_sn_partial = EI_INIT;
186 static expert_field ei_rlc_nr_bytes_after_status_pdu_complete = EI_INIT;
187 static expert_field ei_rlc_nr_um_sn = EI_INIT;
188 static expert_field ei_rlc_nr_am_sn = EI_INIT;
189 static expert_field ei_rlc_nr_header_only = EI_INIT;
190 static expert_field ei_rlc_nr_reserved_bits_not_zero = EI_INIT;
191 static expert_field ei_rlc_nr_no_per_frame_info = EI_INIT;
192 static expert_field ei_rlc_nr_unknown_udp_framing_tag = EI_INIT;
193
194 /* Value-strings */
195 static const value_string direction_vals[] =
196 {
197 { DIRECTION_UPLINK, "Uplink" },
198 { DIRECTION_DOWNLINK, "Downlink" },
199 { 0, NULL }
200 };
201
202 static const value_string rlc_mode_short_vals[] =
203 {
204 { RLC_TM_MODE, "TM" },
205 { RLC_UM_MODE, "UM" },
206 { RLC_AM_MODE, "AM" },
207 { 0, NULL }
208 };
209
210 static const value_string rlc_mode_vals[] =
211 {
212 { RLC_TM_MODE, "Transparent Mode" },
213 { RLC_UM_MODE, "Unacknowledged Mode" },
214 { RLC_AM_MODE, "Acknowledged Mode" },
215 { 0, NULL }
216 };
217
218 static const value_string rlc_bearer_type_vals[] =
219 {
220 { BEARER_TYPE_CCCH, "CCCH" },
221 { BEARER_TYPE_BCCH_BCH, "BCCH BCH" },
222 { BEARER_TYPE_PCCH, "PCCH" },
223 { BEARER_TYPE_SRB, "SRB" },
224 { BEARER_TYPE_DRB, "DRB" },
225 { BEARER_TYPE_BCCH_DL_SCH, "BCCH DL-SCH" },
226 { 0, NULL }
227 };
228
229 static const value_string seg_info_vals[] =
230 {
231 { 0, "Data field contains all bytes of an RLC SDU" },
232 { 1, "Data field contains the first segment of an RLC SDU" },
233 { 2, "Data field contains the last segment of an RLC SDU" },
234 { 3, "Data field contains neither the first nor last segment of an RLC SDU" },
235 { 0, NULL }
236 };
237
238 static const true_false_string data_or_control_vals =
239 {
240 "Data PDU",
241 "Control PDU"
242 };
243
244 static const true_false_string polling_bit_vals =
245 {
246 "Status report is requested",
247 "Status report not requested"
248 };
249
250 static const value_string control_pdu_type_vals[] =
251 {
252 { 0, "STATUS PDU" },
253 { 0, NULL }
254 };
255
256 static const true_false_string am_e1_vals =
257 {
258 "A set of NACK_SN, E1, E2 and E3 follows",
259 "A set of NACK_SN, E1, E2 and E3 does not follow"
260 };
261
262 static const true_false_string am_e2_vals =
263 {
264 "A set of SOstart and SOend follows for this NACK_SN",
265 "A set of SOstart and SOend does not follow for this NACK_SN"
266 };
267
268 static const true_false_string am_e3_vals =
269 {
270 "NACK range field follows for this NACK_SN",
271 "NACK range field does not follow for this NACK_SN"
272 };
273
274 static const true_false_string header_only_vals =
275 {
276 "RLC PDU Headers only",
277 "RLC PDU Headers and body present"
278 };
279
280 /* Reassembly state */
281 static reassembly_table pdu_reassembly_table;
282
pdu_hash(gconstpointer k _U_)283 static guint pdu_hash(gconstpointer k _U_)
284 {
285 return GPOINTER_TO_UINT(k);
286 }
287
pdu_equal(gconstpointer k1,gconstpointer k2)288 static gint pdu_equal(gconstpointer k1, gconstpointer k2)
289 {
290 return k1 == k2;
291 }
292
pdu_temporary_key(const packet_info * pinfo _U_,const guint32 id _U_,const void * data _U_)293 static gpointer pdu_temporary_key(const packet_info *pinfo _U_, const guint32 id _U_, const void *data _U_)
294 {
295 return (gpointer)data;
296 }
297
pdu_persistent_key(const packet_info * pinfo _U_,const guint32 id _U_,const void * data)298 static gpointer pdu_persistent_key(const packet_info *pinfo _U_, const guint32 id _U_,
299 const void *data)
300 {
301 return (gpointer)data;
302 }
303
pdu_free_temporary_key(gpointer ptr _U_)304 static void pdu_free_temporary_key(gpointer ptr _U_)
305 {
306 }
307
pdu_free_persistent_key(gpointer ptr _U_)308 static void pdu_free_persistent_key(gpointer ptr _U_)
309 {
310 }
311
312 static reassembly_table_functions pdu_reassembly_table_functions =
313 {
314 pdu_hash,
315 pdu_equal,
316 pdu_temporary_key,
317 pdu_persistent_key,
318 pdu_free_temporary_key,
319 pdu_free_persistent_key
320 };
321
322
323 /********************************************************/
324 /* Forward declarations & functions */
325 static void dissect_rlc_nr_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing);
326
327
328 /* Write the given formatted text to:
329 - the info column
330 - the top-level RLC PDU item
331 - another subtree item (if supplied) */
write_pdu_label_and_info(proto_item * pdu_ti,proto_item * sub_ti,packet_info * pinfo,const char * format,...)332 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
333 packet_info *pinfo, const char *format, ...)
334 {
335 #define MAX_INFO_BUFFER 256
336 static char info_buffer[MAX_INFO_BUFFER];
337
338 va_list ap;
339
340 va_start(ap, format);
341 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
342 va_end(ap);
343
344 /* Add to indicated places */
345 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
346 proto_item_append_text(pdu_ti, "%s", info_buffer);
347 if (sub_ti != NULL) {
348 proto_item_append_text(sub_ti, "%s", info_buffer);
349 }
350 }
351
352 /* Version of function above, where no g_vsnprintf() call needed
353 - the info column
354 - the top-level RLC PDU item
355 - another subtree item (if supplied) */
write_pdu_label_and_info_literal(proto_item * pdu_ti,proto_item * sub_ti,packet_info * pinfo,const char * info_buffer)356 static void write_pdu_label_and_info_literal(proto_item *pdu_ti, proto_item *sub_ti,
357 packet_info *pinfo, const char *info_buffer)
358 {
359 /* Add to indicated places */
360 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
361 proto_item_append_text(pdu_ti, "%s", info_buffer);
362 if (sub_ti != NULL) {
363 proto_item_append_text(sub_ti, "%s", info_buffer);
364 }
365 }
366
367 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
368 whether or not the beginning and end are included in this packet */
show_PDU_in_info(packet_info * pinfo,proto_item * top_ti,gint32 length,guint8 seg_info)369 static void show_PDU_in_info(packet_info *pinfo,
370 proto_item *top_ti,
371 gint32 length,
372 guint8 seg_info)
373 {
374 /* Reflect this PDU in the info column */
375 if (length > 0) {
376 write_pdu_label_and_info(top_ti, NULL, pinfo,
377 " %s%u-byte%s%s",
378 (seg_info & 0x02) ? ".." : "[",
379 length,
380 (length > 1) ? "s" : "",
381 (seg_info & 0x01) ? ".." : "]");
382 } else {
383 write_pdu_label_and_info(top_ti, NULL, pinfo,
384 " %sunknown-bytes%s",
385 (seg_info & 0x02) ? ".." : "[",
386 (seg_info & 0x01) ? ".." : "]");
387 }
388 }
389
390
391 /* Show an SDU. If configured, pass to PDCP/RRC dissector */
show_PDU_in_tree(packet_info * pinfo,proto_tree * tree,tvbuff_t * tvb,gint offset,gint length,rlc_nr_info * rlc_info,guint32 seg_info,gboolean is_reassembled)392 static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, gint offset, gint length,
393 rlc_nr_info *rlc_info, guint32 seg_info, gboolean is_reassembled)
394 {
395 wmem_tree_key_t key[2];
396 guint32 id;
397 pdcp_bearer_parameters *params;
398
399 /* Add raw data (according to mode) */
400 if (!is_reassembled) {
401 proto_tree_add_item(tree, (rlc_info->rlcMode == RLC_AM_MODE) ?
402 hf_rlc_nr_am_data : hf_rlc_nr_um_data,
403 tvb, offset, length, ENC_NA);
404 }
405
406 if ((seg_info == 0) || is_reassembled) { /* i.e. contains whole SDU */
407 if ((global_rlc_nr_call_pdcp_for_srb && (rlc_info->bearerType == BEARER_TYPE_SRB)) ||
408 ((rlc_info->bearerType == BEARER_TYPE_DRB) &&
409 (((rlc_info->direction == PDCP_NR_DIRECTION_UPLINK) && (global_rlc_nr_call_pdcp_for_ul_drb != PDCP_drb_off)) ||
410 ((rlc_info->direction == PDCP_NR_DIRECTION_DOWNLINK) && (global_rlc_nr_call_pdcp_for_dl_drb != PDCP_drb_off)))))
411 {
412
413 /* Get whole PDU into tvb */
414 tvbuff_t *pdcp_tvb = tvb_new_subset_length(tvb, offset, length);
415
416 /* Reuse or allocate struct */
417 struct pdcp_nr_info *p_pdcp_nr_info;
418 p_pdcp_nr_info = (pdcp_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0);
419 if (p_pdcp_nr_info == NULL) {
420 p_pdcp_nr_info = wmem_new0(wmem_file_scope(), pdcp_nr_info);
421 /* Store info in packet */
422 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_nr, 0, p_pdcp_nr_info);
423 }
424
425 /* Fill in struct params. */
426 p_pdcp_nr_info->direction = rlc_info->direction;
427 p_pdcp_nr_info->ueid = rlc_info->ueid;
428
429 gint seqnum_len;
430
431 switch (rlc_info->bearerType) {
432 case BEARER_TYPE_SRB:
433 p_pdcp_nr_info->plane = NR_SIGNALING_PLANE;
434 p_pdcp_nr_info->bearerType = Bearer_DCCH;
435 p_pdcp_nr_info->seqnum_length = 12;
436 break;
437
438 case BEARER_TYPE_DRB:
439 p_pdcp_nr_info->plane = NR_USER_PLANE;
440 p_pdcp_nr_info->bearerType = Bearer_DCCH;
441
442 seqnum_len = (rlc_info->direction == PDCP_NR_DIRECTION_UPLINK) ?
443 global_rlc_nr_call_pdcp_for_ul_drb :
444 global_rlc_nr_call_pdcp_for_dl_drb;
445 switch (seqnum_len) {
446 case PDCP_drb_SN_12:
447 p_pdcp_nr_info->seqnum_length = 12;
448 break;
449 case PDCP_drb_SN_18:
450 p_pdcp_nr_info->seqnum_length = 18;
451 break;
452 case PDCP_drb_SN_signalled:
453 /* Use whatever was signalled (i.e. in RRC) */
454 id = (rlc_info->bearerId << 16) | rlc_info->ueid;
455 key[0].length = 1;
456 key[0].key = &id;
457 key[1].length = 0;
458 key[1].key = NULL;
459
460 /* Look up configured params for this PDCP DRB. */
461 params = (pdcp_bearer_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
462 if (params && (params->id != id)) {
463 params = NULL;
464 }
465 if (params) {
466 if (p_pdcp_nr_info->direction == DIRECTION_UPLINK) {
467 p_pdcp_nr_info->seqnum_length = params->pdcp_sn_bits_ul;
468 if (params->pdcp_sdap_ul) {
469 p_pdcp_nr_info->sdap_header &= PDCP_NR_UL_SDAP_HEADER_PRESENT;
470 }
471 }
472 else {
473 p_pdcp_nr_info->seqnum_length = params->pdcp_sn_bits_dl;
474 if (params->pdcp_sdap_dl) {
475 p_pdcp_nr_info->sdap_header &= PDCP_NR_DL_SDAP_HEADER_PRESENT;
476 }
477 }
478 p_pdcp_nr_info->maci_present = params->pdcp_integrity;
479 p_pdcp_nr_info->ciphering_disabled = params->pdcp_ciphering_disabled;
480 }
481 break;
482
483 }
484 break;
485
486 default:
487 /* Shouldn't get here */
488 return;
489 }
490 p_pdcp_nr_info->bearerId = rlc_info->bearerId;
491
492 /* Assume no SDAP present */
493 p_pdcp_nr_info->sdap_header = 0;
494 p_pdcp_nr_info->rohc.rohc_compression = FALSE;
495 p_pdcp_nr_info->is_retx = FALSE;
496 p_pdcp_nr_info->pdu_length = length;
497
498 TRY {
499 call_dissector_only(pdcp_nr_handle, pdcp_tvb, pinfo, tree, NULL);
500 }
501 CATCH_ALL {
502 }
503 ENDTRY
504 }
505 }
506 }
507
508 /***************************************************/
509 /* Transparent mode PDU. Call RRC if configured to */
dissect_rlc_nr_tm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,int offset,rlc_nr_info * p_rlc_nr_info,proto_item * top_ti)510 static void dissect_rlc_nr_tm(tvbuff_t *tvb, packet_info *pinfo,
511 proto_tree *tree,
512 int offset,
513 rlc_nr_info *p_rlc_nr_info,
514 proto_item *top_ti)
515 {
516 proto_item *raw_tm_ti;
517 proto_item *tm_ti;
518
519 /* Create hidden TM root */
520 tm_ti = proto_tree_add_string_format(tree, hf_rlc_nr_tm,
521 tvb, offset, 0, "", "TM");
522 proto_item_set_hidden(tm_ti);
523
524 /* Remaining bytes are all data */
525 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_nr_tm_data, tvb, offset, -1, ENC_NA);
526 if (!global_rlc_nr_call_rrc_for_ccch) {
527 write_pdu_label_and_info(top_ti, NULL, pinfo,
528 " [%u-bytes]", tvb_reported_length_remaining(tvb, offset));
529 }
530
531 if (global_rlc_nr_call_rrc_for_ccch) {
532 tvbuff_t *rrc_tvb = tvb_new_subset_remaining(tvb, offset);
533 volatile dissector_handle_t protocol_handle;
534
535 switch (p_rlc_nr_info->bearerType) {
536 case BEARER_TYPE_BCCH_BCH:
537 protocol_handle = nr_rrc_bcch_bch;
538 break;
539 case BEARER_TYPE_BCCH_DL_SCH:
540 protocol_handle = nr_rrc_bcch_dl_sch;
541 break;
542 case BEARER_TYPE_PCCH:
543 protocol_handle = nr_rrc_pcch;
544 break;
545 case BEARER_TYPE_CCCH:
546 if (p_rlc_nr_info->direction == DIRECTION_UPLINK) {
547 protocol_handle = (tvb_reported_length(rrc_tvb) == 8) ?
548 nr_rrc_ul_ccch1 : nr_rrc_ul_ccch;
549 } else {
550 protocol_handle = nr_rrc_dl_ccch;
551 }
552 break;
553 case BEARER_TYPE_SRB:
554 case BEARER_TYPE_DRB:
555 default:
556 /* Shouldn't happen, just return... */
557 return;
558 }
559
560 /* Hide raw view of bytes */
561 proto_item_set_hidden(raw_tm_ti);
562
563 /* Call it (catch exceptions) */
564 TRY {
565 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
566 }
567 CATCH_ALL {
568 }
569 ENDTRY
570 }
571 }
572
573
574
575 /***************************************************/
576 /* Unacknowledged mode PDU */
dissect_rlc_nr_um(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,int offset,rlc_nr_info * p_rlc_nr_info,proto_item * top_ti)577 static void dissect_rlc_nr_um(tvbuff_t *tvb, packet_info *pinfo,
578 proto_tree *tree,
579 int offset,
580 rlc_nr_info *p_rlc_nr_info,
581 proto_item *top_ti)
582 {
583 guint32 seg_info, sn;
584 guint64 reserved;
585 proto_item *um_ti;
586 proto_tree *um_header_tree;
587 proto_item *um_header_ti;
588 gboolean is_truncated = FALSE;
589 proto_item *truncated_ti;
590 proto_item *reserved_ti;
591 int start_offset = offset;
592 guint32 so = 0;
593
594 /* Hidden UM root */
595 um_ti = proto_tree_add_string_format(tree, hf_rlc_nr_um,
596 tvb, offset, 0, "", "UM");
597 proto_item_set_hidden(um_ti);
598
599 /* Add UM header subtree */
600 um_header_ti = proto_tree_add_string_format(tree, hf_rlc_nr_um_header,
601 tvb, offset, 0,
602 "", "UM header");
603 um_header_tree = proto_item_add_subtree(um_header_ti,
604 ett_rlc_nr_um_header);
605
606 /* Segmentation Info */
607 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_si, tvb, offset, 1, ENC_BIG_ENDIAN, &seg_info);
608 if (seg_info == 0) {
609 /* Have all bytes of SDU, so no SN. */
610 reserved_ti = proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_nr_um_reserved,
611 tvb, (offset<<3)+2, 6, &reserved, ENC_BIG_ENDIAN);
612 offset++;
613 if (reserved) {
614 expert_add_info(pinfo, reserved_ti, &ei_rlc_nr_reserved_bits_not_zero);
615 }
616 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " ");
617 } else {
618 /* Add sequence number */
619 if (p_rlc_nr_info->sequenceNumberLength == UM_SN_LENGTH_6_BITS) {
620 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_sn6, tvb, offset, 1, ENC_BIG_ENDIAN, &sn);
621 offset++;
622 } else if (p_rlc_nr_info->sequenceNumberLength == UM_SN_LENGTH_12_BITS) {
623 reserved_ti = proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_nr_um_reserved, tvb,
624 (offset<<3)+2, 2, &reserved, ENC_BIG_ENDIAN);
625 if (reserved) {
626 expert_add_info(pinfo, reserved_ti, &ei_rlc_nr_reserved_bits_not_zero);
627 }
628 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_sn12, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
629 offset += 2;
630 } else {
631 /* Invalid length of sequence number */
632 proto_tree_add_expert_format(um_header_tree, pinfo, &ei_rlc_nr_um_sn, tvb, 0, 0,
633 "Invalid sequence number length (%u bits)",
634 p_rlc_nr_info->sequenceNumberLength);
635 return;
636 }
637 if (seg_info >= 2) {
638 /* Segment offset */
639 proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_nr_um_so, tvb, offset, 2, ENC_BIG_ENDIAN, &so);
640 offset += 2;
641 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " SN=%-6u SO=%-4u", sn, so);
642 } else {
643 /* Seg info is 1, so start of SDU - no SO */
644 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " SN=%-6u ", sn);
645 }
646 }
647 /* End of header */
648 proto_item_set_len(um_header_ti, offset-start_offset);
649
650 if (global_rlc_nr_headers_expected) {
651 /* There might not be any data, if only headers (plus control data) were logged */
652 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
653 truncated_ti = proto_tree_add_boolean(tree, hf_rlc_nr_header_only, tvb, 0, 0,
654 is_truncated);
655 if (is_truncated) {
656 proto_item_set_generated(truncated_ti);
657 expert_add_info(pinfo, truncated_ti, &ei_rlc_nr_header_only);
658 show_PDU_in_info(pinfo, top_ti, p_rlc_nr_info->pduLength - offset, seg_info);
659 return;
660 } else {
661 proto_item_set_hidden(truncated_ti);
662 }
663 }
664
665 /* Data */
666
667 /* Handle any reassembly. */
668 tvbuff_t *next_tvb = NULL;
669 if (global_rlc_nr_reassemble_um_pdus && seg_info && tvb_reported_length_remaining(tvb, offset) > 0) {
670 // Set fragmented flag.
671 gboolean save_fragmented = pinfo->fragmented;
672 pinfo->fragmented = TRUE;
673 fragment_head *fh;
674 gboolean more_frags = seg_info & 0x01;
675 /* TODO: This should be unique enough, but is there a way to get frame number of first frame in reassembly table? */
676 guint32 id = p_rlc_nr_info->direction + /* 1 bit */
677 (p_rlc_nr_info->ueid<<1) + /* 7 bits */
678 (p_rlc_nr_info->bearerId<<8) + /* 5 bits */
679 (sn<<13); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
680
681 fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
682 id, /* id */
683 GUINT_TO_POINTER(id), /* data */
684 so, /* frag_offset */
685 tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
686 more_frags /* more_frags */
687 );
688
689 gboolean update_col_info = TRUE;
690 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
691 fh, &rlc_nr_frag_items,
692 &update_col_info, tree);
693 pinfo->fragmented = save_fragmented;
694 }
695
696 if (tvb_reported_length_remaining(tvb, offset) > 0) {
697 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset),
698 p_rlc_nr_info, seg_info, FALSE);
699 show_PDU_in_info(pinfo, top_ti, tvb_reported_length_remaining(tvb, offset), seg_info);
700
701 /* Also add any reassembled PDU */
702 if (next_tvb) {
703 add_new_data_source(pinfo, next_tvb, "Reassembled RLC-NR PDU");
704 show_PDU_in_tree(pinfo, tree, next_tvb, 0, tvb_captured_length(next_tvb),
705 p_rlc_nr_info, seg_info, TRUE);
706 }
707 } else if (!global_rlc_nr_headers_expected) {
708 /* Report that expected data was missing (unless we know it might happen) */
709 expert_add_info(pinfo, um_header_ti, &ei_rlc_nr_um_data_no_data);
710 }
711 }
712
713
714
715 /* Dissect an AM STATUS PDU */
dissect_rlc_nr_am_status_pdu(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * status_ti,int offset,proto_item * top_ti,rlc_nr_info * p_rlc_nr_info)716 static void dissect_rlc_nr_am_status_pdu(tvbuff_t *tvb,
717 packet_info *pinfo,
718 proto_tree *tree,
719 proto_item *status_ti,
720 int offset,
721 proto_item *top_ti,
722 rlc_nr_info *p_rlc_nr_info)
723 {
724 guint8 sn_size, reserved_bits1, reserved_bits2;
725 guint32 cpt, sn_limit, nack_count = 0;
726 guint64 ack_sn, nack_sn;
727 guint64 e1, e2, e3, reserved;
728 guint32 so_start, so_end, nack_range;
729 int bit_offset = offset << 3;
730 proto_item *ti;
731
732 /****************************************************************/
733 /* Part of RLC control PDU header */
734
735 /* Control PDU Type (CPT) */
736 ti = proto_tree_add_item_ret_uint(tree, hf_rlc_nr_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN, &cpt);
737 if (cpt != 0) {
738 /* Protest and stop - only know about STATUS PDUs */
739 expert_add_info_format(pinfo, ti, &ei_rlc_nr_am_cpt,
740 "RLC Control frame type %u not handled", cpt);
741 return;
742 }
743
744 if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_12_BITS) {
745 sn_size = 12;
746 sn_limit = 4096;
747 reserved_bits1 = 7;
748 reserved_bits2 = 1;
749 } else if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_18_BITS) {
750 sn_size = 18;
751 sn_limit = 262044;
752 reserved_bits1 = 1;
753 reserved_bits2 = 3;
754 } else {
755 proto_tree_add_expert_format(tree, pinfo, &ei_rlc_nr_am_sn, tvb, 0, 0,
756 "Invalid sequence number length (%u bits)",
757 p_rlc_nr_info->sequenceNumberLength);
758 return;
759 }
760
761 /* The Status PDU itself starts 4 bits into the byte */
762 bit_offset += 4;
763
764 /* ACK SN */
765 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_ack_sn, tvb,
766 bit_offset, sn_size, &ack_sn, ENC_BIG_ENDIAN);
767 bit_offset += sn_size;
768 write_pdu_label_and_info(top_ti, status_ti, pinfo, " ACK_SN=%-6u", (guint32)ack_sn);
769
770 /* E1 */
771 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e1, tvb,
772 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
773 bit_offset++;
774
775 /* Reserved bits */
776 ti = proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_reserved, tvb, bit_offset,
777 reserved_bits1, &reserved, ENC_BIG_ENDIAN);
778 bit_offset += reserved_bits1;
779 if (reserved) {
780 expert_add_info(pinfo, ti, &ei_rlc_nr_reserved_bits_not_zero);
781 }
782
783 /* Optional, extra fields */
784 while (e1) {
785 proto_item *nack_ti;
786
787 /****************************/
788 /* Read NACK_SN, E1, E2, E3 */
789
790 /* NACK_SN */
791 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_nack_sn, tvb,
792 bit_offset, sn_size, &nack_sn, ENC_BIG_ENDIAN);
793 bit_offset += sn_size;
794 write_pdu_label_and_info(top_ti, NULL, pinfo, " NACK_SN=%-6u", (guint32)nack_sn);
795
796 /* We shouldn't NACK the ACK_SN! */
797 if (nack_sn == ack_sn) {
798 expert_add_info_format(pinfo, nack_ti, &ei_rlc_nr_am_nack_sn_ack_same,
799 "Status PDU shouldn't ACK and NACK the same sequence number (%" G_GINT64_MODIFIER "u)",
800 ack_sn);
801 }
802
803 /* NACK should always be 'behind' the ACK */
804 if ((sn_limit + ack_sn - nack_sn) % sn_limit > (sn_limit>>1)) {
805 expert_add_info(pinfo, nack_ti, &ei_rlc_nr_am_nack_sn_ahead_ack);
806 }
807
808 nack_count++;
809
810 /* E1 */
811 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e1, tvb,
812 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
813 bit_offset++;
814
815 /* E2 */
816 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e2, tvb,
817 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
818 bit_offset++;
819
820 /* Report as expert info */
821 if (e2) {
822 expert_add_info_format(pinfo, nack_ti, &ei_rlc_nr_am_nack_sn_partial,
823 "Status PDU reports NACK (partial) on %s for UE %u",
824 val_to_str_const(p_rlc_nr_info->direction, direction_vals, "Unknown"),
825 p_rlc_nr_info->ueid);
826 } else {
827 expert_add_info_format(pinfo, nack_ti, &ei_rlc_nr_am_nack_sn,
828 "Status PDU reports NACK on %s for UE %u",
829 val_to_str_const(p_rlc_nr_info->direction, direction_vals, "Unknown"),
830 p_rlc_nr_info->ueid);
831 }
832
833 /* E3 */
834 proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_e3, tvb,
835 bit_offset, 1, &e3, ENC_BIG_ENDIAN);
836 bit_offset++;
837
838 /* Reserved bits */
839 ti = proto_tree_add_bits_ret_val(tree, hf_rlc_nr_am_reserved, tvb, bit_offset,
840 reserved_bits2, &reserved, ENC_BIG_ENDIAN);
841 bit_offset += reserved_bits2;
842 if (reserved) {
843 expert_add_info(pinfo, ti, &ei_rlc_nr_reserved_bits_not_zero);
844 }
845
846 if (e2) {
847 /* Read SOstart, SOend */
848 proto_tree_add_item_ret_uint(tree, hf_rlc_nr_am_so_start, tvb,
849 bit_offset>>3, 2, ENC_BIG_ENDIAN, &so_start);
850 bit_offset += 16;
851
852 proto_tree_add_item_ret_uint(tree, hf_rlc_nr_am_so_end, tvb,
853 bit_offset>>3, 2, ENC_BIG_ENDIAN, &so_end);
854 bit_offset += 16;
855
856
857 if (so_end == 0xffff) {
858 write_pdu_label_and_info(top_ti, NULL, pinfo,
859 " (SOstart=%u SOend=<END-OF_SDU>)",
860 so_start);
861 } else {
862 write_pdu_label_and_info(top_ti, NULL, pinfo,
863 " (SOstart=%u SOend=%u)",
864 so_start, so_end);
865 }
866 }
867
868 if (e3) {
869 proto_item *nack_range_ti;
870
871 /* Read NACK range */
872 nack_range_ti = proto_tree_add_item_ret_uint(tree, hf_rlc_nr_am_nack_range, tvb,
873 bit_offset>>3, 1, ENC_BIG_ENDIAN, &nack_range);
874 bit_offset += 8;
875 if (nack_range == 0) {
876 expert_add_info(pinfo, nack_range_ti, &ei_rlc_nr_am_nack_range);
877 } else {
878 nack_count += nack_range-1;
879 }
880
881 write_pdu_label_and_info(top_ti, NULL, pinfo," NACK range=%u", nack_range);
882 }
883 }
884
885 if (nack_count > 0) {
886 proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_nr_am_nacks, tvb, 0, 1, nack_count);
887 proto_item_set_generated(count_ti);
888 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
889 }
890
891 /* Check that we've reached the end of the PDU. If not, show malformed */
892 offset = (bit_offset+7) / 8;
893 if (tvb_reported_length_remaining(tvb, offset) > 0) {
894 expert_add_info_format(pinfo, status_ti, &ei_rlc_nr_bytes_after_status_pdu_complete,
895 "%cL %u bytes remaining after Status PDU complete",
896 (p_rlc_nr_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
897 tvb_reported_length_remaining(tvb, offset));
898 }
899
900 /* Set selected length of control tree */
901 proto_item_set_len(status_ti, offset);
902 }
903
904
905 /***************************************************/
906 /* Acknowledged mode PDU */
dissect_rlc_nr_am(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,int offset,rlc_nr_info * p_rlc_nr_info,proto_item * top_ti)907 static void dissect_rlc_nr_am(tvbuff_t *tvb, packet_info *pinfo,
908 proto_tree *tree,
909 int offset,
910 rlc_nr_info *p_rlc_nr_info,
911 proto_item *top_ti)
912 {
913 gboolean dc, polling;
914 guint32 seg_info, sn;
915 guint64 reserved;
916 proto_item *am_ti;
917 proto_tree *am_header_tree;
918 proto_item *am_header_ti;
919 gint start_offset = offset;
920 gboolean is_truncated = FALSE;
921 proto_item *truncated_ti;
922 proto_item *reserved_ti;
923 guint32 so = 0;
924
925 /* Hidden AM root */
926 am_ti = proto_tree_add_string_format(tree, hf_rlc_nr_am,
927 tvb, offset, 0, "", "AM");
928 proto_item_set_hidden(am_ti);
929
930 /* Add AM header subtree */
931 am_header_ti = proto_tree_add_string_format(tree, hf_rlc_nr_am_header,
932 tvb, offset, 0,
933 "", "AM Header ");
934 am_header_tree = proto_item_add_subtree(am_header_ti,
935 ett_rlc_nr_am_header);
936
937 /* First bit is Data/Control flag */
938 proto_tree_add_item_ret_boolean(am_header_tree, hf_rlc_nr_am_data_control,
939 tvb, offset, 1, ENC_BIG_ENDIAN, &dc);
940
941 if (dc == 0) {
942 /**********************/
943 /* Status PDU */
944 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
945
946 /* Control PDUs are a completely separate format */
947 dissect_rlc_nr_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
948 offset, top_ti, p_rlc_nr_info);
949 return;
950 }
951
952 /**********************/
953 /* Data PDU */
954 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [DATA]");
955
956 /* Polling bit */
957 proto_tree_add_item_ret_boolean(am_header_tree, hf_rlc_nr_am_p, tvb,
958 offset, 1, ENC_BIG_ENDIAN, &polling);
959
960 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : " ");
961 if (polling) {
962 proto_item_append_text(am_header_ti, " (P) ");
963 }
964
965 /* Segmentation Info */
966 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_nr_am_si, tvb,
967 offset, 1, ENC_BIG_ENDIAN, &seg_info);
968
969 /* Sequence Number */
970 if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_12_BITS) {
971 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_nr_am_sn12, tvb,
972 offset, 2, ENC_BIG_ENDIAN, &sn);
973 offset += 2;
974 } else if (p_rlc_nr_info->sequenceNumberLength == AM_SN_LENGTH_18_BITS) {
975 reserved_ti = proto_tree_add_bits_ret_val(am_header_tree, hf_rlc_nr_am_reserved, tvb,
976 (offset<<3)+4, 2, &reserved, ENC_BIG_ENDIAN);
977 if (reserved) {
978 expert_add_info(pinfo, reserved_ti, &ei_rlc_nr_reserved_bits_not_zero);
979 }
980 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_nr_am_sn18, tvb,
981 offset, 3, ENC_BIG_ENDIAN, &sn);
982 offset += 3;
983 } else {
984 /* Invalid length of sequence number */
985 proto_tree_add_expert_format(am_header_tree, pinfo, &ei_rlc_nr_am_sn, tvb, 0, 0,
986 "Invalid sequence number length (%u bits)",
987 p_rlc_nr_info->sequenceNumberLength);
988 return;
989 }
990
991 /* Segment Offset */
992 if (seg_info >= 2) {
993 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_nr_am_so, tvb,
994 offset, 2, ENC_BIG_ENDIAN, &so);
995 offset += 2;
996 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "SN=%-6u SO=%-4u",sn, so);
997 } else {
998 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "SN=%-6u ", sn);
999 }
1000
1001 /* Header is now complete */
1002 proto_item_set_len(am_header_ti, offset-start_offset);
1003
1004 /* There might not be any data, if only headers (plus control data) were logged */
1005 if (global_rlc_nr_headers_expected) {
1006 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
1007 truncated_ti = proto_tree_add_boolean(tree, hf_rlc_nr_header_only, tvb, 0, 0,
1008 is_truncated);
1009 if (is_truncated) {
1010 proto_item_set_generated(truncated_ti);
1011 expert_add_info(pinfo, truncated_ti, &ei_rlc_nr_header_only);
1012 show_PDU_in_info(pinfo, top_ti, p_rlc_nr_info->pduLength - offset, seg_info);
1013 return;
1014 } else {
1015 proto_item_set_hidden(truncated_ti);
1016 }
1017 }
1018
1019 /* Data */
1020
1021 /* Handle any reassembly. */
1022 tvbuff_t *next_tvb = NULL;
1023 if (global_rlc_nr_reassemble_am_pdus && seg_info && tvb_reported_length_remaining(tvb, offset) > 0) {
1024 // Set fragmented flag.
1025 gboolean save_fragmented = pinfo->fragmented;
1026 pinfo->fragmented = TRUE;
1027 fragment_head *fh;
1028 gboolean more_frags = seg_info & 0x01;
1029 /* TODO: This should be unique enough, but is there a way to get frame number of first frame in reassembly table? */
1030 guint32 id = p_rlc_nr_info->direction + /* 1 bit */
1031 (p_rlc_nr_info->ueid<<1) + /* 7 bits */
1032 (p_rlc_nr_info->bearerId<<8) + /* 5 bits */
1033 (sn<<13); /* Leave 19 bits for SN - overlaps with other fields but room to overflow into msb */
1034
1035 fh = fragment_add(&pdu_reassembly_table, tvb, offset, pinfo,
1036 id, /* id */
1037 GUINT_TO_POINTER(id), /* data */
1038 so, /* frag_offset */
1039 tvb_reported_length_remaining(tvb, offset), /* frag_data_len */
1040 more_frags /* more_frags */
1041 );
1042
1043 gboolean update_col_info = TRUE;
1044 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled RLC SDU",
1045 fh, &rlc_nr_frag_items,
1046 &update_col_info, tree);
1047 pinfo->fragmented = save_fragmented;
1048 }
1049
1050
1051 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1052 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset),
1053 p_rlc_nr_info, seg_info, FALSE);
1054 show_PDU_in_info(pinfo, top_ti, tvb_reported_length_remaining(tvb, offset), seg_info);
1055
1056 /* Also add any reassembled PDU */
1057 if (next_tvb) {
1058 add_new_data_source(pinfo, next_tvb, "Reassembled RLC-NR PDU");
1059 show_PDU_in_tree(pinfo, tree, next_tvb, 0, tvb_captured_length(next_tvb),
1060 p_rlc_nr_info, seg_info, TRUE);
1061 }
1062 } else if (!global_rlc_nr_headers_expected) {
1063 /* Report that expected data was missing (unless we know it might happen) */
1064 expert_add_info(pinfo, am_header_ti, &ei_rlc_nr_am_data_no_data);
1065 }
1066 }
1067
1068
1069 /* Heuristic dissector looks for supported framing protocol (see header file for details) */
dissect_rlc_nr_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1070 static gboolean dissect_rlc_nr_heur(tvbuff_t *tvb, packet_info *pinfo,
1071 proto_tree *tree, void *data _U_)
1072 {
1073 gint offset = 0;
1074 rlc_nr_info *p_rlc_nr_info;
1075 tvbuff_t *rlc_tvb;
1076 guint8 tag;
1077
1078 /* Do this again on re-dissection to re-discover offset of actual PDU */
1079
1080 /* Needs to be at least as long as:
1081 - the signature string
1082 - fixed header bytes
1083 - tag for data
1084 - at least one byte of RLC PDU payload */
1085 if (tvb_captured_length_remaining(tvb, offset) < (gint)(strlen(RLC_NR_START_STRING)+2+2)) {
1086 return FALSE;
1087 }
1088
1089 /* OK, compare with signature string */
1090 if (tvb_strneql(tvb, offset, RLC_NR_START_STRING, (gint)strlen(RLC_NR_START_STRING)) != 0) {
1091 return FALSE;
1092 }
1093 offset += (gint)strlen(RLC_NR_START_STRING);
1094
1095
1096 /* If redissecting, use previous info struct (if available) */
1097 p_rlc_nr_info = (rlc_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0);
1098 if (p_rlc_nr_info == NULL) {
1099 /* Allocate new info struct for this frame */
1100 p_rlc_nr_info = wmem_new0(wmem_file_scope(), struct rlc_nr_info);
1101
1102 /* Read fixed fields */
1103 p_rlc_nr_info->rlcMode = tvb_get_guint8(tvb, offset++);
1104 p_rlc_nr_info->sequenceNumberLength = tvb_get_guint8(tvb, offset++);
1105
1106 /* Read optional fields */
1107 do {
1108 /* Process next tag */
1109 tag = tvb_get_guint8(tvb, offset++);
1110 switch (tag) {
1111 case RLC_NR_DIRECTION_TAG:
1112 p_rlc_nr_info->direction = tvb_get_guint8(tvb, offset);
1113 offset++;
1114 break;
1115 case RLC_NR_UEID_TAG:
1116 p_rlc_nr_info->ueid = tvb_get_ntohs(tvb, offset);
1117 offset += 2;
1118 break;
1119 case RLC_NR_BEARER_TYPE_TAG:
1120 p_rlc_nr_info->bearerType = tvb_get_guint8(tvb, offset);
1121 offset++;
1122 break;
1123 case RLC_NR_BEARER_ID_TAG:
1124 p_rlc_nr_info->bearerId = tvb_get_guint8(tvb, offset);
1125 offset++;
1126 break;
1127 case RLC_NR_PAYLOAD_TAG:
1128 /* Have reached data, so set payload length and get out of loop */
1129 p_rlc_nr_info->pduLength = tvb_reported_length_remaining(tvb, offset);
1130 break;
1131 default:
1132 /* It must be a recognised tag */
1133 {
1134 proto_item *ti;
1135 proto_tree *subtree;
1136
1137 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-NR");
1138 col_clear(pinfo->cinfo, COL_INFO);
1139 ti = proto_tree_add_item(tree, proto_rlc_nr, tvb, offset, tvb_reported_length(tvb), ENC_NA);
1140 subtree = proto_item_add_subtree(ti, ett_rlc_nr);
1141 proto_tree_add_expert(subtree, pinfo, &ei_rlc_nr_unknown_udp_framing_tag,
1142 tvb, offset-1, 1);
1143 }
1144 wmem_free(wmem_file_scope(), p_rlc_nr_info);
1145 return TRUE;
1146 }
1147 } while (tag != RLC_NR_PAYLOAD_TAG);
1148
1149 /* Store info in packet */
1150 p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0, p_rlc_nr_info);
1151 } else {
1152 offset = tvb_reported_length(tvb) - p_rlc_nr_info->pduLength;
1153 }
1154
1155 /**************************************/
1156 /* OK, now dissect as RLC NR */
1157
1158 /* Create tvb that starts at actual RLC PDU */
1159 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
1160 dissect_rlc_nr_common(rlc_tvb, pinfo, tree, TRUE);
1161 return TRUE;
1162 }
1163
1164 /*****************************/
1165 /* Main dissection function. */
1166 /*****************************/
1167
dissect_rlc_nr(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1168 static int dissect_rlc_nr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1169 {
1170 dissect_rlc_nr_common(tvb, pinfo, tree, FALSE);
1171 return tvb_captured_length(tvb);
1172 }
1173
dissect_rlc_nr_common(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gboolean is_udp_framing)1174 static void dissect_rlc_nr_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing)
1175 {
1176 proto_tree *rlc_nr_tree;
1177 proto_tree *context_tree;
1178 proto_item *top_ti;
1179 proto_item *context_ti;
1180 proto_item *ti;
1181 proto_item *mode_ti;
1182 gint offset = 0;
1183 struct rlc_nr_info *p_rlc_nr_info;
1184
1185 /* Set protocol name */
1186 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-NR");
1187
1188 /* Create protocol tree. */
1189 top_ti = proto_tree_add_item(tree, proto_rlc_nr, tvb, offset, -1, ENC_NA);
1190 rlc_nr_tree = proto_item_add_subtree(top_ti, ett_rlc_nr);
1191
1192
1193 /* Look for packet info! */
1194 p_rlc_nr_info = (rlc_nr_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_nr, 0);
1195
1196 /* Can't dissect anything without it... */
1197 if (p_rlc_nr_info == NULL) {
1198 proto_tree_add_expert(rlc_nr_tree, pinfo, &ei_rlc_nr_no_per_frame_info, tvb, offset, -1);
1199 return;
1200 }
1201
1202 /* Clear info column when using UDP framing */
1203 if (is_udp_framing) {
1204 col_clear(pinfo->cinfo, COL_INFO);
1205 }
1206
1207 /*****************************************/
1208 /* Show context information */
1209
1210 /* Create context root */
1211 context_ti = proto_tree_add_string_format(rlc_nr_tree, hf_rlc_nr_context,
1212 tvb, offset, 0, "", "Context");
1213 context_tree = proto_item_add_subtree(context_ti, ett_rlc_nr_context);
1214 proto_item_set_generated(context_ti);
1215
1216 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_direction,
1217 tvb, 0, 0, p_rlc_nr_info->direction);
1218 proto_item_set_generated(ti);
1219
1220 mode_ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_mode,
1221 tvb, 0, 0, p_rlc_nr_info->rlcMode);
1222 proto_item_set_generated(mode_ti);
1223
1224 if (p_rlc_nr_info->ueid != 0) {
1225 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_ueid,
1226 tvb, 0, 0, p_rlc_nr_info->ueid);
1227 proto_item_set_generated(ti);
1228 }
1229
1230 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_bearer_type,
1231 tvb, 0, 0, p_rlc_nr_info->bearerType);
1232 proto_item_set_generated(ti);
1233
1234 if ((p_rlc_nr_info->bearerType == BEARER_TYPE_SRB) ||
1235 (p_rlc_nr_info->bearerType == BEARER_TYPE_DRB)) {
1236 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_bearer_id,
1237 tvb, 0, 0, p_rlc_nr_info->bearerId);
1238 proto_item_set_generated(ti);
1239 }
1240
1241 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_pdu_length,
1242 tvb, 0, 0, p_rlc_nr_info->pduLength);
1243 proto_item_set_generated(ti);
1244
1245 if (p_rlc_nr_info->rlcMode != RLC_TM_MODE) {
1246 ti = proto_tree_add_uint(context_tree, hf_rlc_nr_context_sn_length,
1247 tvb, 0, 0, p_rlc_nr_info->sequenceNumberLength);
1248 proto_item_set_generated(ti);
1249 }
1250
1251 /* Append highlights to top-level item */
1252 if (p_rlc_nr_info->ueid != 0) {
1253 proto_item_append_text(top_ti, " UEId=%u", p_rlc_nr_info->ueid);
1254 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%-4u ", p_rlc_nr_info->ueid);
1255 }
1256
1257 /* Append context highlights to info column */
1258 write_pdu_label_and_info(top_ti, NULL, pinfo,
1259 " [%s] [%s] ",
1260 (p_rlc_nr_info->direction == 0) ? "UL" : "DL",
1261 val_to_str_const(p_rlc_nr_info->rlcMode, rlc_mode_short_vals, "Unknown"));
1262
1263 if (p_rlc_nr_info->bearerId == 0) {
1264 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s ",
1265 val_to_str_const(p_rlc_nr_info->bearerType, rlc_bearer_type_vals, "Unknown"));
1266 } else {
1267 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
1268 val_to_str_const(p_rlc_nr_info->bearerType, rlc_bearer_type_vals, "Unknown"),
1269 p_rlc_nr_info->bearerId);
1270 }
1271
1272 /* Dissect the RLC PDU itself. Format depends upon mode... */
1273 switch (p_rlc_nr_info->rlcMode) {
1274
1275 case RLC_TM_MODE:
1276 dissect_rlc_nr_tm(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti);
1277 break;
1278
1279 case RLC_UM_MODE:
1280 dissect_rlc_nr_um(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti);
1281 break;
1282
1283 case RLC_AM_MODE:
1284 dissect_rlc_nr_am(tvb, pinfo, rlc_nr_tree, offset, p_rlc_nr_info, top_ti);
1285 break;
1286
1287 default:
1288 /* Error - unrecognised mode */
1289 expert_add_info_format(pinfo, mode_ti, &ei_rlc_nr_context_mode,
1290 "Unrecognised RLC Mode set (%u)", p_rlc_nr_info->rlcMode);
1291 break;
1292 }
1293 }
1294
1295
1296 /* Configure DRB PDCP channel properties. */
set_rlc_nr_drb_pdcp_mapping(packet_info * pinfo,nr_drb_rlc_pdcp_mapping_t * drb_mapping)1297 void set_rlc_nr_drb_pdcp_mapping(packet_info *pinfo,
1298 nr_drb_rlc_pdcp_mapping_t *drb_mapping)
1299 {
1300 wmem_tree_key_t key[2];
1301 guint32 id;
1302 pdcp_bearer_parameters *params;
1303
1304 if (PINFO_FD_VISITED(pinfo)) {
1305 return;
1306 }
1307
1308 id = (drb_mapping->drbid << 16) | drb_mapping->ueid;
1309 key[0].length = 1;
1310 key[0].key = &id;
1311 key[1].length = 0;
1312 key[1].key = NULL;
1313
1314 /* Look up entry for this UEId/drbid */
1315 params = (pdcp_bearer_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
1316 if (params && (params->id != id)) {
1317 params = NULL;
1318 }
1319 if (params == NULL) {
1320 /* Not found so create new entry */
1321 params = (pdcp_bearer_parameters *)wmem_new(wmem_file_scope(), pdcp_bearer_parameters);
1322 params->id = id;
1323 wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
1324 }
1325
1326 /* Populate params */
1327 params->pdcp_sn_bits_ul = drb_mapping->pdcpUlSnLength;
1328 params->pdcp_sn_bits_dl = drb_mapping->pdcpDlSnLength;
1329 params->pdcp_sdap_ul = drb_mapping->pdcpUlSdap;
1330 params->pdcp_sdap_dl = drb_mapping->pdcpDlSdap;
1331 params->pdcp_integrity = drb_mapping->pdcpIntegrityProtection;
1332 params->pdcp_ciphering_disabled = drb_mapping->pdcpCipheringDisabled;
1333 }
1334
get_rlc_nr_drb_pdcp_mapping(guint16 ue_id,guint8 drb_id)1335 pdcp_bearer_parameters* get_rlc_nr_drb_pdcp_mapping(guint16 ue_id, guint8 drb_id)
1336 {
1337 wmem_tree_key_t key[2];
1338 guint32 id;
1339 pdcp_bearer_parameters *params;
1340
1341 id = (drb_id << 16) | ue_id;
1342 key[0].length = 1;
1343 key[0].key = &id;
1344 key[1].length = 0;
1345 key[1].key = NULL;
1346
1347 /* Look up configured params for this PDCP DRB. */
1348 params = (pdcp_bearer_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
1349 if (params && (params->id != id)) {
1350 params = NULL;
1351 }
1352
1353 return params;
1354 }
1355
1356
proto_register_rlc_nr(void)1357 void proto_register_rlc_nr(void)
1358 {
1359 static hf_register_info hf[] =
1360 {
1361 /**********************************/
1362 /* Items for decoding context */
1363 { &hf_rlc_nr_context,
1364 { "Context",
1365 "rlc-nr.context", FT_STRING, BASE_NONE, NULL, 0x0,
1366 NULL, HFILL
1367 }
1368 },
1369 { &hf_rlc_nr_context_mode,
1370 { "RLC Mode",
1371 "rlc-nr.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
1372 NULL, HFILL
1373 }
1374 },
1375 { &hf_rlc_nr_context_direction,
1376 { "Direction",
1377 "rlc-nr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1378 "Direction of message", HFILL
1379 }
1380 },
1381 { &hf_rlc_nr_context_ueid,
1382 { "UEId",
1383 "rlc-nr.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
1384 "User Equipment Identifier associated with message", HFILL
1385 }
1386 },
1387 { &hf_rlc_nr_context_bearer_type,
1388 { "Bearer Type",
1389 "rlc-nr.bearer-type", FT_UINT16, BASE_DEC, VALS(rlc_bearer_type_vals), 0x0,
1390 "Bearer Type associated with message", HFILL
1391 }
1392 },
1393 { &hf_rlc_nr_context_bearer_id,
1394 { "Bearer Id",
1395 "rlc-nr.bearer-id", FT_UINT16, BASE_DEC, 0, 0x0,
1396 "Bearer ID associated with message", HFILL
1397 }
1398 },
1399 { &hf_rlc_nr_context_pdu_length,
1400 { "PDU Length",
1401 "rlc-nr.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
1402 "Length of PDU (in bytes)", HFILL
1403 }
1404 },
1405 { &hf_rlc_nr_context_sn_length,
1406 { "Sequence Number length",
1407 "rlc-nr.seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
1408 "Length of sequence number in bits", HFILL
1409 }
1410 },
1411
1412 /* Transparent mode fields */
1413 { &hf_rlc_nr_tm,
1414 { "TM",
1415 "rlc-nr.tm", FT_STRING, BASE_NONE, NULL, 0x0,
1416 "Transparent Mode", HFILL
1417 }
1418 },
1419 { &hf_rlc_nr_tm_data,
1420 { "TM Data",
1421 "rlc-nr.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
1422 "Transparent Mode Data", HFILL
1423 }
1424 },
1425
1426 /* Unacknowledged mode fields */
1427 { &hf_rlc_nr_um,
1428 { "UM",
1429 "rlc-nr.um", FT_STRING, BASE_NONE, NULL, 0x0,
1430 "Unacknowledged Mode", HFILL
1431 }
1432 },
1433 { &hf_rlc_nr_um_header,
1434 { "UM Header",
1435 "rlc-nr.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
1436 "Unacknowledged Mode Header", HFILL
1437 }
1438 },
1439 { &hf_rlc_nr_um_si,
1440 { "Segmentation Info",
1441 "rlc-nr.um.si", FT_UINT8, BASE_HEX, VALS(seg_info_vals), 0xc0,
1442 NULL, HFILL
1443 }
1444 },
1445 { &hf_rlc_nr_um_reserved,
1446 { "Reserved",
1447 "rlc-nr.um.reserved", FT_UINT8, BASE_HEX, 0, 0x0,
1448 NULL, HFILL
1449 }
1450 },
1451 { &hf_rlc_nr_um_sn6,
1452 { "Sequence Number",
1453 "rlc-nr.um.sn", FT_UINT8, BASE_DEC, 0, 0x3f,
1454 NULL, HFILL
1455 }
1456 },
1457 { &hf_rlc_nr_um_sn12,
1458 { "Sequence Number",
1459 "rlc-nr.um.sn", FT_UINT16, BASE_DEC, 0, 0x0fff,
1460 NULL, HFILL
1461 }
1462 },
1463 { &hf_rlc_nr_um_so,
1464 { "Segment Offset",
1465 "rlc-nr.um.so", FT_UINT16, BASE_DEC, 0, 0x0,
1466 NULL, HFILL
1467 }
1468 },
1469 { &hf_rlc_nr_um_data,
1470 { "UM Data",
1471 "rlc-nr.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
1472 "Unacknowledged Mode Data", HFILL
1473 }
1474 },
1475
1476 /* Acknowledged mode fields */
1477 { &hf_rlc_nr_am,
1478 { "AM",
1479 "rlc-nr.am", FT_STRING, BASE_NONE, NULL, 0x0,
1480 "Acknowledged Mode", HFILL
1481 }
1482 },
1483 { &hf_rlc_nr_am_header,
1484 { "AM Header",
1485 "rlc-nr.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
1486 "Acknowledged Mode Header", HFILL
1487 }
1488 },
1489 { &hf_rlc_nr_am_data_control,
1490 { "Data/Control",
1491 "rlc-nr.am.dc", FT_BOOLEAN, 8, TFS(&data_or_control_vals), 0x80,
1492 NULL, HFILL
1493 }
1494 },
1495 { &hf_rlc_nr_am_p,
1496 { "Polling Bit",
1497 "rlc-nr.am.p", FT_BOOLEAN, 8, TFS(&polling_bit_vals), 0x40,
1498 NULL, HFILL
1499 }
1500 },
1501 { &hf_rlc_nr_am_si,
1502 { "Segmentation Info",
1503 "rlc-nr.am.si", FT_UINT8, BASE_HEX, VALS(seg_info_vals), 0x30,
1504 NULL, HFILL
1505 }
1506 },
1507 { &hf_rlc_nr_am_sn12,
1508 { "Sequence Number",
1509 "rlc-nr.am.sn", FT_UINT16, BASE_DEC, 0, 0x0fff,
1510 NULL, HFILL
1511 }
1512 },
1513 { &hf_rlc_nr_am_sn18,
1514 { "Sequence Number",
1515 "rlc-nr.am.sn", FT_UINT24, BASE_DEC, 0, 0x03ffff,
1516 NULL, HFILL
1517 }
1518 },
1519 { &hf_rlc_nr_am_reserved,
1520 { "Reserved",
1521 "rlc-nr.am.reserved", FT_UINT8, BASE_HEX, 0, 0x0,
1522 NULL, HFILL
1523 }
1524 },
1525 { &hf_rlc_nr_am_so,
1526 { "Segment Offset",
1527 "rlc-nr.am.so", FT_UINT16, BASE_DEC, 0, 0x0,
1528 NULL, HFILL
1529 }
1530 },
1531 { &hf_rlc_nr_am_data,
1532 { "AM Data",
1533 "rlc-nr.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
1534 "Acknowledged Mode Data", HFILL
1535 }
1536 },
1537
1538 { &hf_rlc_nr_am_cpt,
1539 { "Control PDU Type",
1540 "rlc-nr.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
1541 "AM Control PDU Type", HFILL
1542 }
1543 },
1544 { &hf_rlc_nr_am_ack_sn,
1545 { "ACK Sequence Number",
1546 "rlc-nr.am.ack-sn", FT_UINT24, BASE_DEC, 0, 0x0,
1547 "Sequence Number we expect to receive next", HFILL
1548 }
1549 },
1550 { &hf_rlc_nr_am_e1,
1551 { "Extension bit 1",
1552 "rlc-nr.am.e1", FT_BOOLEAN, BASE_NONE, TFS(&am_e1_vals), 0x0,
1553 NULL, HFILL
1554 }
1555 },
1556 { &hf_rlc_nr_am_e2,
1557 { "Extension bit 2",
1558 "rlc-nr.am.e2", FT_BOOLEAN, BASE_NONE, TFS(&am_e2_vals), 0x0,
1559 NULL, HFILL
1560 }
1561 },
1562 { &hf_rlc_nr_am_e3,
1563 { "Extension bit 3",
1564 "rlc-nr.am.e3", FT_BOOLEAN, BASE_NONE, TFS(&am_e3_vals), 0x0,
1565 NULL, HFILL
1566 }
1567 },
1568 { &hf_rlc_nr_am_nacks,
1569 { "Number of NACKs",
1570 "rlc-nr.am.nacks", FT_UINT32, BASE_DEC, 0, 0x0,
1571 "Number of NACKs in this status PDU", HFILL
1572 }
1573 },
1574 { &hf_rlc_nr_am_nack_sn,
1575 { "NACK Sequence Number",
1576 "rlc-nr.am.nack-sn", FT_UINT24, BASE_DEC, 0, 0x0,
1577 "Negative Acknowledgement Sequence Number", HFILL
1578 }
1579 },
1580 { &hf_rlc_nr_am_so_start,
1581 { "SO start",
1582 "rlc-nr.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
1583 "Segment Offset Start byte index", HFILL
1584 }
1585 },
1586 { &hf_rlc_nr_am_so_end,
1587 { "SO end",
1588 "rlc-nr.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
1589 "Segment Offset End byte index", HFILL
1590 }
1591 },
1592 { &hf_rlc_nr_am_nack_range,
1593 { "NACK range",
1594 "rlc-nr.am.nack-range", FT_UINT16, BASE_DEC, 0, 0x0,
1595 "Number of consecutively lost RLC SDUs starting from and including NACK_SN", HFILL
1596 }
1597 },
1598
1599 { &hf_rlc_nr_header_only,
1600 { "RLC PDU Header only",
1601 "rlc-nr.header-only", FT_BOOLEAN, BASE_NONE, TFS(&header_only_vals), 0x0,
1602 NULL, HFILL
1603 }
1604 },
1605
1606 { &hf_rlc_nr_fragment,
1607 { "RLC-NR fragment",
1608 "rlc-nr.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1609 NULL, HFILL }
1610 },
1611 { &hf_rlc_nr_fragments,
1612 { "RLC-NR fragments",
1613 "rlc-nr.fragments", FT_BYTES, BASE_NONE, NULL, 0x0,
1614 NULL, HFILL }
1615 },
1616 { &hf_rlc_nr_fragment_overlap,
1617 { "Fragment overlap",
1618 "rlc-nr.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1619 "Fragment overlaps with other fragments", HFILL }
1620 },
1621 { &hf_rlc_nr_fragment_overlap_conflict,
1622 { "Conflicting data in fragment overlap",
1623 "rlc-nr.fragment.overlap.conflict",
1624 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1625 "Overlapping fragments contained conflicting data", HFILL }
1626 },
1627 { &hf_rlc_nr_fragment_multiple_tails,
1628 { "Multiple tail fragments found",
1629 "rlc-nr.fragment.multipletails",
1630 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1631 "Several tails were found when defragmenting the packet", HFILL }
1632 },
1633 { &hf_rlc_nr_fragment_too_long_fragment,
1634 { "Fragment too long",
1635 "rlc-nr.fragment.toolongfragment",
1636 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1637 "Fragment contained data past end of packet", HFILL }
1638 },
1639 { &hf_rlc_nr_fragment_error,
1640 { "Defragmentation error",
1641 "rlc-nr.fragment.error",
1642 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1643 "Defragmentation error due to illegal fragments", HFILL }
1644 },
1645 { &hf_rlc_nr_fragment_count,
1646 { "Fragment count",
1647 "rlc-nr.fragment.count",
1648 FT_UINT32, BASE_DEC, NULL, 0x0,
1649 NULL, HFILL }
1650 },
1651 { &hf_rlc_nr_reassembled_in,
1652 { "Reassembled RLC-NR in frame",
1653 "rlc-nr.reassembled_in",
1654 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1655 "This RLC-NR packet is reassembled in this frame", HFILL }
1656 },
1657 { &hf_rlc_nr_reassembled_length,
1658 { "Reassembled RLC-NR length",
1659 "rlc-nr.reassembled.length",
1660 FT_UINT32, BASE_DEC, NULL, 0x0,
1661 "The total length of the reassembled payload", HFILL }
1662 },
1663 { &hf_rlc_nr_reassembled_data,
1664 { "Reassembled payload",
1665 "rlc-nr.reassembled.data",
1666 FT_BYTES, BASE_NONE, NULL, 0x0,
1667 "The reassembled payload", HFILL }
1668 },
1669
1670 };
1671
1672 static gint *ett[] =
1673 {
1674 &ett_rlc_nr,
1675 &ett_rlc_nr_context,
1676 &ett_rlc_nr_um_header,
1677 &ett_rlc_nr_am_header,
1678 &ett_rlc_nr_fragment,
1679 &ett_rlc_nr_fragments
1680 };
1681
1682 static ei_register_info ei[] = {
1683 { &ei_rlc_nr_reserved_bits_not_zero, { "rlc-nr.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
1684 { &ei_rlc_nr_um_sn, { "rlc-nr.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
1685 { &ei_rlc_nr_am_sn, { "rlc-nr.am.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
1686 { &ei_rlc_nr_header_only, { "rlc-nr.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
1687 { &ei_rlc_nr_am_cpt, { "rlc-nr.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
1688 { &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 }},
1689 { &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 }},
1690 { &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 }},
1691 { &ei_rlc_nr_am_nack_sn_partial, { "rlc-nr.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
1692 { &ei_rlc_nr_am_nack_sn, { "rlc-nr.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
1693 { &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 }},
1694 { &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 }},
1695 { &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 }},
1696 { &ei_rlc_nr_context_mode, { "rlc-nr.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
1697 { &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 }},
1698 { &ei_rlc_nr_unknown_udp_framing_tag, { "rlc-nr.unknown-udp-framing-tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }}
1699 };
1700
1701 module_t *rlc_nr_module;
1702 expert_module_t* expert_rlc_nr;
1703
1704 /* Register protocol. */
1705 proto_rlc_nr = proto_register_protocol("RLC-NR", "RLC-NR", "rlc-nr");
1706 proto_register_field_array(proto_rlc_nr, hf, array_length(hf));
1707 proto_register_subtree_array(ett, array_length(ett));
1708 expert_rlc_nr = expert_register_protocol(proto_rlc_nr);
1709 expert_register_field_array(expert_rlc_nr, ei, array_length(ei));
1710
1711 /* Allow other dissectors to find this one by name. */
1712 register_dissector("rlc-nr", dissect_rlc_nr, proto_rlc_nr);
1713
1714 /* Preferences */
1715 rlc_nr_module = prefs_register_protocol(proto_rlc_nr, NULL);
1716
1717 prefs_register_bool_preference(rlc_nr_module, "call_pdcp_for_srb",
1718 "Call PDCP dissector for SRB PDUs",
1719 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
1720 "only be called for complete PDUs (i.e. not segmented over RLC)",
1721 &global_rlc_nr_call_pdcp_for_srb);
1722
1723 prefs_register_enum_preference(rlc_nr_module, "call_pdcp_for_ul_drb",
1724 "Call PDCP dissector for UL DRB PDUs",
1725 "Call PDCP dissector for UL user-plane PDUs. Note that without reassembly, it can"
1726 "only be called for complete PDUs (i.e. not segmented over RLC)",
1727 &global_rlc_nr_call_pdcp_for_ul_drb, pdcp_drb_col_vals, FALSE);
1728
1729 prefs_register_enum_preference(rlc_nr_module, "call_pdcp_for_dl_drb",
1730 "Call PDCP dissector for DL DRB PDUs",
1731 "Call PDCP dissector for DL user-plane PDUs. Note that without reassembly, it can"
1732 "only be called for complete PDUs (i.e. not segmented over RLC)",
1733 &global_rlc_nr_call_pdcp_for_dl_drb, pdcp_drb_col_vals, FALSE);
1734
1735 prefs_register_bool_preference(rlc_nr_module, "call_rrc_for_ccch",
1736 "Call RRC dissector for CCCH PDUs",
1737 "Call RRC dissector for CCCH PDUs",
1738 &global_rlc_nr_call_rrc_for_ccch);
1739
1740 prefs_register_bool_preference(rlc_nr_module, "header_only_mode",
1741 "May see RLC headers only",
1742 "When enabled, if data is not present, don't report as an error, but instead "
1743 "add expert info to indicate that headers were omitted",
1744 &global_rlc_nr_headers_expected);
1745
1746 prefs_register_bool_preference(rlc_nr_module, "reassemble_am_frames",
1747 "Try to reassemble AM frames",
1748 "N.B. This should be considered experimental/incomplete, in that it doesn't try to discard reassembled state "
1749 "when reestablishment happens, or in certain packet-loss cases",
1750 &global_rlc_nr_reassemble_am_pdus);
1751
1752 prefs_register_bool_preference(rlc_nr_module, "reassemble_um_frames",
1753 "Try to reassemble UM frames",
1754 "N.B. This should be considered experimental/incomplete, in that it doesn't try to discard reassembled state "
1755 "when reestablishment happens, or in certain packet-loss cases",
1756 &global_rlc_nr_reassemble_um_pdus);
1757
1758 ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1759
1760 /* Register reassembly table. */
1761 reassembly_table_register(&pdu_reassembly_table, &pdu_reassembly_table_functions);
1762 }
1763
proto_reg_handoff_rlc_nr(void)1764 void proto_reg_handoff_rlc_nr(void)
1765 {
1766 /* Add as a heuristic UDP dissector */
1767 heur_dissector_add("udp", dissect_rlc_nr_heur, "RLC-NR over UDP", "rlc_nr_udp", proto_rlc_nr, HEURISTIC_DISABLE);
1768
1769 pdcp_nr_handle = find_dissector("pdcp-nr");
1770 nr_rrc_bcch_bch = find_dissector_add_dependency("nr-rrc.bcch.bch", proto_rlc_nr);
1771 nr_rrc_bcch_dl_sch = find_dissector_add_dependency("nr-rrc.bcch.dl.sch", proto_rlc_nr);
1772 nr_rrc_pcch = find_dissector_add_dependency("nr-rrc.pcch", proto_pdcp_nr);
1773 nr_rrc_ul_ccch = find_dissector_add_dependency("nr-rrc.ul.ccch", proto_rlc_nr);
1774 nr_rrc_ul_ccch1 = find_dissector_add_dependency("nr-rrc.ul.ccch1", proto_rlc_nr);
1775 nr_rrc_dl_ccch = find_dissector_add_dependency("nr-rrc.dl.ccch", proto_rlc_nr);
1776 }
1777
1778 /*
1779 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1780 *
1781 * Local variables:
1782 * c-basic-offset: 4
1783 * tab-width: 8
1784 * indent-tabs-mode: nil
1785 * End:
1786 *
1787 * vi: set shiftwidth=4 tabstop=8 expandtab:
1788 * :indentSize=4:tabSize=8:noTabs=true:
1789 */
1790