Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rlc-lte.c
blob5dfdea7ae2c69d5acef401c11ec6b52c372f8318
1 /* Routines for LTE RLC disassembly
3 * Martin Mathieson
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/tfs.h>
21 #include <wsutil/array.h>
22 #include "packet-mac-lte.h"
23 #include "packet-rlc-lte.h"
24 #include "packet-rlc-3gpp-common.h"
25 #include "packet-pdcp-lte.h"
28 /* Described in:
29 * 3GPP TS 36.322 Evolved Universal Terrestrial Radio Access (E-UTRA)
30 * Radio Link Control (RLC) Protocol specification v14.0.0
33 /* TODO:
34 - add intermediate results to segments leading to final reassembly
35 - use multiple active rlc_channel_reassembly_info's per channel
36 - sequence analysis gets confused when we change cells and skip back
37 to SN 0. Maybe add cell-id to context and add to channel/result key?
40 void proto_register_rlc_lte(void);
41 void proto_reg_handoff_rlc_lte(void);
43 /********************************/
44 /* Preference settings */
46 #define SEQUENCE_ANALYSIS_MAC_ONLY 1
47 #define SEQUENCE_ANALYSIS_RLC_ONLY 2
49 /* By default do try to analyse the sequence of messages for AM/UM channels
50 using MAC PDUs */
51 static int global_rlc_lte_am_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
52 static int global_rlc_lte_um_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
54 /* By default do call PDCP/RRC dissectors for SDU data */
55 static bool global_rlc_lte_call_pdcp_for_srb = true;
57 enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12, PDCP_drb_SN_signalled, PDCP_drb_SN_15, PDCP_drb_SN_18};
58 static const enum_val_t pdcp_drb_col_vals[] = {
59 {"pdcp-drb-off", "Off", PDCP_drb_off},
60 {"pdcp-drb-sn-7", "7-bit SN", PDCP_drb_SN_7},
61 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
62 {"pdcp-drb-sn-15", "15-bit SN", PDCP_drb_SN_15},
63 {"pdcp-drb-sn-18", "18-bit SN", PDCP_drb_SN_18},
64 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
65 {NULL, NULL, -1}
67 static int global_rlc_lte_call_pdcp_for_drb = (int)PDCP_drb_SN_signalled;
69 static bool global_rlc_lte_call_rrc_for_ccch = true;
70 static bool global_rlc_lte_call_rrc_for_mcch;
71 static bool global_rlc_lte_call_ip_for_mtch;
73 /* Preference to expect RLC headers without payloads */
74 static bool global_rlc_lte_headers_expected;
76 /* Re-assembly of segments */
77 static bool global_rlc_lte_reassembly = true;
79 /* Tree storing UE related parameters */
80 #define NO_EXT_LI 0x0
81 #define UL_EXT_LI 0x1
82 #define DL_EXT_LI 0x2
83 typedef struct rlc_ue_parameters {
84 uint32_t id;
85 uint8_t ext_li_field;
86 uint8_t pdcp_sn_bits;
87 } rlc_ue_parameters;
88 static wmem_tree_t *ue_parameters_tree;
90 /**************************************************/
91 /* Initialize the protocol and registered fields. */
92 int proto_rlc_lte;
94 extern int proto_mac_lte;
95 extern int proto_pdcp_lte;
97 static dissector_handle_t pdcp_lte_handle;
98 static dissector_handle_t ip_handle;
99 static dissector_handle_t lte_rrc_mcch;
100 static dissector_handle_t lte_rrc_ul_ccch;
101 static dissector_handle_t lte_rrc_dl_ccch;
102 static dissector_handle_t lte_rrc_bcch_bch;
103 static dissector_handle_t lte_rrc_bcch_dl_sch;
104 static dissector_handle_t lte_rrc_pcch;
105 static dissector_handle_t lte_rrc_ul_ccch_nb;
106 static dissector_handle_t lte_rrc_dl_ccch_nb;
107 static dissector_handle_t lte_rrc_bcch_bch_nb;
108 static dissector_handle_t lte_rrc_bcch_dl_sch_nb;
109 static dissector_handle_t lte_rrc_pcch_nb;
112 static int rlc_lte_tap;
114 /* Decoding context */
115 static int hf_rlc_lte_context;
116 static int hf_rlc_lte_context_mode;
117 static int hf_rlc_lte_context_direction;
118 static int hf_rlc_lte_context_priority;
119 static int hf_rlc_lte_context_ueid;
120 static int hf_rlc_lte_context_channel_type;
121 static int hf_rlc_lte_context_channel_id;
122 static int hf_rlc_lte_context_pdu_length;
123 static int hf_rlc_lte_context_um_sn_length;
124 static int hf_rlc_lte_context_am_sn_length;
126 /* Transparent mode fields */
127 static int hf_rlc_lte_tm;
128 static int hf_rlc_lte_tm_data;
130 /* Unacknowledged mode fields */
131 static int hf_rlc_lte_um;
132 static int hf_rlc_lte_um_header;
133 static int hf_rlc_lte_um_fi;
134 static int hf_rlc_lte_um_fixed_e;
135 static int hf_rlc_lte_um_sn;
136 static int hf_rlc_lte_um_fixed_reserved;
137 static int hf_rlc_lte_um_data;
138 static int hf_rlc_lte_extension_part;
140 /* Extended header (common to UM and AM) */
141 static int hf_rlc_lte_extension_e;
142 static int hf_rlc_lte_extension_li;
143 static int hf_rlc_lte_extension_padding;
146 /* Acknowledged mode fields */
147 static int hf_rlc_lte_am;
148 static int hf_rlc_lte_am_header;
149 static int hf_rlc_lte_am_data_control;
150 static int hf_rlc_lte_am_rf;
151 static int hf_rlc_lte_am_p;
152 static int hf_rlc_lte_am_fi;
153 static int hf_rlc_lte_am_fixed_e;
154 static int hf_rlc_lte_am_fixed_sn;
155 static int hf_rlc_lte_am_fixed_reserved;
156 static int hf_rlc_lte_am_segment_lsf16;
157 static int hf_rlc_lte_am_fixed_reserved2;
158 static int hf_rlc_lte_am_fixed_sn16;
159 static int hf_rlc_lte_am_segment_lsf;
160 static int hf_rlc_lte_am_segment_so;
161 static int hf_rlc_lte_am_segment_so16;
162 static int hf_rlc_lte_am_data;
164 /* Control fields */
165 static int hf_rlc_lte_am_cpt;
166 static int hf_rlc_lte_am_ack_sn;
167 static int hf_rlc_lte_am_e1;
168 static int hf_rlc_lte_am_e2;
169 static int hf_rlc_lte_am_nack_sn;
170 static int hf_rlc_lte_am_nacks;
171 static int hf_rlc_lte_am_so_start;
172 static int hf_rlc_lte_am_so_end;
174 static int hf_rlc_lte_predefined_pdu;
175 static int hf_rlc_lte_header_only;
177 /* Sequence Analysis */
178 static int hf_rlc_lte_sequence_analysis;
179 static int hf_rlc_lte_sequence_analysis_ok;
180 static int hf_rlc_lte_sequence_analysis_previous_frame;
181 static int hf_rlc_lte_sequence_analysis_next_frame;
182 static int hf_rlc_lte_sequence_analysis_expected_sn;
183 static int hf_rlc_lte_sequence_analysis_framing_info_correct;
185 static int hf_rlc_lte_sequence_analysis_mac_retx;
186 static int hf_rlc_lte_sequence_analysis_retx;
187 static int hf_rlc_lte_sequence_analysis_repeated;
188 static int hf_rlc_lte_sequence_analysis_skipped;
190 static int hf_rlc_lte_sequence_analysis_repeated_nack;
191 static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame;
193 static int hf_rlc_lte_sequence_analysis_ack_out_of_range;
194 static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame;
196 /* Reassembly */
197 static int hf_rlc_lte_reassembly_source;
198 static int hf_rlc_lte_reassembly_source_number_of_segments;
199 static int hf_rlc_lte_reassembly_source_total_length;
200 static int hf_rlc_lte_reassembly_source_segment;
201 static int hf_rlc_lte_reassembly_source_segment_sn;
202 static int hf_rlc_lte_reassembly_source_segment_framenum;
203 static int hf_rlc_lte_reassembly_source_segment_length;
205 /* Subtrees. */
206 static int ett_rlc_lte;
207 static int ett_rlc_lte_context;
208 static int ett_rlc_lte_um_header;
209 static int ett_rlc_lte_am_header;
210 static int ett_rlc_lte_extension_part;
211 static int ett_rlc_lte_sequence_analysis;
212 static int ett_rlc_lte_reassembly_source;
213 static int ett_rlc_lte_reassembly_source_segment;
215 static expert_field ei_rlc_lte_context_mode;
216 static expert_field ei_rlc_lte_am_nack_sn;
217 static expert_field ei_rlc_lte_am_nack_sn_ahead_ack;
218 static expert_field ei_rlc_lte_um_sn_repeated;
219 static expert_field ei_rlc_lte_am_nack_sn_ack_same;
220 static expert_field ei_rlc_lte_am_cpt;
221 static expert_field ei_rlc_lte_am_data_no_data;
222 static expert_field ei_rlc_lte_sequence_analysis_last_segment_complete;
223 static expert_field ei_rlc_lte_sequence_analysis_mac_retx;
224 static expert_field ei_rlc_lte_am_nack_sn_partial;
225 static expert_field ei_rlc_lte_sequence_analysis_repeated_nack;
226 static expert_field ei_rlc_lte_bytes_after_status_pdu_complete;
227 static expert_field ei_rlc_lte_sequence_analysis_repeated;
228 static expert_field ei_rlc_lte_wrong_sequence_number;
229 static expert_field ei_rlc_lte_sequence_analysis_retx;
230 static expert_field ei_rlc_lte_am_sn_missing;
231 static expert_field ei_rlc_lte_um_sn;
232 static expert_field ei_rlc_lte_header_only;
233 static expert_field ei_rlc_lte_am_data_no_data_beyond_extensions;
234 static expert_field ei_rlc_lte_um_sn_missing;
235 static expert_field ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame;
236 static expert_field ei_rlc_lte_sequence_analysis_last_segment_not_continued;
237 static expert_field ei_rlc_lte_reserved_bits_not_zero;
238 static expert_field ei_rlc_lte_no_per_frame_info;
239 static expert_field ei_rlc_lte_unknown_udp_framing_tag;
240 static expert_field ei_rlc_lte_missing_udp_framing_tag;
242 /* Value-strings */
243 static const value_string direction_vals[] =
245 { DIRECTION_UPLINK, "Uplink"},
246 { DIRECTION_DOWNLINK, "Downlink"},
247 { 0, NULL }
250 static const value_string rlc_mode_short_vals[] =
252 { RLC_TM_MODE, "TM"},
253 { RLC_UM_MODE, "UM"},
254 { RLC_AM_MODE, "AM"},
255 { RLC_PREDEF, "PREDEFINED"}, /* For data testing */
256 { 0, NULL }
259 static const value_string rlc_mode_vals[] =
261 { RLC_TM_MODE, "Transparent Mode"},
262 { RLC_UM_MODE, "Unacknowledged Mode"},
263 { RLC_AM_MODE, "Acknowledged Mode"},
264 { 0, NULL }
267 static const value_string rlc_channel_type_vals[] =
269 { CHANNEL_TYPE_CCCH, "CCCH"},
270 { CHANNEL_TYPE_BCCH_BCH, "BCCH_BCH"},
271 { CHANNEL_TYPE_PCCH, "PCCH"},
272 { CHANNEL_TYPE_SRB, "SRB"},
273 { CHANNEL_TYPE_DRB, "DRB"},
274 { CHANNEL_TYPE_BCCH_DL_SCH, "BCCH_DL_SCH"},
275 { CHANNEL_TYPE_MCCH, "MCCH"},
276 { CHANNEL_TYPE_MTCH, "MTCH"},
277 { 0, NULL }
280 static const value_string framing_info_vals[] =
282 { 0, "First byte begins a RLC SDU and last byte ends a RLC SDU"},
283 { 1, "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
284 { 2, "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
285 { 3, "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
286 { 0, NULL }
289 static const value_string fixed_extension_vals[] =
291 { 0, "Data field follows from the octet following the fixed part of the header"},
292 { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"},
293 { 0, NULL }
296 static const value_string extension_extension_vals[] =
298 { 0, "Data field follows from the octet following the LI field following this E field"},
299 { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"},
300 { 0, NULL }
303 static const value_string resegmentation_flag_vals[] =
305 { 0, "AMD PDU"},
306 { 1, "AMD PDU segment"},
307 { 0, NULL }
310 static const value_string polling_bit_vals[] =
312 { 0, "Status report not requested"},
313 { 1, "Status report is requested"},
314 { 0, NULL }
317 static const value_string lsf_vals[] =
319 { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
320 { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
321 { 0, NULL }
324 static const value_string control_pdu_type_vals[] =
326 { 0, "STATUS PDU"},
327 { 0, NULL }
330 static const value_string am_e1_vals[] =
332 { 0, "A set of NACK_SN, E1 and E2 does not follow"},
333 { 1, "A set of NACK_SN, E1 and E2 follows"},
334 { 0, NULL }
337 static const value_string am_e2_vals[] =
339 { 0, "A set of SOstart and SOend does not follow for this NACK_SN"},
340 { 1, "A set of SOstart and SOend follows for this NACK_SN"},
341 { 0, NULL }
344 static const value_string header_only_vals[] =
346 { 0, "RLC PDU Headers and body present"},
347 { 1, "RLC PDU Headers only"},
348 { 0, NULL }
353 /**********************************************************************************/
354 /* These are for keeping track of UM/AM extension headers, and the lengths found */
355 /* in them */
356 static uint8_t s_number_of_extensions;
357 #define MAX_RLC_SDUS 192
358 static uint16_t s_lengths[MAX_RLC_SDUS];
361 /*********************************************************************/
362 /* UM/AM sequence analysis */
364 /* Types for RLC channel hash table */
365 /* This table is maintained during initial dissection of RLC */
366 /* frames, mapping from channel_hash_key -> sequence_analysis_report */
368 /* Channel key */
369 typedef struct
371 unsigned ueId : 16;
372 unsigned channelType : 3;
373 unsigned channelId : 5;
374 unsigned direction : 1;
375 } channel_hash_key;
378 /******************************************************************/
379 /* State maintained for AM/UM reassembly */
381 typedef struct rlc_segment {
382 uint32_t frameNum;
383 uint16_t SN;
384 uint8_t *data;
385 uint16_t length;
386 } rlc_segment;
388 typedef struct rlc_channel_reassembly_info
390 uint16_t number_of_segments;
391 #define RLC_MAX_SEGMENTS 100
392 rlc_segment segments[RLC_MAX_SEGMENTS];
393 } rlc_channel_reassembly_info;
398 /*******************************************************************/
399 /* Conversation-type status for sequence analysis on channel */
400 typedef struct
402 uint8_t rlcMode;
404 /* For UM, we always expect the SN to keep advancing, and these fields
405 keep track of this.
406 For AM, these correspond to new data */
407 uint16_t previousSequenceNumber;
408 uint32_t previousFrameNum;
409 bool previousSegmentIncomplete;
411 /* Accumulate info about current segmented SDU */
412 struct rlc_channel_reassembly_info *reassembly_info;
413 } channel_sequence_analysis_status;
415 /* The sequence analysis channel hash table (channel_hash_key* -> channel_sequence_analysis_status*) */
416 static wmem_map_t *sequence_analysis_channel_hash;
419 /* Types for sequence analysis frame report hash table */
420 /* This is a table from framenum -> state_report_in_frame */
421 /* This is necessary because the per-packet info is already being used */
422 /* for context information before the dissector is called */
424 /* Info to attach to frame when first read, recording what to show about sequence */
425 typedef enum {
426 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window, SN_Error
427 } sequence_analysis_state;
430 typedef struct
432 bool sequenceExpectedCorrect;
433 uint16_t sequenceExpected;
434 uint32_t previousFrameNum;
435 bool previousSegmentIncomplete;
436 uint32_t nextFrameNum;
438 uint16_t firstSN;
439 uint16_t lastSN;
441 /* AM/UM */
442 sequence_analysis_state state;
443 } sequence_analysis_report;
446 /* The sequence analysis frame report hash table instance itself, lookup when visited */
447 /* rlc_result_hash_key* -> sequence_analysis_report* */
448 static wmem_map_t *sequence_analysis_report_hash;
451 static void *get_report_hash_key(uint16_t SN, uint32_t frameNumber,
452 rlc_lte_info *p_rlc_lte_info,
453 bool do_persist);
458 /* The reassembly result hash table */
459 static wmem_map_t *reassembly_report_hash;
462 /* Create a new struct for reassembly */
463 static void reassembly_reset(channel_sequence_analysis_status *status)
465 status->reassembly_info = wmem_new0(wmem_file_scope(), rlc_channel_reassembly_info);
468 /* Hide previous one */
469 static void reassembly_destroy(channel_sequence_analysis_status *status)
471 /* Just "leak" it. There seems to be no way to free this memory... */
472 status->reassembly_info = NULL;
475 /* Add a new segment to the accumulating segmented SDU */
476 static void reassembly_add_segment(channel_sequence_analysis_status *status,
477 uint16_t SN, uint32_t frame,
478 tvbuff_t *tvb, int offset, int length)
480 int segment_number = status->reassembly_info->number_of_segments;
481 uint8_t *segment_data;
483 /* Give up if reach segment limit */
484 if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
485 reassembly_destroy(status);
486 return;
489 segment_data = (uint8_t *)tvb_memdup(wmem_file_scope(),tvb, offset, length);
491 /* Add new segment */
492 status->reassembly_info->segments[segment_number].frameNum = frame;
493 status->reassembly_info->segments[segment_number].SN = SN;
494 status->reassembly_info->segments[segment_number].data = segment_data;
495 status->reassembly_info->segments[segment_number].length = length;
497 status->reassembly_info->number_of_segments++;
501 /* Record the current & complete segmented SDU by mapping from this frame number to
502 struct with segment info. */
503 static void reassembly_record(channel_sequence_analysis_status *status, packet_info *pinfo,
504 uint16_t SN, rlc_lte_info *p_rlc_lte_info)
506 /* Just store existing info in hash table */
507 wmem_map_insert(reassembly_report_hash,
508 get_report_hash_key(SN, pinfo->num, p_rlc_lte_info, true),
509 status->reassembly_info);
512 /* Create and return a tvb based upon contents of reassembly info */
513 static tvbuff_t* reassembly_get_reassembled_tvb(rlc_channel_reassembly_info *reassembly_info,
514 tvbuff_t *parent_tvb, packet_info *pinfo)
516 int n;
517 unsigned combined_length = 0;
518 uint8_t *combined_data;
519 unsigned combined_offset = 0;
520 tvbuff_t *reassembled_tvb;
522 /* Allocate buffer big enough to hold re-assembled data */
523 for (n=0; n < reassembly_info->number_of_segments; n++) {
524 combined_length += reassembly_info->segments[n].length;
526 combined_data = (uint8_t *)wmem_alloc(pinfo->pool, combined_length);
528 /* Copy data into contiguous buffer */
529 for (n=0; n < reassembly_info->number_of_segments; n++) {
530 uint8_t *data = reassembly_info->segments[n].data;
531 int length = reassembly_info->segments[n].length;
532 memcpy(combined_data+combined_offset, data, length);
533 combined_offset += length;
536 /* Create and return tvb with this data */
537 reassembled_tvb = tvb_new_child_real_data(parent_tvb, combined_data, combined_offset, combined_offset);
538 add_new_data_source(pinfo, reassembled_tvb, "Reassembled SDU");
539 return reassembled_tvb;
542 /* Show where the segments came from for a reassembled SDU */
543 static void reassembly_show_source(rlc_channel_reassembly_info *reassembly_info,
544 proto_tree *tree, tvbuff_t *tvb, int offset)
546 int n;
547 proto_item *source_ti, *ti;
548 proto_tree *source_tree;
549 proto_item *segment_ti;
550 proto_tree *segment_tree;
551 unsigned total_length=0;
553 /* Create root of source info */
554 source_ti = proto_tree_add_item(tree,
555 hf_rlc_lte_reassembly_source,
556 tvb, 0, 0, ENC_ASCII);
557 source_tree = proto_item_add_subtree(source_ti, ett_rlc_lte_reassembly_source);
558 proto_item_set_generated(source_ti);
560 for (n=0; n < reassembly_info->number_of_segments; n++) {
561 total_length += reassembly_info->segments[n].length;
563 proto_item_append_text(source_ti, " %u segments, %u bytes", reassembly_info->number_of_segments,
564 total_length);
566 /* Number of segments */
567 ti = proto_tree_add_uint(source_tree,
568 hf_rlc_lte_reassembly_source_number_of_segments,
569 tvb, 0, 0, reassembly_info->number_of_segments);
570 proto_item_set_generated(ti);
572 /* Total length */
573 ti = proto_tree_add_uint(source_tree,
574 hf_rlc_lte_reassembly_source_total_length,
575 tvb, 0, 0, total_length);
576 proto_item_set_generated(ti);
578 /* Now add info about each segment in turn */
579 for (n=0; n < reassembly_info->number_of_segments; n++) {
581 /* Add next segment as a subtree */
582 rlc_segment *segment = &(reassembly_info->segments[n]);
583 proto_item_append_text(source_ti, " (SN=%u frame=%u len=%u)",
584 segment->SN, segment->frameNum, segment->length);
586 /* N.B. assume last segment from passed-in tvb! */
587 segment_ti = proto_tree_add_item(source_tree,
588 hf_rlc_lte_reassembly_source_segment,
589 tvb,
590 (n == reassembly_info->number_of_segments-1) ? offset : 0,
591 (n == reassembly_info->number_of_segments-1) ? segment->length : 0,
592 ENC_NA);
593 segment_tree = proto_item_add_subtree(segment_ti, ett_rlc_lte_reassembly_source_segment);
594 proto_item_append_text(segment_ti, " (SN=%u frame=%u length=%u)",
595 segment->SN, segment->frameNum, segment->length);
596 proto_item_set_generated(segment_ti);
598 /* Add details to segment tree */
599 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_sn,
600 tvb, 0, 0, segment->SN);
601 proto_item_set_generated(ti);
602 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_framenum,
603 tvb, 0, 0, segment->frameNum);
604 proto_item_set_generated(ti);
605 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_length,
606 tvb, 0, 0, segment->length);
607 proto_item_set_generated(ti);
614 /******************************************************************/
615 /* Conversation-type status for repeated NACK checking on channel */
616 typedef struct
618 uint16_t noOfNACKs;
619 uint16_t NACKs[MAX_NACKs];
620 uint32_t frameNum;
621 } channel_repeated_nack_status;
623 static wmem_map_t *repeated_nack_channel_hash;
625 typedef struct {
626 uint16_t noOfNACKsRepeated;
627 uint16_t repeatedNACKs[MAX_NACKs];
628 uint32_t previousFrameNum;
629 } channel_repeated_nack_report;
631 static wmem_map_t *repeated_nack_report_hash;
635 /********************************************************/
636 /* Forward declarations & functions */
637 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool is_udp_framing);
640 /* Write the given formatted text to:
641 - the info column
642 - the top-level RLC PDU item
643 - another subtree item (if supplied) */
644 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
645 packet_info *pinfo, const char *format, ...) G_GNUC_PRINTF(4, 5);
646 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
647 packet_info *pinfo, const char *format, ...)
649 #define MAX_INFO_BUFFER 256
650 static char info_buffer[MAX_INFO_BUFFER];
652 va_list ap;
654 va_start(ap, format);
655 vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
656 va_end(ap);
658 /* Add to indicated places */
659 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
660 proto_item_append_text(pdu_ti, "%s", info_buffer);
661 if (sub_ti != NULL) {
662 proto_item_append_text(sub_ti, "%s", info_buffer);
666 /* Version of function above, where no vsnprintf() call needed
667 - the info column
668 - the top-level RLC PDU item
669 - another subtree item (if supplied) */
670 static void write_pdu_label_and_info_literal(proto_item *pdu_ti, proto_item *sub_ti,
671 packet_info *pinfo, const char *info_buffer)
673 /* Add to indicated places */
674 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
675 proto_item_append_text(pdu_ti, "%s", info_buffer);
676 if (sub_ti != NULL) {
677 proto_item_append_text(sub_ti, "%s", info_buffer);
683 /* Dissect extension headers (common to both UM and AM) */
684 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo _U_,
685 proto_tree *tree,
686 int offset,
687 rlc_lte_info *p_rlc_lte_info)
689 uint8_t isOdd;
690 uint64_t extension = 1;
691 uint64_t length;
693 /* Reset this count */
694 s_number_of_extensions = 0;
696 while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
697 proto_tree *extension_part_tree;
698 proto_item *extension_part_ti;
700 /* Extension part subtree */
701 extension_part_ti = proto_tree_add_string_format(tree,
702 hf_rlc_lte_extension_part,
703 tvb, offset, 2,
705 "Extension Part");
706 extension_part_tree = proto_item_add_subtree(extension_part_ti,
707 ett_rlc_lte_extension_part);
709 if (p_rlc_lte_info->extendedLiField == false) {
710 isOdd = (s_number_of_extensions % 2);
712 /* Read next extension */
713 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
714 (offset*8) + ((isOdd) ? 4 : 0),
716 &extension, ENC_BIG_ENDIAN);
718 /* Read length field */
719 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
720 (offset*8) + ((isOdd) ? 5 : 1),
722 &length, ENC_BIG_ENDIAN);
724 /* Move on to byte of next extension */
725 if (isOdd) {
726 offset += 2;
727 } else {
728 offset++;
730 } else {
731 /* Read next extension */
732 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
733 (offset*8),
735 &extension, ENC_BIG_ENDIAN);
737 /* Read length field */
738 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
739 (offset*8) + 1,
741 &length, ENC_BIG_ENDIAN);
743 /* Move on to byte of next extension */
744 offset += 2;
747 proto_item_append_text(extension_part_tree, " (length=%u)", (uint16_t)length);
749 s_lengths[s_number_of_extensions++] = (uint16_t)length;
752 /* May need to skip padding after last extension part */
753 isOdd = (s_number_of_extensions % 2);
754 if (isOdd && (p_rlc_lte_info->extendedLiField == false)) {
755 proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
756 tvb, offset++, 1, ENC_BIG_ENDIAN);
759 return offset;
763 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
764 whether or not the beginning and end are included in this packet */
765 static void show_PDU_in_info(packet_info *pinfo,
766 proto_item *top_ti,
767 int32_t length,
768 bool first_includes_start,
769 bool last_includes_end)
771 /* Reflect this PDU in the info column */
772 if (length > 0) {
773 write_pdu_label_and_info(top_ti, NULL, pinfo,
774 " %s%u-byte%s%s",
775 (first_includes_start) ? "[" : "..",
776 length,
777 (length > 1) ? "s" : "",
778 (last_includes_end) ? "]" : "..");
780 else {
781 write_pdu_label_and_info(top_ti, NULL, pinfo,
782 " %sunknown-bytes%s",
783 (first_includes_start) ? "[" : "..",
784 (last_includes_end) ? "]" : "..");
789 /* Show an SDU. If configured, pass to PDCP/RRC/IP dissector */
790 static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, int length,
791 rlc_lte_info *rlc_info, bool whole_pdu, rlc_channel_reassembly_info *reassembly_info,
792 sequence_analysis_state state)
794 wmem_tree_key_t key[3];
795 uint32_t id;
796 rlc_ue_parameters *params;
798 /* Add raw data (according to mode) */
799 proto_item *data_ti = proto_tree_add_item(tree,
800 (rlc_info->rlcMode == RLC_AM_MODE) ?
801 hf_rlc_lte_am_data :
802 hf_rlc_lte_um_data,
803 tvb, offset, length, ENC_NA);
805 if (whole_pdu || (reassembly_info != NULL)) {
806 if (((global_rlc_lte_call_pdcp_for_srb) && (rlc_info->channelType == CHANNEL_TYPE_SRB)) ||
807 ((global_rlc_lte_call_pdcp_for_drb != PDCP_drb_off) && (rlc_info->channelType == CHANNEL_TYPE_DRB))) {
808 /* Send whole PDU to PDCP */
810 /* TODO: made static to avoid compiler warning... */
811 static tvbuff_t *pdcp_tvb = NULL;
812 struct pdcp_lte_info *p_pdcp_lte_info;
814 /* Get tvb for passing to LTE PDCP dissector */
815 if (reassembly_info == NULL) {
816 pdcp_tvb = tvb_new_subset_length(tvb, offset, length);
818 else {
819 /* Get combined tvb. */
820 pdcp_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
821 reassembly_show_source(reassembly_info, tree, tvb, offset);
824 /* Reuse or allocate struct */
825 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
826 if (p_pdcp_lte_info == NULL) {
827 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
828 /* Store info in packet */
829 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0, p_pdcp_lte_info);
832 p_pdcp_lte_info->ueid = rlc_info->ueid;
833 if (rlc_info->nbMode == rlc_nb_mode) {
834 p_pdcp_lte_info->channelType = Channel_DCCH_NB;
835 } else {
836 p_pdcp_lte_info->channelType = Channel_DCCH;
838 p_pdcp_lte_info->channelId = rlc_info->channelId;
839 p_pdcp_lte_info->direction = rlc_info->direction;
840 p_pdcp_lte_info->is_retx = (state != SN_OK);
842 /* Set plane and sequence number length */
843 p_pdcp_lte_info->no_header_pdu = false;
844 if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
845 p_pdcp_lte_info->plane = SIGNALING_PLANE;
846 if ((rlc_info->nbMode == rlc_nb_mode) && (rlc_info->channelId == 3)) {
847 p_pdcp_lte_info->no_header_pdu = true;
848 p_pdcp_lte_info->seqnum_length = 0;
849 } else {
850 p_pdcp_lte_info->seqnum_length = 5;
853 else {
854 p_pdcp_lte_info->plane = USER_PLANE;
855 switch (global_rlc_lte_call_pdcp_for_drb) {
856 case PDCP_drb_SN_7:
857 p_pdcp_lte_info->seqnum_length = 7;
858 break;
859 case PDCP_drb_SN_12:
860 p_pdcp_lte_info->seqnum_length = 12;
861 break;
862 case PDCP_drb_SN_15:
863 p_pdcp_lte_info->seqnum_length = 15;
864 break;
865 case PDCP_drb_SN_18:
866 p_pdcp_lte_info->seqnum_length = 18;
867 break;
868 case PDCP_drb_SN_signalled:
869 /* Use whatever was signalled (e.g. in RRC) */
870 id = (rlc_info->channelId << 16) | rlc_info->ueid;
871 key[0].length = 1;
872 key[0].key = &id;
873 key[1].length = 1;
874 key[1].key = &pinfo->num;
875 key[2].length = 0;
876 key[2].key = NULL;
878 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
879 if (params && (params->id != id)) {
880 params = NULL;
882 if (params) {
883 p_pdcp_lte_info->seqnum_length = params->pdcp_sn_bits;
884 } else if (rlc_info->nbMode == rlc_nb_mode) {
885 p_pdcp_lte_info->seqnum_length = 7;
886 } else {
887 p_pdcp_lte_info->seqnum_length = 12;
889 break;
891 default:
892 DISSECTOR_ASSERT(false);
893 break;
897 TRY {
898 call_dissector_only(pdcp_lte_handle, pdcp_tvb, pinfo, tree, NULL);
900 CATCH_ALL {
902 ENDTRY
904 proto_item_set_hidden(data_ti);
906 else if (global_rlc_lte_call_rrc_for_mcch && (rlc_info->channelType == CHANNEL_TYPE_MCCH)) {
907 /* Send whole PDU to RRC */
908 static tvbuff_t *rrc_tvb = NULL;
910 /* Get tvb for passing to LTE RRC dissector */
911 if (reassembly_info == NULL) {
912 rrc_tvb = tvb_new_subset_length(tvb, offset, length);
914 else {
915 /* Get combined tvb. */
916 rrc_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
917 reassembly_show_source(reassembly_info, tree, tvb, offset);
920 TRY {
921 call_dissector_only(lte_rrc_mcch, rrc_tvb, pinfo, tree, NULL);
923 CATCH_ALL {
925 ENDTRY
927 proto_item_set_hidden(data_ti);
929 else if (global_rlc_lte_call_ip_for_mtch && (rlc_info->channelType == CHANNEL_TYPE_MTCH)) {
930 /* Send whole PDU to IP */
931 static tvbuff_t *ip_tvb = NULL;
933 /* Get tvb for passing to IP dissector */
934 if (reassembly_info == NULL) {
935 ip_tvb = tvb_new_subset_length(tvb, offset, length);
937 else {
938 /* Get combined tvb. */
939 ip_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
940 reassembly_show_source(reassembly_info, tree, tvb, offset);
943 TRY {
944 call_dissector_only(ip_handle, ip_tvb, pinfo, tree, NULL);
946 CATCH_ALL {
948 ENDTRY
950 proto_item_set_hidden(data_ti);
955 /* Hash table functions for RLC channels */
957 /* Equal keys */
958 static int rlc_channel_equal(const void *v, const void *v2)
960 const channel_hash_key* val1 = (const channel_hash_key *)v;
961 const channel_hash_key* val2 = (const channel_hash_key *)v2;
963 /* All fields must match */
964 /* N.B. Currently fits into one word, so could return (*v == *v2)
965 if we're sure they're initialised to 0... */
966 return ((val1->ueId == val2->ueId) &&
967 (val1->channelType == val2->channelType) &&
968 (val1->channelId == val2->channelId) &&
969 (val1->direction == val2->direction));
972 /* Compute a hash value for a given key. */
973 static unsigned rlc_channel_hash_func(const void *v)
975 const channel_hash_key* val1 = (const channel_hash_key *)v;
977 /* TODO: check/reduce multipliers */
978 return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
982 /*************************************************************************/
983 /* Result hash */
985 typedef struct {
986 uint32_t frameNumber;
987 uint32_t SN : 10;
988 uint32_t channelType : 2;
989 uint32_t channelId: 5;
990 uint32_t direction: 1;
991 } rlc_result_hash_key;
993 /* Compare 2 rlc_result_hash_key structs */
994 static int rlc_result_hash_equal(const void *v, const void *v2)
996 const rlc_result_hash_key *val1 = (const rlc_result_hash_key *)v;
997 const rlc_result_hash_key *val2 = (const rlc_result_hash_key *)v2;
999 /* All fields (and any padding...) must match */
1000 return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
1003 /* Compute a hash value for a given key. */
1004 static unsigned rlc_result_hash_func(const void *v)
1006 const rlc_result_hash_key* val1 = (const rlc_result_hash_key *)v;
1008 /* Got rid of multipliers - no evidence that they reduced collisions */
1009 return val1->frameNumber + val1->SN +
1010 val1->channelType +
1011 val1->channelId +
1012 val1->direction;
1015 /* Convenience function to get a pointer for the hash_func to work with */
1016 static void *get_report_hash_key(uint16_t SN, uint32_t frameNumber,
1017 rlc_lte_info *p_rlc_lte_info,
1018 bool do_persist)
1020 static rlc_result_hash_key key;
1021 rlc_result_hash_key *p_key;
1023 /* Only allocate a struct when will be adding entry */
1024 if (do_persist) {
1025 p_key = wmem_new0(wmem_file_scope(), rlc_result_hash_key);
1027 else {
1028 memset(&key, 0, sizeof(rlc_result_hash_key));
1029 p_key = &key;
1032 /* Fill in details, and return pointer */
1033 p_key->frameNumber = frameNumber;
1034 p_key->SN = SN;
1035 p_key->channelType = p_rlc_lte_info->channelType;
1036 p_key->channelId = p_rlc_lte_info->channelId;
1037 p_key->direction = p_rlc_lte_info->direction;
1039 return p_key;
1042 static void checkFIconsistency(sequence_analysis_report *p,
1043 rlc_lte_info *p_rlc_lte_info,
1044 bool newSegmentStarted,
1045 proto_tree *seqnum_tree,
1046 packet_info *pinfo, tvbuff_t *tvb)
1048 proto_item *ti;
1050 if (p->previousSegmentIncomplete) {
1051 /* Previous segment was incomplete, so this PDU should continue it */
1052 if (newSegmentStarted) {
1053 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1054 tvb, 0, 0, false);
1055 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_not_continued,
1056 "Last segment of previous PDU was not continued for UE %u (%s-%u)",
1057 p_rlc_lte_info->ueid,
1058 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1059 p_rlc_lte_info->channelId);
1061 else {
1062 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1063 tvb, 0, 0, true);
1064 proto_item_set_hidden(ti);
1067 else {
1068 /* Previous segment was complete, so this PDU should start a new one */
1069 if (!newSegmentStarted) {
1070 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1071 tvb, 0, 0, false);
1072 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_complete,
1073 "Last segment of previous PDU was complete, but new segment was not started on UE %u (%s-%u)",
1074 p_rlc_lte_info->ueid,
1075 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1076 p_rlc_lte_info->channelId);
1078 else {
1079 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1080 tvb, 0, 0, true);
1081 proto_item_set_hidden(ti);
1084 proto_item_set_generated(ti);
1087 /* Add to the tree values associated with sequence analysis for this frame */
1088 static void addChannelSequenceInfo(sequence_analysis_report *p,
1089 bool isControlFrame,
1090 rlc_lte_info *p_rlc_lte_info,
1091 uint16_t sequenceNumber,
1092 bool newSegmentStarted,
1093 rlc_3gpp_tap_info *tap_info,
1094 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
1096 proto_tree *seqnum_tree;
1097 proto_item *seqnum_ti;
1098 proto_item *ti;
1100 /* Create subtree */
1101 seqnum_ti = proto_tree_add_string_format(tree,
1102 hf_rlc_lte_sequence_analysis,
1103 tvb, 0, 0,
1104 "", "Sequence Analysis");
1105 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1106 ett_rlc_lte_sequence_analysis);
1107 proto_item_set_generated(seqnum_ti);
1109 if (p->previousFrameNum != 0) {
1110 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1111 tvb, 0, 0, p->previousFrameNum);
1112 proto_item_set_generated(ti);
1115 switch (p_rlc_lte_info->rlcMode) {
1116 case RLC_AM_MODE:
1118 /********************************************/
1119 /* AM */
1120 /********************************************/
1122 switch (p->state) {
1123 case SN_OK:
1124 if (isControlFrame) {
1125 return;
1128 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1129 tvb, 0, 0, true);
1130 proto_item_set_generated(ti);
1131 proto_item_append_text(seqnum_ti, " - OK");
1133 /* Link to next SN in channel (if known) */
1134 if (p->nextFrameNum != 0) {
1135 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1136 tvb, 0, 0, p->nextFrameNum);
1138 /* Correct sequence number, so check frame indication bits consistent */
1139 /* Deactivated for now as it gets confused by resegmentation */
1140 /* checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb); */
1141 break;
1143 case SN_MAC_Retx:
1144 if (isControlFrame) {
1145 return;
1148 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1149 tvb, 0, 0, false);
1150 proto_item_set_generated(ti);
1151 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1152 tvb, 0, 0, true);
1153 proto_item_set_generated(ti);
1154 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1155 "AM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1156 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1157 p_rlc_lte_info->ueid,
1158 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1159 p_rlc_lte_info->channelId);
1160 proto_item_append_text(seqnum_ti, " - MAC retx of SN %u", p->firstSN);
1161 break;
1163 case SN_Retx:
1164 if (isControlFrame) {
1165 return;
1168 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1169 tvb, 0, 0, false);
1170 proto_item_set_generated(ti);
1171 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
1172 tvb, 0, 0, true);
1173 proto_item_set_generated(ti);
1174 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_retx,
1175 "AM Frame retransmitted for %s on UE %u - most likely in response to NACK (%s-%u)",
1176 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1177 p_rlc_lte_info->ueid,
1178 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1179 p_rlc_lte_info->channelId);
1180 proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
1181 break;
1183 case SN_Repeated:
1184 if (isControlFrame) {
1185 return;
1188 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1189 tvb, 0, 0, false);
1190 proto_item_set_generated(ti);
1191 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1192 tvb, 0, 0, true);
1193 proto_item_set_generated(ti);
1194 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated,
1195 "AM SN Repeated for %s for UE %u - probably because didn't receive Status PDU? (%s-%u)",
1196 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1197 p_rlc_lte_info->ueid,
1198 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1199 p_rlc_lte_info->channelId);
1200 proto_item_append_text(seqnum_ti, "- SN %u Repeated", p->firstSN);
1201 break;
1203 case SN_Missing:
1204 if (isControlFrame) {
1205 return;
1208 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1209 tvb, 0, 0, false);
1210 proto_item_set_generated(ti);
1211 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1212 tvb, 0, 0, true);
1213 proto_item_set_generated(ti);
1214 if (p->lastSN != p->firstSN) {
1215 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1216 "AM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1217 p->firstSN, p->lastSN,
1218 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1219 p_rlc_lte_info->ueid,
1220 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1221 p_rlc_lte_info->channelId);
1222 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1223 p->firstSN, p->lastSN);
1224 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1225 tap_info->missingSNs = ((65536 + (uint32_t)p->lastSN - (uint32_t)p->firstSN) % 65536) + 1;
1226 } else {
1227 tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1230 else {
1231 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1232 "AM SN (%u) missing for %s on UE %u (%s-%u)",
1233 p->firstSN,
1234 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1235 p_rlc_lte_info->ueid,
1236 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1237 p_rlc_lte_info->channelId);
1238 proto_item_append_text(seqnum_ti, " - SN missing (%u)", p->firstSN);
1239 tap_info->missingSNs = 1;
1241 break;
1243 case ACK_Out_of_Window:
1244 if (!isControlFrame) {
1245 return;
1249 /* Not OK */
1250 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1251 tvb, 0, 0, false);
1252 /* Out of range */
1253 proto_item_set_generated(ti);
1254 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1255 tvb, 0, 0, true);
1256 proto_item_set_generated(ti);
1258 /* Link back to last seen SN in other direction */
1259 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1260 tvb, 0, 0, p->previousFrameNum);
1261 proto_item_set_generated(ti);
1263 /* Expert error */
1264 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1265 "AM ACK for SN %u - but last received SN in other direction is %u for UE %u (%s-%u)",
1266 p->firstSN, p->sequenceExpected,
1267 p_rlc_lte_info->ueid,
1268 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1269 p_rlc_lte_info->channelId);
1270 proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1271 p->firstSN, p->sequenceExpected);
1273 break;
1275 default:
1276 return;
1278 break;
1280 case RLC_UM_MODE:
1282 /********************************************/
1283 /* UM */
1284 /********************************************/
1286 /* Expected sequence number */
1287 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
1288 tvb, 0, 0, p->sequenceExpected);
1289 proto_item_set_generated(ti);
1290 if (p->sequenceExpectedCorrect) {
1291 proto_item_set_hidden(ti);
1294 if (!p->sequenceExpectedCorrect) {
1295 /* Work out SN wrap (in case needed below) */
1296 uint16_t snLimit;
1297 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1298 snLimit = 32;
1300 else {
1301 snLimit = 1024;
1304 switch (p->state) {
1305 case SN_Missing:
1306 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1307 tvb, 0, 0, false);
1308 proto_item_set_generated(ti);
1309 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1310 tvb, 0, 0, true);
1311 proto_item_set_generated(ti);
1312 if (p->lastSN != p->firstSN) {
1313 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1314 "UM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1315 p->firstSN, p->lastSN,
1316 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1317 p_rlc_lte_info->ueid,
1318 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1319 p_rlc_lte_info->channelId);
1320 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1321 p->firstSN, p->lastSN);
1322 tap_info->missingSNs = ((snLimit + p->lastSN - p->firstSN) % snLimit) + 1;
1324 else {
1325 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1326 "UM SN (%u) missing for %s on UE %u (%s-%u)",
1327 p->firstSN,
1328 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1329 p_rlc_lte_info->ueid,
1330 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1331 p_rlc_lte_info->channelId);
1332 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
1333 p->firstSN);
1334 tap_info->missingSNs = 1;
1336 break;
1338 case SN_Repeated:
1339 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1340 tvb, 0, 0, false);
1341 proto_item_set_generated(ti);
1342 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1343 tvb, 0, 0, true);
1344 proto_item_set_generated(ti);
1345 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_repeated,
1346 "UM SN (%u) repeated for %s for UE %u (%s-%u)",
1347 p->firstSN,
1348 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1349 p_rlc_lte_info->ueid,
1350 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1351 p_rlc_lte_info->channelId);
1352 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
1353 p->firstSN);
1354 break;
1356 case SN_MAC_Retx:
1357 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1358 tvb, 0, 0, false);
1359 proto_item_set_generated(ti);
1360 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1361 tvb, 0, 0, true);
1362 proto_item_set_generated(ti);
1363 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1364 "UM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1365 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1366 p_rlc_lte_info->ueid,
1367 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1368 p_rlc_lte_info->channelId);
1369 break;
1371 default:
1372 /* Incorrect sequence number */
1373 expert_add_info_format(pinfo, ti, &ei_rlc_lte_wrong_sequence_number,
1374 "Wrong Sequence Number for %s on UE %u - got %u, expected %u (%s-%u)",
1375 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1376 p_rlc_lte_info->ueid, sequenceNumber, p->sequenceExpected,
1377 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1378 p_rlc_lte_info->channelId);
1380 break;
1384 else {
1385 /* Correct sequence number, so check frame indication bits consistent */
1386 checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb);
1388 /* Set OK here! */
1389 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1390 tvb, 0, 0, true);
1391 proto_item_set_generated(ti);
1392 proto_item_append_text(seqnum_ti, " - OK");
1395 /* Next channel frame */
1396 if (p->nextFrameNum != 0) {
1397 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1398 tvb, 0, 0, p->nextFrameNum);
1399 proto_item_set_generated(ti);
1404 /* Update the channel status and set report for this frame */
1405 static sequence_analysis_state checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
1406 rlc_lte_info *p_rlc_lte_info,
1407 bool isControlFrame,
1408 uint8_t number_of_segments,
1409 uint16_t firstSegmentOffset,
1410 uint16_t firstSegmentLength,
1411 uint16_t lastSegmentOffset,
1412 uint16_t sequenceNumber,
1413 bool first_includes_start, bool last_includes_end,
1414 bool is_resegmented _U_,
1415 rlc_3gpp_tap_info *tap_info,
1416 proto_tree *tree)
1418 channel_hash_key channel_key;
1419 channel_hash_key *p_channel_key;
1420 channel_sequence_analysis_status *p_channel_status;
1421 sequence_analysis_report *p_report_in_frame = NULL;
1422 bool createdChannel = false;
1423 uint16_t expectedSequenceNumber = 0;
1424 uint32_t snLimit = 0;
1426 /* If find stat_report_in_frame already, use that and get out */
1427 if (pinfo->fd->visited) {
1428 p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1429 get_report_hash_key(sequenceNumber,
1430 pinfo->num,
1431 p_rlc_lte_info,
1432 false));
1433 if (p_report_in_frame != NULL) {
1434 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
1435 sequenceNumber, first_includes_start,
1436 tap_info, pinfo, tree, tvb);
1437 return p_report_in_frame->state;
1440 /* Don't just give up here... */
1444 /**************************************************/
1445 /* Create or find an entry for this channel state */
1446 channel_key.ueId = p_rlc_lte_info->ueid;
1447 channel_key.channelType = p_rlc_lte_info->channelType;
1448 channel_key.channelId = p_rlc_lte_info->channelId;
1449 channel_key.direction = p_rlc_lte_info->direction;
1451 /* Do the table lookup */
1452 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1454 /* Create table entry if necessary */
1455 if (p_channel_status == NULL) {
1456 createdChannel = true;
1458 /* Allocate a new value and duplicate key contents */
1459 p_channel_status = wmem_new0(wmem_file_scope(), channel_sequence_analysis_status);
1460 p_channel_key = (channel_hash_key *)wmem_memdup(wmem_file_scope(), &channel_key, sizeof(channel_hash_key));
1462 /* Set mode */
1463 p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1465 /* Add entry */
1466 wmem_map_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1469 /* Create space for frame state_report */
1470 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1473 /* Deal with according to channel mode */
1474 switch (p_channel_status->rlcMode) {
1475 case RLC_UM_MODE:
1477 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1478 snLimit = 32;
1480 else {
1481 snLimit = 1024;
1484 /* Work out expected sequence number */
1485 if (!createdChannel) {
1486 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1488 else {
1489 /* Whatever we got is fine.. */
1490 expectedSequenceNumber = sequenceNumber;
1493 if ((sequenceNumber == 0) &&
1494 ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH))) {
1495 /* With eMBMS, SN restarts to 0 at each MCH Scheduling Period so we cannot deduce easily whether
1496 there was a PDU loss or not without analysing the Frame Indicator; assume no loss when seeing 0 */
1497 expectedSequenceNumber = 0;
1500 /* Set report for this frame */
1501 /* For UM, sequence number is always expectedSequence number */
1502 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
1504 /* For wrong sequence number... */
1505 if (!p_report_in_frame->sequenceExpectedCorrect) {
1507 /* Don't get confused by MAC (HARQ) retx */
1508 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1509 p_report_in_frame->state = SN_MAC_Retx;
1510 p_report_in_frame->firstSN = sequenceNumber;
1512 /* No channel state to update */
1513 break;
1516 /* Frames are not missing if we get an earlier sequence number again */
1517 /* TODO: taking time into account would give better idea of whether missing or repeated... */
1518 else if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH) ||
1519 (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10)) {
1520 reassembly_destroy(p_channel_status);
1522 p_report_in_frame->state = SN_Missing;
1523 tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
1524 p_report_in_frame->firstSN = expectedSequenceNumber;
1525 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
1527 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1528 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1529 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1531 /* Update channel status to remember *this* frame */
1532 p_channel_status->previousFrameNum = pinfo->num;
1533 p_channel_status->previousSequenceNumber = sequenceNumber;
1534 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1536 else {
1537 /* An SN has been repeated */
1538 p_report_in_frame->state = SN_Repeated;
1539 p_report_in_frame->firstSN = sequenceNumber;
1541 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1542 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1545 else {
1546 /* SN was OK */
1547 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1548 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1549 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1551 /* Update channel status to remember *this* frame */
1552 p_channel_status->previousFrameNum = pinfo->num;
1553 p_channel_status->previousSequenceNumber = sequenceNumber;
1554 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1556 if (p_channel_status->reassembly_info) {
1557 /* Add next segment to reassembly info */
1558 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1559 tvb, firstSegmentOffset, firstSegmentLength);
1561 /* The end of existing reassembly? */
1562 if (!first_includes_start &&
1563 ((number_of_segments > 1) || last_includes_end)) {
1565 reassembly_record(p_channel_status, pinfo, sequenceNumber, p_rlc_lte_info);
1566 reassembly_destroy(p_channel_status);
1570 /* The start of a new reassembly? */
1571 if (!last_includes_end &&
1572 ((number_of_segments > 1) || first_includes_start)) {
1574 uint16_t lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1576 if (global_rlc_lte_reassembly) {
1577 reassembly_reset(p_channel_status);
1578 reassembly_add_segment(p_channel_status, sequenceNumber,
1579 pinfo->num,
1580 tvb, lastSegmentOffset, lastSegmentLength);
1584 if (p_report_in_frame->previousFrameNum != 0) {
1585 /* Get report for previous frame */
1586 sequence_analysis_report *p_previous_report;
1587 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1588 snLimit = 32;
1590 else {
1591 snLimit = 1024;
1594 /* Look up report for previous SN */
1595 p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1596 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1597 p_report_in_frame->previousFrameNum,
1598 p_rlc_lte_info,
1599 false));
1600 /* It really shouldn't be NULL... */
1601 if (p_previous_report != NULL) {
1602 /* Point it forward to this one */
1603 p_previous_report->nextFrameNum = pinfo->num;
1608 break;
1610 case RLC_AM_MODE:
1612 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1613 snLimit = 65536;
1614 } else {
1615 snLimit = 1024;
1618 /* Work out expected sequence number */
1619 if (!createdChannel) {
1620 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1622 else {
1623 /* Whatever we got is fine.. */
1624 expectedSequenceNumber = sequenceNumber;
1627 /* For AM, may be:
1628 - expected Sequence number OR
1629 - previous frame repeated
1630 - old SN being sent (in response to NACK)
1631 - new SN, but with frames missed out
1632 Assume window whose front is at expectedSequenceNumber */
1634 /* First of all, check to see whether frame is judged to be MAC Retx */
1635 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1636 /* Just report that this is a MAC Retx */
1637 p_report_in_frame->state = SN_MAC_Retx;
1638 p_report_in_frame->firstSN = sequenceNumber;
1640 /* No channel state to update */
1641 break;
1644 if (sequenceNumber != expectedSequenceNumber) {
1645 /* Don't trash reassembly info if this looks like a close retx... */
1646 if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 50) {
1647 reassembly_destroy(p_channel_status);
1651 /* Expected? */
1652 if (sequenceNumber == expectedSequenceNumber) {
1653 /* Set report for this frame */
1654 p_report_in_frame->sequenceExpectedCorrect = true;
1655 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1656 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1657 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1658 p_report_in_frame->state = SN_OK;
1660 /* Update channel status */
1661 p_channel_status->previousSequenceNumber = sequenceNumber;
1662 p_channel_status->previousFrameNum = pinfo->num;
1663 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1666 if (p_channel_status->reassembly_info) {
1668 /* Add next segment to reassembly info */
1669 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1670 tvb, firstSegmentOffset, firstSegmentLength);
1672 /* The end of existing reassembly? */
1673 if (!first_includes_start &&
1674 ((number_of_segments > 1) || last_includes_end)) {
1676 reassembly_record(p_channel_status, pinfo,
1677 sequenceNumber, p_rlc_lte_info);
1678 reassembly_destroy(p_channel_status);
1682 /* The start of a new reassembly? */
1683 if (!last_includes_end &&
1684 ((number_of_segments > 1) || first_includes_start)) {
1686 uint16_t lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1687 if (global_rlc_lte_reassembly) {
1688 reassembly_reset(p_channel_status);
1689 reassembly_add_segment(p_channel_status, sequenceNumber,
1690 pinfo->num,
1691 tvb, lastSegmentOffset, lastSegmentLength);
1695 if (p_report_in_frame->previousFrameNum != 0) {
1696 /* Get report for previous frame */
1697 sequence_analysis_report *p_previous_report;
1698 p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1699 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1700 p_report_in_frame->previousFrameNum,
1701 p_rlc_lte_info,
1702 false));
1703 /* It really shouldn't be NULL... */
1704 if (p_previous_report != NULL) {
1705 /* Point it forward to this one */
1706 p_previous_report->nextFrameNum = pinfo->num;
1712 /* Previous subframe repeated? */
1713 else if (((sequenceNumber+1) % snLimit) == expectedSequenceNumber) {
1714 p_report_in_frame->state = SN_Repeated;
1716 /* Set report for this frame */
1717 p_report_in_frame->sequenceExpectedCorrect = false;
1718 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1719 p_report_in_frame->firstSN = sequenceNumber;
1720 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1721 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1724 /* Really should be nothing to update... */
1725 p_channel_status->previousSequenceNumber = sequenceNumber;
1726 p_channel_status->previousFrameNum = pinfo->num;
1727 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1730 else {
1731 /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1732 int delta = (snLimit + expectedSequenceNumber - sequenceNumber) % snLimit;
1734 /* Rx window is 512/32768, so check to see if this is a retx */
1735 if (delta < (int)(snLimit>>1)) {
1736 /* Probably a retx due to receiving NACK */
1737 p_report_in_frame->state = SN_Retx;
1739 p_report_in_frame->firstSN = sequenceNumber;
1740 /* Don't update anything in channel state */
1743 else {
1744 /* Ahead of expected SN. Assume frames have been missed */
1745 p_report_in_frame->state = SN_Missing;
1747 p_report_in_frame->firstSN = expectedSequenceNumber;
1748 p_report_in_frame->lastSN = (snLimit + sequenceNumber-1) % snLimit;
1750 /* Update channel state - forget about missed SNs */
1751 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1752 p_channel_status->previousSequenceNumber = sequenceNumber;
1753 p_channel_status->previousFrameNum = pinfo->num;
1754 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1757 break;
1759 default:
1760 /* Shouldn't get here! */
1761 return SN_Error;
1764 /* Associate with this frame number */
1765 wmem_map_insert(sequence_analysis_report_hash,
1766 get_report_hash_key(sequenceNumber, pinfo->num, p_rlc_lte_info, true),
1767 p_report_in_frame);
1769 /* Add state report for this frame into tree */
1770 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1771 first_includes_start, tap_info, pinfo, tree, tvb);
1773 return p_report_in_frame->state;
1777 /* Add to the tree values associated with sequence analysis for this frame */
1778 static void addChannelRepeatedNACKInfo(channel_repeated_nack_report *p,
1779 rlc_lte_info *p_rlc_lte_info,
1780 packet_info *pinfo, proto_tree *tree,
1781 tvbuff_t *tvb)
1783 proto_tree *seqnum_tree;
1784 proto_item *seqnum_ti;
1785 proto_item *ti;
1786 int n;
1788 /* Create subtree */
1789 seqnum_ti = proto_tree_add_string_format(tree,
1790 hf_rlc_lte_sequence_analysis,
1791 tvb, 0, 0,
1792 "", "Sequence Analysis");
1793 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1794 ett_rlc_lte_sequence_analysis);
1795 proto_item_set_generated(seqnum_ti);
1797 /* OK = false */
1798 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1799 tvb, 0, 0, false);
1800 proto_item_set_generated(ti);
1802 /* Add each repeated NACK as item & expert info */
1803 for (n=0; n < p->noOfNACKsRepeated; n++) {
1805 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
1806 tvb, 0, 0, p->repeatedNACKs[n]);
1807 proto_item_set_generated(ti);
1809 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated_nack,
1810 "Same SN (%u) NACKd for %s on UE %u in successive Status PDUs",
1811 p->repeatedNACKs[n],
1812 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1813 p_rlc_lte_info->ueid);
1816 /* Link back to previous status report */
1817 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
1818 tvb, 0, 0, p->previousFrameNum);
1819 proto_item_set_generated(ti);
1821 /* Append count to sequence analysis root */
1822 proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
1823 p->noOfNACKsRepeated);
1827 /* Update the channel repeated NACK status and set report for this frame */
1828 static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
1829 rlc_lte_info *p_rlc_lte_info,
1830 rlc_3gpp_tap_info *tap_info,
1831 proto_tree *tree,
1832 tvbuff_t *tvb)
1834 channel_hash_key channel_key;
1835 channel_hash_key *p_channel_key;
1836 channel_repeated_nack_status *p_channel_status;
1837 channel_repeated_nack_report *p_report_in_frame = NULL;
1839 uint16_t noOfNACKsRepeated = 0;
1840 uint16_t repeatedNACKs[MAX_NACKs];
1841 int n, i, j;
1843 /* If find state_report_in_frame already, use that and get out */
1844 if (pinfo->fd->visited) {
1845 p_report_in_frame = (channel_repeated_nack_report*)wmem_map_lookup(repeated_nack_report_hash,
1846 get_report_hash_key(0, pinfo->num,
1847 p_rlc_lte_info, false));
1848 if (p_report_in_frame != NULL) {
1849 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1850 pinfo, tree, tvb);
1851 return;
1853 else {
1854 /* Give up - we must have tried already... */
1855 return;
1860 /**************************************************/
1861 /* Create or find an entry for this channel state */
1862 channel_key.ueId = p_rlc_lte_info->ueid;
1863 channel_key.channelType = p_rlc_lte_info->channelType;
1864 channel_key.channelId = p_rlc_lte_info->channelId;
1865 channel_key.direction = p_rlc_lte_info->direction;
1866 memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1868 /* Do the table lookup */
1869 p_channel_status = (channel_repeated_nack_status*)wmem_map_lookup(repeated_nack_channel_hash, &channel_key);
1871 /* Create table entry if necessary */
1872 if (p_channel_status == NULL) {
1874 /* Allocate a new key and value */
1875 p_channel_key = wmem_new(wmem_file_scope(), channel_hash_key);
1876 p_channel_status = wmem_new0(wmem_file_scope(), channel_repeated_nack_status);
1878 /* Copy key contents */
1879 memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1881 /* Add entry to table */
1882 wmem_map_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1885 /* Compare NACKs in channel status with NACKs in tap_info.
1886 Note any that are repeated */
1887 for (i=0; i < p_channel_status->noOfNACKs; i++) {
1888 for (j=0; j < MIN(tap_info->noOfNACKs, MAX_NACKs); j++) {
1889 if (tap_info->NACKs[j] == p_channel_status->NACKs[i]) {
1890 /* Don't add the same repeated NACK twice! */
1891 if ((noOfNACKsRepeated == 0) ||
1892 (repeatedNACKs[noOfNACKsRepeated-1] != p_channel_status->NACKs[i])) {
1894 repeatedNACKs[noOfNACKsRepeated++] = p_channel_status->NACKs[i];
1900 /* Copy NACKs from tap_info into channel status for next time! */
1901 p_channel_status->noOfNACKs = 0;
1902 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1903 p_channel_status->NACKs[p_channel_status->noOfNACKs++] = tap_info->NACKs[n];
1906 if (noOfNACKsRepeated >= 1) {
1907 /* Create space for frame state_report */
1908 p_report_in_frame = wmem_new(wmem_file_scope(), channel_repeated_nack_report);
1910 /* Copy in found duplicates */
1911 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1912 p_report_in_frame->repeatedNACKs[n] = repeatedNACKs[n];
1914 p_report_in_frame->noOfNACKsRepeated = noOfNACKsRepeated;
1916 p_report_in_frame->previousFrameNum = p_channel_status->frameNum;
1918 /* Associate with this frame number */
1919 wmem_map_insert(repeated_nack_report_hash,
1920 get_report_hash_key(0, pinfo->num,
1921 p_rlc_lte_info, true),
1922 p_report_in_frame);
1924 /* Add state report for this frame into tree */
1925 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1926 pinfo, tree, tvb);
1929 /* Save frame number for next comparison */
1930 p_channel_status->frameNum = pinfo->num;
1933 /* Check that the ACK is consistent with data the expected sequence number
1934 in the other direction */
1935 static void checkChannelACKWindow(uint16_t ack_sn,
1936 packet_info *pinfo,
1937 rlc_lte_info *p_rlc_lte_info,
1938 rlc_3gpp_tap_info *tap_info,
1939 proto_tree *tree,
1940 tvbuff_t *tvb)
1942 channel_hash_key channel_key;
1943 channel_sequence_analysis_status *p_channel_status;
1944 sequence_analysis_report *p_report_in_frame = NULL;
1945 uint32_t snLimit;
1947 /* If find stat_report_in_frame already, use that and get out */
1948 if (pinfo->fd->visited) {
1949 p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1950 get_report_hash_key(0, pinfo->num,
1951 p_rlc_lte_info,
1952 false));
1953 if (p_report_in_frame != NULL) {
1954 /* Add any info to tree */
1955 addChannelSequenceInfo(p_report_in_frame, true, p_rlc_lte_info,
1956 0, false,
1957 tap_info, pinfo, tree, tvb);
1958 return;
1960 else {
1961 /* Give up - we must have tried already... */
1962 return;
1966 /*******************************************************************/
1967 /* Find an entry for this channel state (in the opposite direction */
1968 channel_key.ueId = p_rlc_lte_info->ueid;
1969 channel_key.channelType = p_rlc_lte_info->channelType;
1970 channel_key.channelId = p_rlc_lte_info->channelId;
1971 channel_key.direction =
1972 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1974 /* Do the table lookup */
1975 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1977 /* Create table entry if necessary */
1978 if (p_channel_status == NULL) {
1979 return;
1982 /* Is it in the rx window? This test will catch if it's ahead, but we don't
1983 really know what the back of the tx window is... */
1984 snLimit = (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) ? 65536 : 1024;
1985 if (((snLimit + (uint32_t)p_channel_status->previousSequenceNumber+1 - ack_sn) % snLimit) > (snLimit>>1)) {
1987 /* Set result */
1988 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1989 p_report_in_frame->state = ACK_Out_of_Window;
1990 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1991 p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1992 p_report_in_frame->firstSN = ack_sn;
1994 /* Associate with this frame number */
1995 wmem_map_insert(sequence_analysis_report_hash,
1996 get_report_hash_key(0, pinfo->num,
1997 p_rlc_lte_info, true),
1998 p_report_in_frame);
2000 /* Add state report for this frame into tree */
2001 addChannelSequenceInfo(p_report_in_frame, true, p_rlc_lte_info, 0,
2002 false, tap_info, pinfo, tree, tvb);
2009 /***************************************************/
2010 /* Transparent mode PDU. Call RRC if configured to */
2011 static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
2012 proto_tree *tree,
2013 int offset,
2014 rlc_lte_info *p_rlc_lte_info,
2015 proto_item *top_ti)
2017 proto_item *raw_tm_ti;
2018 proto_item *tm_ti;
2020 /* Create hidden TM root */
2021 tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
2022 tvb, offset, 0, "", "TM");
2023 proto_item_set_hidden(tm_ti);
2025 /* Remaining bytes are all data */
2026 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, ENC_NA);
2027 if (!global_rlc_lte_call_rrc_for_ccch) {
2028 write_pdu_label_and_info(top_ti, NULL, pinfo,
2029 " [%u-bytes]", tvb_reported_length_remaining(tvb, offset));
2032 if (global_rlc_lte_call_rrc_for_ccch) {
2033 tvbuff_t *rrc_tvb = tvb_new_subset_remaining(tvb, offset);
2034 volatile dissector_handle_t protocol_handle;
2036 switch (p_rlc_lte_info->channelType) {
2037 case CHANNEL_TYPE_CCCH:
2038 if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
2039 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2040 lte_rrc_ul_ccch_nb : lte_rrc_ul_ccch;
2042 else {
2043 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2044 lte_rrc_dl_ccch_nb : lte_rrc_dl_ccch;
2046 break;
2048 case CHANNEL_TYPE_BCCH_BCH:
2049 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2050 lte_rrc_bcch_bch_nb : lte_rrc_bcch_bch;
2051 break;
2052 case CHANNEL_TYPE_BCCH_DL_SCH:
2053 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2054 lte_rrc_bcch_dl_sch_nb : lte_rrc_bcch_dl_sch;
2055 break;
2056 case CHANNEL_TYPE_PCCH:
2057 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2058 lte_rrc_pcch_nb : lte_rrc_pcch;
2059 break;
2061 case CHANNEL_TYPE_SRB:
2062 case CHANNEL_TYPE_DRB:
2063 case CHANNEL_TYPE_MCCH:
2064 case CHANNEL_TYPE_MTCH:
2066 default:
2067 /* Shouldn't happen, just return... */
2068 return;
2071 /* Hide raw view of bytes */
2072 proto_item_set_hidden(raw_tm_ti);
2074 /* Call it (catch exceptions) */
2075 TRY {
2076 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
2078 CATCH_ALL {
2080 ENDTRY
2086 /***************************************************/
2087 /* Unacknowledged mode PDU */
2088 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
2089 proto_tree *tree,
2090 int offset,
2091 rlc_lte_info *p_rlc_lte_info,
2092 proto_item *top_ti,
2093 rlc_3gpp_tap_info *tap_info)
2095 uint64_t framing_info;
2096 bool first_includes_start;
2097 bool last_includes_end;
2098 uint64_t fixed_extension;
2099 uint64_t sn;
2100 int start_offset = offset;
2101 proto_item *um_ti;
2102 proto_tree *um_header_tree;
2103 proto_item *um_header_ti;
2104 bool is_truncated = false;
2105 proto_item *truncated_ti;
2106 rlc_channel_reassembly_info *reassembly_info = NULL;
2107 sequence_analysis_state seq_anal_state = SN_OK;
2109 /* Hidden UM root */
2110 um_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um,
2111 tvb, offset, 0, "", "UM");
2112 proto_item_set_hidden(um_ti);
2114 /* Add UM header subtree */
2115 um_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um_header,
2116 tvb, offset, 0,
2117 "", "UM header");
2118 um_header_tree = proto_item_add_subtree(um_header_ti,
2119 ett_rlc_lte_um_header);
2122 /*******************************/
2123 /* Fixed UM header */
2124 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
2125 /* Framing info (2 bits) */
2126 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2127 tvb, offset*8, 2,
2128 &framing_info, ENC_BIG_ENDIAN);
2130 /* Extension (1 bit) */
2131 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2132 (offset*8) + 2, 1,
2133 &fixed_extension, ENC_BIG_ENDIAN);
2135 /* Sequence Number (5 bit) */
2136 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2137 (offset*8) + 3, 5,
2138 &sn, ENC_BIG_ENDIAN);
2139 offset++;
2141 else if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_10_BITS) {
2142 uint32_t reserved;
2143 proto_item *ti;
2145 /* Check 3 Reserved bits */
2146 ti = proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2147 if (reserved != 0) {
2148 expert_add_info_format(pinfo, ti, &ei_rlc_lte_reserved_bits_not_zero,
2149 "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
2152 /* Framing info (2 bits) */
2153 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2154 tvb, (offset*8)+3, 2,
2155 &framing_info, ENC_BIG_ENDIAN);
2157 /* Extension (1 bit) */
2158 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2159 (offset*8) + 5, 1,
2160 &fixed_extension, ENC_BIG_ENDIAN);
2162 /* Sequence Number (10 bits) */
2163 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2164 (offset*8) + 6, 10,
2165 &sn, ENC_BIG_ENDIAN);
2166 offset += 2;
2168 else {
2169 /* Invalid length of sequence number */
2170 proto_tree_add_expert_format(um_header_tree, pinfo, &ei_rlc_lte_um_sn, tvb, 0, 0,
2171 "Invalid sequence number length (%u bits)",
2172 p_rlc_lte_info->sequenceNumberLength);
2173 return;
2176 tap_info->sequenceNumberGiven = true;
2177 tap_info->sequenceNumber = (uint16_t)sn;
2179 /* Show SN in info column */
2180 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2181 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (uint16_t)sn);
2183 else {
2184 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (uint16_t)sn);
2187 proto_item_set_len(um_header_ti, offset-start_offset);
2190 /*************************************/
2191 /* UM header extension */
2192 if (fixed_extension) {
2193 offset = dissect_rlc_lte_extension_header(tvb, pinfo, um_header_tree, offset, p_rlc_lte_info);
2196 /* Extract these 2 flags from framing_info */
2197 first_includes_start = ((uint8_t)framing_info & 0x02) == 0;
2198 last_includes_end = ((uint8_t)framing_info & 0x01) == 0;
2200 if (global_rlc_lte_headers_expected) {
2201 /* There might not be any data, if only headers (plus control data) were logged */
2202 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2203 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2204 is_truncated);
2205 if (is_truncated) {
2206 int n;
2207 proto_item_set_generated(truncated_ti);
2208 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2210 /* Show in the info column how long the data would be */
2211 for (n=0; n < s_number_of_extensions; n++) {
2212 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2213 (n==0) ? first_includes_start : true,
2214 true);
2215 offset += s_lengths[n];
2217 /* Last one */
2218 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2219 (s_number_of_extensions == 0) ? first_includes_start : true,
2220 last_includes_end);
2222 else {
2223 proto_item_set_hidden(truncated_ti);
2227 /* Show number of extensions in header root */
2228 if (s_number_of_extensions > 0) {
2229 proto_item_append_text(um_header_ti, " (%u extensions)", s_number_of_extensions);
2232 /* Call sequence analysis function now */
2233 if (((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2234 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2235 ((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2236 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2238 uint16_t lastSegmentOffset = offset;
2239 if (s_number_of_extensions >= 1) {
2240 int n;
2241 lastSegmentOffset = offset;
2242 for (n=0; n < s_number_of_extensions; n++) {
2243 lastSegmentOffset += s_lengths[n];
2247 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
2248 false,
2249 s_number_of_extensions+1,
2250 offset,
2251 s_number_of_extensions ?
2252 s_lengths[0] :
2253 p_rlc_lte_info->pduLength - offset,
2254 lastSegmentOffset,
2255 (uint16_t)sn, first_includes_start, last_includes_end,
2256 false, /* UM doesn't re-segment */
2257 tap_info, um_header_tree);
2260 if (is_truncated) {
2261 return;
2264 /*************************************/
2265 /* Data */
2267 reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2268 get_report_hash_key((uint16_t)sn, pinfo->num,
2269 p_rlc_lte_info, false));
2271 if (s_number_of_extensions > 0) {
2272 /* Show each data segment separately */
2273 int n;
2274 for (n=0; n < s_number_of_extensions; n++) {
2275 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2276 (n==0) ? first_includes_start : true,
2277 (n==0) ? reassembly_info : NULL,
2278 seq_anal_state);
2279 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2280 (n==0) ? first_includes_start : true,
2281 true);
2282 /* Make sure we don't lose the summary of this SDU */
2283 col_append_str(pinfo->cinfo, COL_INFO, " | ");
2284 col_set_fence(pinfo->cinfo, COL_INFO);
2286 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2287 offset += s_lengths[n];
2291 /* Final data element */
2292 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2293 ((s_number_of_extensions == 0) ? first_includes_start : true) && last_includes_end,
2294 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2295 seq_anal_state);
2296 show_PDU_in_info(pinfo, top_ti, (uint16_t)tvb_reported_length_remaining(tvb, offset),
2297 (s_number_of_extensions == 0) ? first_includes_start : true,
2298 last_includes_end);
2303 /* Dissect an AM STATUS PDU */
2304 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
2305 packet_info *pinfo,
2306 proto_tree *tree,
2307 proto_item *status_ti,
2308 int offset,
2309 proto_item *top_ti,
2310 rlc_lte_info *p_rlc_lte_info,
2311 rlc_3gpp_tap_info *tap_info)
2313 uint32_t cpt;
2314 uint8_t sn_size, so_size;
2315 uint32_t sn_limit;
2316 uint64_t ack_sn, nack_sn;
2317 uint16_t nack_count = 0, so_end_of_pdu;
2318 uint64_t e1 = 0, e2 = 0;
2319 uint64_t so_start, so_end;
2320 int bit_offset = offset * 8;
2321 proto_item *ti;
2323 /****************************************************************/
2324 /* Part of RLC control PDU header */
2326 /* Control PDU Type (CPT) */
2327 ti = proto_tree_add_item_ret_uint(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN, &cpt);
2328 if (cpt != 0) {
2329 /* Protest and stop - only know about STATUS PDUs */
2330 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_cpt,
2331 "RLC Control frame type %u not handled", cpt);
2332 return;
2335 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2336 sn_size = 16;
2337 sn_limit = 65536;
2338 so_size = 16;
2339 so_end_of_pdu = 0xffff;
2340 } else {
2341 sn_size = 10;
2342 sn_limit = 1024;
2343 so_size = 15;
2344 so_end_of_pdu = 0x7fff;
2347 /* The Status PDU itself starts 4 bits into the byte */
2348 bit_offset += 4;
2350 /* ACK SN */
2351 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2352 bit_offset, sn_size, &ack_sn, ENC_BIG_ENDIAN);
2353 bit_offset += sn_size;
2354 write_pdu_label_and_info(top_ti, status_ti, pinfo, " ACK_SN=%-4u", (uint16_t)ack_sn);
2356 tap_info->ACKNo = (uint16_t)ack_sn;
2358 /* E1 */
2359 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2360 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2362 /* Skip another bit to byte-align the next bit... */
2363 bit_offset++;
2365 /* Optional, extra fields */
2366 do {
2367 if (e1) {
2368 proto_item *nack_ti;
2370 /****************************/
2371 /* Read NACK_SN, E1, E2 */
2373 /* NACK_SN */
2374 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
2375 bit_offset, sn_size, &nack_sn, ENC_BIG_ENDIAN);
2376 bit_offset += sn_size;
2377 write_pdu_label_and_info(top_ti, NULL, pinfo, " NACK_SN=%-4u", (uint16_t)nack_sn);
2379 /* We shouldn't NACK the ACK_SN! */
2380 if (nack_sn == ack_sn) {
2381 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ack_same,
2382 "Status PDU shouldn't ACK and NACK the same sequence number (%" PRIu64 ")",
2383 ack_sn);
2386 /* NACK should always be 'behind' the ACK */
2387 if ((sn_limit + ack_sn - nack_sn) % sn_limit > (sn_limit>>1)) {
2388 expert_add_info(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ahead_ack);
2391 /* Copy into struct, but don't exceed buffer */
2392 if (nack_count < MAX_NACKs) {
2393 tap_info->NACKs[nack_count++] = (uint16_t)nack_sn;
2395 else {
2396 /* Let it get bigger than the array for accurate stats... */
2397 nack_count++;
2400 /* E1 */
2401 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2402 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2403 bit_offset++;
2405 /* E2 */
2406 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
2407 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
2409 /* Report as expert info */
2410 if (e2) {
2411 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_partial,
2412 "Status PDU reports NACK (partial) on %s for UE %u",
2413 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2414 p_rlc_lte_info->ueid);
2416 else {
2417 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn,
2418 "Status PDU reports NACK on %s for UE %u",
2419 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2420 p_rlc_lte_info->ueid);
2423 bit_offset++;
2426 if (e2) {
2427 /* Read SOstart, SOend */
2428 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
2429 bit_offset, so_size, &so_start, ENC_BIG_ENDIAN);
2430 bit_offset += so_size;
2432 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
2433 bit_offset, so_size, &so_end, ENC_BIG_ENDIAN);
2434 bit_offset += so_size;
2437 if ((uint16_t)so_end == so_end_of_pdu) {
2438 write_pdu_label_and_info(top_ti, NULL, pinfo,
2439 " (SOstart=%u SOend=<END-OF_PDU>)",
2440 (uint16_t)so_start);
2442 else {
2443 write_pdu_label_and_info(top_ti, NULL, pinfo,
2444 " (SOstart=%u SOend=%u)",
2445 (uint16_t)so_start, (uint16_t)so_end);
2448 /* Reset this flag here */
2449 e2 = 0;
2451 } while (e1);
2453 if (nack_count > 0) {
2454 proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
2455 proto_item_set_generated(count_ti);
2456 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
2457 tap_info->noOfNACKs = nack_count;
2460 /* Check that we've reached the end of the PDU. If not, show malformed */
2461 offset = (bit_offset+7) / 8;
2462 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2463 expert_add_info_format(pinfo, status_ti, &ei_rlc_lte_bytes_after_status_pdu_complete,
2464 "%cL %u bytes remaining after Status PDU complete",
2465 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2466 tvb_reported_length_remaining(tvb, offset));
2469 /* Set selected length of control tree */
2470 proto_item_set_len(status_ti, offset);
2472 /* Repeated NACK analysis & check ACK-SN is in range */
2473 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2474 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2475 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2476 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2478 if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2479 checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2480 checkChannelACKWindow((uint16_t)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2486 /***************************************************/
2487 /* Acknowledged mode PDU */
2488 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
2489 proto_tree *tree,
2490 int offset,
2491 rlc_lte_info *p_rlc_lte_info,
2492 proto_item *top_ti,
2493 rlc_3gpp_tap_info *tap_info)
2495 bool is_data;
2496 uint32_t is_resegmented;
2497 uint32_t polling;
2498 uint32_t fixed_extension;
2499 uint32_t framing_info;
2500 bool first_includes_start;
2501 bool last_includes_end;
2502 proto_item *am_ti;
2503 proto_tree *am_header_tree;
2504 proto_item *am_header_ti;
2505 int start_offset = offset;
2506 uint32_t sn;
2507 bool is_truncated = false;
2508 proto_item *truncated_ti;
2509 rlc_channel_reassembly_info *reassembly_info = NULL;
2510 sequence_analysis_state seq_anal_state = SN_OK;
2511 uint32_t id;
2512 wmem_tree_key_t key[3];
2513 rlc_ue_parameters *params;
2515 /* Hidden AM root */
2516 am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2517 tvb, offset, 0, "", "AM");
2518 proto_item_set_hidden(am_ti);
2520 /* Add AM header subtree */
2521 am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2522 tvb, offset, 0,
2523 "", "AM Header ");
2524 am_header_tree = proto_item_add_subtree(am_header_ti,
2525 ett_rlc_lte_am_header);
2527 /* First bit is Data/Control flag */
2528 proto_tree_add_item_ret_boolean(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN, &is_data);
2529 tap_info->isControlPDU = !is_data;
2531 if (!is_data) {
2532 /**********************/
2533 /* Status PDU */
2534 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
2536 /* Control PDUs are a completely separate format */
2537 dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2538 offset, top_ti,
2539 p_rlc_lte_info, tap_info);
2540 return;
2543 /******************************/
2544 /* Data PDU fixed header */
2546 /* Re-segmentation Flag (RF) field */
2547 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1,
2548 ENC_BIG_ENDIAN, &is_resegmented);
2549 tap_info->isResegmented = is_resegmented;
2551 write_pdu_label_and_info_literal(top_ti, NULL, pinfo,
2552 (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2554 /* Polling bit */
2555 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1,
2556 ENC_BIG_ENDIAN, &polling);
2558 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : " ");
2559 if (polling) {
2560 proto_item_append_text(am_header_ti, " (P) ");
2563 /* Framing Info */
2564 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1,
2565 ENC_BIG_ENDIAN, &framing_info);
2567 /* Extension bit */
2568 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1,
2569 ENC_BIG_ENDIAN, &fixed_extension);
2571 /* Sequence Number */
2572 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2573 uint32_t reserved;
2575 if (is_resegmented) {
2576 /* Last Segment Field (LSF) */
2577 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf16, tvb, offset, 1, ENC_BIG_ENDIAN);
2578 /* Reserved (R1) */
2579 am_ti = proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2580 } else {
2581 /* Reserved (R1) */
2582 am_ti = proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2584 if (reserved != 0) {
2585 expert_add_info_format(pinfo, am_ti, &ei_rlc_lte_reserved_bits_not_zero,
2586 "RLC AM Fixed header Reserved bits not zero (found 0x02%x)", reserved);
2588 offset += 1;
2589 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_sn16, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
2590 offset += 2;
2591 } else {
2592 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
2593 offset += 2;
2595 tap_info->sequenceNumberGiven = true;
2596 tap_info->sequenceNumber = sn;
2598 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2600 /***************************************/
2601 /* Dissect extra segment header fields */
2602 if (is_resegmented) {
2603 uint32_t segmentOffset;
2605 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2606 /* SO */
2607 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_segment_so16, tvb, offset, 2, ENC_BIG_ENDIAN, &segmentOffset);
2608 } else {
2609 /* Last Segment Field (LSF) */
2610 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2612 /* SO */
2613 proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN, &segmentOffset);
2615 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2616 offset += 2;
2619 /*************************************/
2620 /* AM header extension */
2621 if (fixed_extension) {
2622 if (!PINFO_FD_VISITED(pinfo)) {
2623 id = (p_rlc_lte_info->channelId << 16) | p_rlc_lte_info->ueid;
2624 key[0].length = 1;
2625 key[0].key = &id;
2626 key[1].length = 1;
2627 key[1].key = &pinfo->num;
2628 key[2].length = 0;
2629 key[2].key = NULL;
2630 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
2631 if (params && (params->id == id)) {
2632 p_rlc_lte_info->extendedLiField = (p_rlc_lte_info->direction == DIRECTION_UPLINK) ?
2633 (params->ext_li_field & UL_EXT_LI): (params->ext_li_field & DL_EXT_LI);
2636 offset = dissect_rlc_lte_extension_header(tvb, pinfo, am_header_tree, offset, p_rlc_lte_info);
2639 /* Header is now complete */
2640 proto_item_set_len(am_header_ti, offset-start_offset);
2642 /* Show number of extensions in header root */
2643 if (s_number_of_extensions > 0) {
2644 proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2647 /* Extract these 2 flags from framing_info */
2648 first_includes_start = (framing_info & 0x02) == 0;
2649 last_includes_end = (framing_info & 0x01) == 0;
2651 /* There might not be any data, if only headers (plus control data) were logged */
2652 if (global_rlc_lte_headers_expected) {
2653 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2654 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2655 is_truncated);
2656 if (is_truncated) {
2657 int n;
2658 proto_item_set_generated(truncated_ti);
2659 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2660 /* Show in the info column how long the data would be */
2661 for (n=0; n < s_number_of_extensions; n++) {
2662 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2663 (n==0) ? first_includes_start : true,
2664 true);
2665 offset += s_lengths[n];
2667 /* Last one */
2668 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2669 (s_number_of_extensions == 0) ? first_includes_start : true,
2670 last_includes_end);
2672 else {
2673 proto_item_set_hidden(truncated_ti);
2677 /* Call sequence analysis function now */
2678 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2679 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2680 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2681 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2683 uint16_t firstSegmentLength;
2684 uint16_t lastSegmentOffset = offset;
2685 if (s_number_of_extensions >= 1) {
2686 int n;
2687 for (n=0; n < s_number_of_extensions; n++) {
2688 lastSegmentOffset += s_lengths[n];
2691 firstSegmentLength = s_lengths[0];
2693 else {
2694 firstSegmentLength = tvb_reported_length_remaining(tvb, offset);
2697 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, false,
2698 s_number_of_extensions+1,
2699 offset, firstSegmentLength,
2700 lastSegmentOffset,
2701 (uint16_t)sn,
2702 first_includes_start, last_includes_end,
2703 is_resegmented, tap_info, tree);
2706 if (is_truncated) {
2707 return;
2710 /*************************************/
2711 /* Data */
2713 if (!first_includes_start) {
2714 reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2715 get_report_hash_key((uint16_t)sn,
2716 pinfo->num,
2717 p_rlc_lte_info,
2718 false));
2721 if (s_number_of_extensions > 0) {
2722 /* Show each data segment separately */
2723 int n;
2724 for (n=0; n < s_number_of_extensions; n++) {
2725 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2726 (n==0) ? first_includes_start : true,
2727 (n==0) ? reassembly_info : NULL,
2728 seq_anal_state);
2729 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2730 (n==0) ? first_includes_start : true,
2731 true);
2732 /* Make sure we don't lose the summary of this SDU */
2733 col_append_str(pinfo->cinfo, COL_INFO, " | ");
2734 col_set_fence(pinfo->cinfo, COL_INFO);
2736 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2737 offset += s_lengths[n];
2741 /* Final data element */
2742 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2743 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2744 ((s_number_of_extensions == 0) ? first_includes_start : true) && last_includes_end,
2745 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2746 seq_anal_state);
2747 show_PDU_in_info(pinfo, top_ti, (uint16_t)tvb_reported_length_remaining(tvb, offset),
2748 (s_number_of_extensions == 0) ? first_includes_start : true,
2749 last_includes_end);
2751 else {
2752 /* Report that expected data was missing (unless we know it might happen) */
2753 if (!global_rlc_lte_headers_expected) {
2754 if (s_number_of_extensions > 0) {
2755 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data_beyond_extensions);
2757 else {
2758 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data);
2764 static void report_heur_error(proto_tree *tree, packet_info *pinfo, expert_field *eiindex,
2765 tvbuff_t *tvb, int start, int length)
2767 proto_item *ti;
2768 proto_tree *subtree;
2770 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2771 col_clear(pinfo->cinfo, COL_INFO);
2772 ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, 0, -1, ENC_NA);
2773 subtree = proto_item_add_subtree(ti, ett_rlc_lte);
2774 proto_tree_add_expert(subtree, pinfo, eiindex, tvb, start, length);
2777 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2778 static bool dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
2779 proto_tree *tree, void *data _U_)
2781 int offset = 0;
2782 struct rlc_lte_info *p_rlc_lte_info;
2783 tvbuff_t *rlc_tvb;
2784 uint8_t tag = 0;
2785 bool seqNumLengthTagPresent = false;
2787 /* Needs to be at least as long as:
2788 - the signature string
2789 - fixed header bytes
2790 - tag for data
2791 - at least one byte of RLC PDU payload */
2792 if (tvb_captured_length_remaining(tvb, offset) < (int)(strlen(RLC_LTE_START_STRING)+1+2)) {
2793 return false;
2796 /* OK, compare with signature string */
2797 if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (int)strlen(RLC_LTE_START_STRING)) != 0) {
2798 return false;
2800 offset += (int)strlen(RLC_LTE_START_STRING);
2803 /* If redissecting, use previous info struct (if available) */
2804 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2805 if (p_rlc_lte_info == NULL) {
2806 /* Allocate new info struct for this frame */
2807 p_rlc_lte_info = wmem_new0(wmem_file_scope(), struct rlc_lte_info);
2809 /* Read fixed fields */
2810 p_rlc_lte_info->rlcMode = tvb_get_uint8(tvb, offset++);
2811 if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2812 p_rlc_lte_info->sequenceNumberLength = AM_SN_LENGTH_10_BITS;
2815 /* Read optional fields */
2816 while (tag != RLC_LTE_PAYLOAD_TAG) {
2817 /* Process next tag */
2818 tag = tvb_get_uint8(tvb, offset++);
2819 switch (tag) {
2820 case RLC_LTE_SN_LENGTH_TAG:
2821 p_rlc_lte_info->sequenceNumberLength = tvb_get_uint8(tvb, offset);
2822 offset++;
2823 seqNumLengthTagPresent = true;
2824 break;
2825 case RLC_LTE_DIRECTION_TAG:
2826 p_rlc_lte_info->direction = tvb_get_uint8(tvb, offset);
2827 offset++;
2828 break;
2829 case RLC_LTE_PRIORITY_TAG:
2830 p_rlc_lte_info->priority = tvb_get_uint8(tvb, offset);
2831 offset++;
2832 break;
2833 case RLC_LTE_UEID_TAG:
2834 p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
2835 offset += 2;
2836 break;
2837 case RLC_LTE_CHANNEL_TYPE_TAG:
2838 p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
2839 offset += 2;
2840 break;
2841 case RLC_LTE_CHANNEL_ID_TAG:
2842 p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
2843 offset += 2;
2844 break;
2845 case RLC_LTE_EXT_LI_FIELD_TAG:
2846 p_rlc_lte_info->extendedLiField = true;
2847 break;
2848 case RLC_LTE_NB_MODE_TAG:
2849 p_rlc_lte_info->nbMode =
2850 (rlc_lte_nb_mode)tvb_get_uint8(tvb, offset);
2851 offset++;
2852 break;
2854 case RLC_LTE_PAYLOAD_TAG:
2855 /* Have reached data, so set payload length and get out of loop */
2856 p_rlc_lte_info->pduLength = tvb_reported_length_remaining(tvb, offset);
2857 continue;
2859 default:
2860 /* It must be a recognised tag */
2861 report_heur_error(tree, pinfo, &ei_rlc_lte_unknown_udp_framing_tag, tvb, offset-1, 1);
2862 wmem_free(wmem_file_scope(), p_rlc_lte_info);
2863 return true;
2867 if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (seqNumLengthTagPresent == false)) {
2868 /* Conditional field is not present */
2869 report_heur_error(tree, pinfo, &ei_rlc_lte_missing_udp_framing_tag, tvb, 0, offset);
2870 wmem_free(wmem_file_scope(), p_rlc_lte_info);
2871 return true;
2874 /* Store info in packet */
2875 p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0, p_rlc_lte_info);
2877 else {
2878 offset = tvb_reported_length(tvb) - p_rlc_lte_info->pduLength;
2881 /**************************************/
2882 /* OK, now dissect as RLC LTE */
2884 /* Create tvb that starts at actual RLC PDU */
2885 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
2886 dissect_rlc_lte_common(rlc_tvb, pinfo, tree, true);
2887 return true;
2892 /*****************************/
2893 /* Main dissection function. */
2894 /*****************************/
2896 static int dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2898 dissect_rlc_lte_common(tvb, pinfo, tree, false);
2899 return tvb_captured_length(tvb);
2902 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool is_udp_framing)
2904 proto_tree *rlc_lte_tree;
2905 proto_tree *context_tree;
2906 proto_item *top_ti;
2907 proto_item *context_ti;
2908 proto_item *ti;
2909 proto_item *mode_ti;
2910 int offset = 0;
2911 struct rlc_lte_info *p_rlc_lte_info;
2913 /* Allocate and Zero tap struct */
2914 rlc_3gpp_tap_info *tap_info = wmem_new0(pinfo->pool, rlc_3gpp_tap_info);
2915 tap_info->rat = RLC_RAT_LTE;
2917 /* Set protocol name */
2918 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2920 /* Create protocol tree. */
2921 top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2922 rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2925 /* Look for packet info! */
2926 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2928 /* Can't dissect anything without it... */
2929 if (p_rlc_lte_info == NULL) {
2930 proto_tree_add_expert(rlc_lte_tree, pinfo, &ei_rlc_lte_no_per_frame_info, tvb, offset, -1);
2931 return;
2934 /* Clear info column when using UDP framing */
2935 if (is_udp_framing) {
2936 col_clear(pinfo->cinfo, COL_INFO);
2939 /*****************************************/
2940 /* Show context information */
2942 /* Create context root */
2943 context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2944 tvb, offset, 0, "", "Context");
2945 context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2946 proto_item_set_generated(context_ti);
2948 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2949 tvb, 0, 0, p_rlc_lte_info->direction);
2950 proto_item_set_generated(ti);
2952 mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2953 tvb, 0, 0, p_rlc_lte_info->rlcMode);
2954 proto_item_set_generated(mode_ti);
2956 if (p_rlc_lte_info->ueid != 0) {
2957 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_ueid,
2958 tvb, 0, 0, p_rlc_lte_info->ueid);
2959 proto_item_set_generated(ti);
2962 if ((p_rlc_lte_info->priority >= 1) && (p_rlc_lte_info->priority <=16)) {
2963 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_priority,
2964 tvb, 0, 0, p_rlc_lte_info->priority);
2965 proto_item_set_generated(ti);
2968 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2969 tvb, 0, 0, p_rlc_lte_info->channelType);
2970 proto_item_set_generated(ti);
2972 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2973 (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB) ||
2974 (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2975 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2976 tvb, 0, 0, p_rlc_lte_info->channelId);
2977 proto_item_set_generated(ti);
2980 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2981 tvb, 0, 0, p_rlc_lte_info->pduLength);
2982 proto_item_set_generated(ti);
2984 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
2985 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_um_sn_length,
2986 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2987 proto_item_set_generated(ti);
2990 if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2991 if (!p_rlc_lte_info->sequenceNumberLength) {
2992 p_rlc_lte_info->sequenceNumberLength = 10;
2994 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_am_sn_length,
2995 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2996 proto_item_set_generated(ti);
2999 /* Append highlights to top-level item */
3000 if (p_rlc_lte_info->ueid != 0) {
3001 proto_item_append_text(top_ti, " UEId=%u", p_rlc_lte_info->ueid);
3002 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%-4u ", p_rlc_lte_info->ueid);
3005 /* Append context highlights to info column */
3006 write_pdu_label_and_info(top_ti, NULL, pinfo,
3007 " [%s] [%s] ",
3008 (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
3009 val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
3011 if (p_rlc_lte_info->channelId == 0) {
3012 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s ",
3013 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
3015 else {
3016 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
3017 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
3018 p_rlc_lte_info->channelId);
3021 /* Set context-info parts of tap struct */
3022 tap_info->rlcMode = p_rlc_lte_info->rlcMode;
3023 tap_info->direction = p_rlc_lte_info->direction;
3024 tap_info->priority = p_rlc_lte_info->priority;
3025 tap_info->ueid = p_rlc_lte_info->ueid;
3026 tap_info->channelType = p_rlc_lte_info->channelType;
3027 tap_info->channelId = p_rlc_lte_info->channelId;
3028 tap_info->pduLength = p_rlc_lte_info->pduLength;
3029 tap_info->sequenceNumberLength = p_rlc_lte_info->sequenceNumberLength;
3030 tap_info->loggedInMACFrame = (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL);
3032 tap_info->rlc_time = pinfo->abs_ts;
3034 /* Reset this count */
3035 s_number_of_extensions = 0;
3037 /* Dissect the RLC PDU itself. Format depends upon mode... */
3038 switch (p_rlc_lte_info->rlcMode) {
3040 case RLC_TM_MODE:
3041 dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
3042 break;
3044 case RLC_UM_MODE:
3045 dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3046 tap_info);
3047 break;
3049 case RLC_AM_MODE:
3050 dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3051 tap_info);
3052 break;
3054 case RLC_PREDEF:
3055 /* Predefined data (i.e. not containing a valid RLC header */
3056 proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, ENC_NA);
3057 write_pdu_label_and_info(top_ti, NULL, pinfo, " [%u-bytes]",
3058 tvb_reported_length_remaining(tvb, offset));
3059 break;
3061 default:
3062 /* Error - unrecognised mode */
3063 expert_add_info_format(pinfo, mode_ti, &ei_rlc_lte_context_mode,
3064 "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
3065 break;
3068 /* Queue tap info */
3069 tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
3074 /* Configure number of PDCP SN bits to use for DRB channels */
3075 void set_rlc_lte_drb_pdcp_seqnum_length(packet_info *pinfo, uint16_t ueid, uint8_t drbid,
3076 uint8_t userplane_seqnum_length)
3078 wmem_tree_key_t key[3];
3079 uint32_t id;
3080 rlc_ue_parameters *params;
3082 if (PINFO_FD_VISITED(pinfo)) {
3083 return;
3086 id = (drbid << 16) | ueid;
3087 key[0].length = 1;
3088 key[0].key = &id;
3089 key[1].length = 1;
3090 key[1].key = &pinfo->num;
3091 key[2].length = 0;
3092 key[2].key = NULL;
3094 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3095 if (params && (params->id != id)) {
3096 params = NULL;
3098 if (params == NULL) {
3099 params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3100 params->id = id;
3101 params->ext_li_field = NO_EXT_LI;
3102 wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3104 params->pdcp_sn_bits = userplane_seqnum_length;
3107 /*Configure LI field for AM DRB channels */
3108 void set_rlc_lte_drb_li_field(packet_info *pinfo, uint16_t ueid, uint8_t drbid,
3109 bool ul_ext_li_field, bool dl_ext_li_field)
3111 wmem_tree_key_t key[3];
3112 uint32_t id;
3113 rlc_ue_parameters *params;
3115 if (PINFO_FD_VISITED(pinfo)) {
3116 return;
3119 id = (drbid << 16) | ueid;
3120 key[0].length = 1;
3121 key[0].key = &id;
3122 key[1].length = 1;
3123 key[1].key = &pinfo->num;
3124 key[2].length = 0;
3125 key[2].key = NULL;
3127 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3128 if (params && (params->id != id)) {
3129 params = NULL;
3131 if (params == NULL) {
3132 params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3133 params->id = id;
3134 params->pdcp_sn_bits = 12;
3135 wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3137 params->ext_li_field = ul_ext_li_field ? UL_EXT_LI : NO_EXT_LI;
3138 params->ext_li_field |= dl_ext_li_field ? DL_EXT_LI : NO_EXT_LI;
3141 void rlc_lte_reset_ue_bearers(packet_info *pinfo, uint16_t ueid)
3143 if (PINFO_FD_VISITED(pinfo)) {
3144 return;
3147 /* Need to reset current state of any entries in sequence_analysis_channel_hash */
3148 channel_hash_key channel_key;
3149 channel_sequence_analysis_status *p_channel_status;
3151 channel_key.ueId = ueid;
3153 /* SRBs (1-2, both directions) */
3154 channel_key.channelType = CHANNEL_TYPE_SRB;
3155 for (uint32_t channelId=1; channelId <= 2; ++channelId) {
3156 for (uint32_t direction=0; direction <=1; ++direction) {
3157 /* Update key */
3158 channel_key.channelId = channelId;
3159 channel_key.direction = direction;
3161 /* Lookup existing channel status */
3162 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
3163 if (p_channel_status) {
3164 /* Reset if already exists */
3165 p_channel_status->previousSequenceNumber = -1;
3166 p_channel_status->previousFrameNum = 0;
3167 p_channel_status->previousSegmentIncomplete = 0;
3172 /* DRBs (1-32, both directions) */
3173 channel_key.channelType = CHANNEL_TYPE_DRB;
3174 for (uint32_t channelId=1; channelId <= 32; ++channelId) {
3175 for (uint32_t direction=0; direction <=1; ++direction) {
3176 /* Update key */
3177 channel_key.channelId = channelId;
3178 channel_key.direction = direction;
3180 /* Lookup existing channel status */
3181 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
3182 if (p_channel_status) {
3183 /* Reset if already exists */
3184 p_channel_status->previousSequenceNumber = -1;
3185 p_channel_status->previousFrameNum = 0;
3186 p_channel_status->previousSegmentIncomplete = 0;
3194 void proto_register_rlc_lte(void)
3196 static hf_register_info hf[] =
3198 /**********************************/
3199 /* Items for decoding context */
3200 { &hf_rlc_lte_context,
3201 { "Context",
3202 "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
3203 NULL, HFILL
3206 { &hf_rlc_lte_context_mode,
3207 { "RLC Mode",
3208 "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
3209 NULL, HFILL
3212 { &hf_rlc_lte_context_direction,
3213 { "Direction",
3214 "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
3215 "Direction of message", HFILL
3218 { &hf_rlc_lte_context_priority,
3219 { "Priority",
3220 "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
3221 NULL, HFILL
3224 { &hf_rlc_lte_context_ueid,
3225 { "UEId",
3226 "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
3227 "User Equipment Identifier associated with message", HFILL
3230 { &hf_rlc_lte_context_channel_type,
3231 { "Channel Type",
3232 "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
3233 "Channel Type associated with message", HFILL
3236 { &hf_rlc_lte_context_channel_id,
3237 { "Channel ID",
3238 "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
3239 "Channel ID associated with message", HFILL
3242 { &hf_rlc_lte_context_pdu_length,
3243 { "PDU Length",
3244 "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
3245 "Length of PDU (in bytes)", HFILL
3248 { &hf_rlc_lte_context_um_sn_length,
3249 { "UM Sequence number length",
3250 "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3251 "Length of UM sequence number in bits", HFILL
3254 { &hf_rlc_lte_context_am_sn_length,
3255 { "AM Sequence number length",
3256 "rlc-lte.am-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3257 "Length of AM sequence number in bits", HFILL
3261 /* Transparent mode fields */
3262 { &hf_rlc_lte_tm,
3263 { "TM",
3264 "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
3265 "Transparent Mode", HFILL
3268 { &hf_rlc_lte_tm_data,
3269 { "TM Data",
3270 "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
3271 "Transparent Mode Data", HFILL
3275 /* Unacknowledged mode fields */
3276 { &hf_rlc_lte_um,
3277 { "UM",
3278 "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
3279 "Unacknowledged Mode", HFILL
3282 { &hf_rlc_lte_um_header,
3283 { "UM Header",
3284 "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
3285 "Unacknowledged Mode Header", HFILL
3288 { &hf_rlc_lte_um_fi,
3289 { "Framing Info",
3290 "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
3291 NULL, HFILL
3294 { &hf_rlc_lte_um_fixed_e,
3295 { "Extension",
3296 "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
3297 "Extension in fixed part of UM header", HFILL
3300 { &hf_rlc_lte_um_sn,
3301 { "Sequence number",
3302 "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
3303 "Unacknowledged Mode Sequence Number", HFILL
3306 { &hf_rlc_lte_um_fixed_reserved,
3307 { "Reserved",
3308 "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
3309 "Unacknowledged Mode Fixed header reserved bits", HFILL
3312 { &hf_rlc_lte_um_data,
3313 { "UM Data",
3314 "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
3315 "Unacknowledged Mode Data", HFILL
3318 { &hf_rlc_lte_extension_part,
3319 { "Extension Part",
3320 "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
3321 NULL, HFILL
3324 { &hf_rlc_lte_extension_e,
3325 { "Extension",
3326 "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
3327 "Extension in extended part of the header", HFILL
3330 { &hf_rlc_lte_extension_li,
3331 { "Length Indicator",
3332 "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
3333 NULL, HFILL
3336 { &hf_rlc_lte_extension_padding,
3337 { "Padding",
3338 "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
3339 "Extension header padding", HFILL
3343 /* Acknowledged mode fields */
3344 { &hf_rlc_lte_am,
3345 { "AM",
3346 "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
3347 "Acknowledged Mode", HFILL
3350 { &hf_rlc_lte_am_header,
3351 { "AM Header",
3352 "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
3353 "Acknowledged Mode Header", HFILL
3356 { &hf_rlc_lte_am_data_control,
3357 { "Frame type",
3358 "rlc-lte.am.frame-type", FT_BOOLEAN, 8, TFS(&tfs_data_pdu_control_pdu), 0x80,
3359 "AM Frame Type (Control or Data)", HFILL
3362 { &hf_rlc_lte_am_rf,
3363 { "Re-segmentation Flag",
3364 "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
3365 "AM Re-segmentation Flag", HFILL
3368 { &hf_rlc_lte_am_p,
3369 { "Polling Bit",
3370 "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
3371 NULL, HFILL
3374 { &hf_rlc_lte_am_fi,
3375 { "Framing Info",
3376 "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
3377 "AM Framing Info", HFILL
3380 { &hf_rlc_lte_am_fixed_e,
3381 { "Extension",
3382 "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
3383 "Fixed Extension Bit", HFILL
3386 { &hf_rlc_lte_am_fixed_sn,
3387 { "Sequence Number",
3388 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
3389 "AM Fixed Sequence Number", HFILL
3392 { &hf_rlc_lte_am_fixed_reserved,
3393 { "Reserved",
3394 "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x03,
3395 "Acknowledged Mode Fixed header reserved bits", HFILL
3398 { &hf_rlc_lte_am_segment_lsf16,
3399 { "Last Segment Flag",
3400 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x02,
3401 NULL, HFILL
3404 { &hf_rlc_lte_am_fixed_reserved2,
3405 { "Reserved",
3406 "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x01,
3407 "Acknowledged Mode Fixed header reserved bit", HFILL
3410 { &hf_rlc_lte_am_fixed_sn16,
3411 { "Sequence Number",
3412 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3413 "AM Fixed Sequence Number", HFILL
3416 { &hf_rlc_lte_am_segment_lsf,
3417 { "Last Segment Flag",
3418 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3419 NULL, HFILL
3422 { &hf_rlc_lte_am_segment_so,
3423 { "Segment Offset",
3424 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3425 NULL, HFILL
3428 { &hf_rlc_lte_am_segment_so16,
3429 { "Segment Offset",
3430 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x0,
3431 NULL, HFILL
3434 { &hf_rlc_lte_am_data,
3435 { "AM Data",
3436 "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3437 "Acknowledged Mode Data", HFILL
3441 { &hf_rlc_lte_am_cpt,
3442 { "Control PDU Type",
3443 "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3444 "AM Control PDU Type", HFILL
3447 { &hf_rlc_lte_am_ack_sn,
3448 { "ACK Sequence Number",
3449 "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3450 "Sequence Number we expect to receive next", HFILL
3453 { &hf_rlc_lte_am_e1,
3454 { "Extension bit 1",
3455 "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3456 NULL, HFILL
3459 { &hf_rlc_lte_am_e2,
3460 { "Extension bit 2",
3461 "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3462 NULL, HFILL
3465 { &hf_rlc_lte_am_nacks,
3466 { "Number of NACKs",
3467 "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3468 "Number of NACKs in this status PDU", HFILL
3471 { &hf_rlc_lte_am_nack_sn,
3472 { "NACK Sequence Number",
3473 "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3474 "Negative Acknowledgement Sequence Number", HFILL
3477 { &hf_rlc_lte_am_so_start,
3478 { "SO Start",
3479 "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3480 "Segment Offset Start byte index", HFILL
3483 { &hf_rlc_lte_am_so_end,
3484 { "SO End",
3485 "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3486 "Segment Offset End byte index", HFILL
3490 { &hf_rlc_lte_predefined_pdu,
3491 { "Predefined data",
3492 "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3493 "Predefined test data", HFILL
3497 /* Sequence analysis fields */
3498 { &hf_rlc_lte_sequence_analysis,
3499 { "Sequence Analysis",
3500 "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3501 NULL, HFILL
3504 { &hf_rlc_lte_sequence_analysis_ok,
3505 { "OK",
3506 "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3507 NULL, HFILL
3510 { &hf_rlc_lte_sequence_analysis_previous_frame,
3511 { "Previous frame for channel",
3512 "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3513 NULL, HFILL
3516 { &hf_rlc_lte_sequence_analysis_next_frame,
3517 { "Next frame for channel",
3518 "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3519 NULL, HFILL
3522 { &hf_rlc_lte_sequence_analysis_expected_sn,
3523 { "Expected SN",
3524 "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3525 NULL, HFILL
3528 { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3529 { "Frame info continued correctly",
3530 "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3531 NULL, HFILL
3534 { &hf_rlc_lte_sequence_analysis_mac_retx,
3535 { "Frame retransmitted by MAC",
3536 "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3537 NULL, HFILL
3540 { &hf_rlc_lte_sequence_analysis_retx,
3541 { "Retransmitted frame",
3542 "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3543 NULL, HFILL
3546 { &hf_rlc_lte_sequence_analysis_skipped,
3547 { "Skipped frames",
3548 "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3549 NULL, HFILL
3552 { &hf_rlc_lte_sequence_analysis_repeated,
3553 { "Repeated frame",
3554 "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3555 NULL, HFILL
3558 { &hf_rlc_lte_sequence_analysis_repeated_nack,
3559 { "Repeated NACK",
3560 "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3561 NULL, HFILL
3564 { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3565 { "Frame with previous status PDU",
3566 "rlc-lte.sequence-analysis.repeated-nack.original-frame", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_DUP_ACK), 0x0,
3567 NULL, HFILL
3571 { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3572 { "Out of range ACK",
3573 "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3574 NULL, HFILL
3577 { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3578 { "Frame with most recent SN",
3579 "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3580 NULL, HFILL
3584 /* Reassembly fields */
3585 { &hf_rlc_lte_reassembly_source,
3586 { "Reassembly Source",
3587 "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3588 NULL, HFILL
3591 { &hf_rlc_lte_reassembly_source_number_of_segments,
3592 { "Number of segments",
3593 "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3594 NULL, HFILL
3597 { &hf_rlc_lte_reassembly_source_total_length,
3598 { "Total length",
3599 "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3600 NULL, HFILL
3603 { &hf_rlc_lte_reassembly_source_segment,
3604 { "Segment",
3605 "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3606 NULL, HFILL
3609 { &hf_rlc_lte_reassembly_source_segment_sn,
3610 { "SN",
3611 "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3612 NULL, HFILL
3615 { &hf_rlc_lte_reassembly_source_segment_framenum,
3616 { "Frame",
3617 "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3618 NULL, HFILL
3621 { &hf_rlc_lte_reassembly_source_segment_length,
3622 { "Length",
3623 "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3624 NULL, HFILL
3628 { &hf_rlc_lte_header_only,
3629 { "RLC PDU Header only",
3630 "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3631 NULL, HFILL
3636 static int *ett[] =
3638 &ett_rlc_lte,
3639 &ett_rlc_lte_context,
3640 &ett_rlc_lte_um_header,
3641 &ett_rlc_lte_am_header,
3642 &ett_rlc_lte_extension_part,
3643 &ett_rlc_lte_sequence_analysis,
3644 &ett_rlc_lte_reassembly_source,
3645 &ett_rlc_lte_reassembly_source_segment
3648 static ei_register_info ei[] = {
3649 { &ei_rlc_lte_sequence_analysis_last_segment_not_continued, { "rlc-lte.sequence-analysis.last-segment-not-continued", PI_SEQUENCE, PI_WARN, "Last segment of previous PDU was not continued for UE", EXPFILL }},
3650 { &ei_rlc_lte_sequence_analysis_last_segment_complete, { "rlc-lte.sequence-analysis.last-segment-complete", PI_SEQUENCE, PI_WARN, "Last segment of previous PDU was complete, but new segment was not started on UE", EXPFILL }},
3651 { &ei_rlc_lte_sequence_analysis_mac_retx, { "rlc-lte.sequence-analysis.mac-retx.expert", PI_SEQUENCE, PI_WARN, "AM Frame retransmitted due to MAC retx!", EXPFILL }},
3652 { &ei_rlc_lte_sequence_analysis_retx, { "rlc-lte.sequence-analysis.retx.expert", PI_SEQUENCE, PI_WARN, "AM Frame retransmitted most likely in response to NACK", EXPFILL }},
3653 { &ei_rlc_lte_sequence_analysis_repeated, { "rlc-lte.sequence-analysis.repeated-frame.expert", PI_SEQUENCE, PI_WARN, "AM SN Repeated - probably because didn't receive Status PDU?", EXPFILL }},
3654 { &ei_rlc_lte_am_sn_missing, { "rlc-lte.sequence-analysis.am-sn.missing", PI_SEQUENCE, PI_WARN, "AM SNs missing", EXPFILL }},
3655 { &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame, { "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame.expert", PI_SEQUENCE, PI_ERROR, "AM ACK for SN - but last received SN in other direction is X", EXPFILL }},
3656 { &ei_rlc_lte_um_sn_missing, { "rlc-lte.sequence-analysis.um-sn.missing", PI_SEQUENCE, PI_WARN, "UM SNs missing", EXPFILL }},
3657 { &ei_rlc_lte_um_sn_repeated, { "rlc-lte.sequence-analysis.um-sn.repeated", PI_SEQUENCE, PI_WARN, "UM SN repeated", EXPFILL }},
3658 { &ei_rlc_lte_wrong_sequence_number, { "rlc-lte.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
3659 { &ei_rlc_lte_sequence_analysis_repeated_nack, { "rlc-lte.sequence-analysis.repeated-nack.expert", PI_SEQUENCE, PI_ERROR, "Same SN NACKd on successive Status PDUs", EXPFILL }},
3660 { &ei_rlc_lte_reserved_bits_not_zero, { "rlc-lte.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
3661 { &ei_rlc_lte_um_sn, { "rlc-lte.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
3662 { &ei_rlc_lte_header_only, { "rlc-lte.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3663 { &ei_rlc_lte_am_cpt, { "rlc-lte.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
3664 { &ei_rlc_lte_am_nack_sn_ack_same, { "rlc-lte.am.nack-sn.ack-same", PI_MALFORMED, PI_ERROR, "Status PDU shouldn't ACK and NACK the same sequence number", EXPFILL }},
3665 { &ei_rlc_lte_am_nack_sn_ahead_ack, { "rlc-lte.am.nack-sn.ahead-ack", PI_MALFORMED, PI_ERROR, "NACK must not be ahead of ACK in status PDU", EXPFILL }},
3666 { &ei_rlc_lte_am_nack_sn_partial, { "rlc-lte.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
3667 { &ei_rlc_lte_am_nack_sn, { "rlc-lte.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
3668 { &ei_rlc_lte_bytes_after_status_pdu_complete, { "rlc-lte.bytes-after-status-pdu-complete", PI_MALFORMED, PI_ERROR, "bytes remaining after Status PDU complete", EXPFILL }},
3669 { &ei_rlc_lte_am_data_no_data_beyond_extensions, { "rlc-lte.am-data.no-data-beyond-extensions", PI_MALFORMED, PI_ERROR, "AM data PDU doesn't contain any data beyond extensions", EXPFILL }},
3670 { &ei_rlc_lte_am_data_no_data, { "rlc-lte.am-data.no-data", PI_MALFORMED, PI_ERROR, "AM data PDU doesn't contain any data", EXPFILL }},
3671 { &ei_rlc_lte_context_mode, { "rlc-lte.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
3672 { &ei_rlc_lte_no_per_frame_info, { "rlc-lte.no_per_frame_info", PI_UNDECODED, PI_ERROR, "Can't dissect LTE RLC frame because no per-frame info was attached!", EXPFILL }},
3673 { &ei_rlc_lte_unknown_udp_framing_tag, { "rlc-lte.unknown-udp-framing-tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }},
3674 { &ei_rlc_lte_missing_udp_framing_tag, { "rlc-lte.missing-udp-framing-tag", PI_UNDECODED, PI_WARN, "Missing UDP framing conditional tag, aborting dissection", EXPFILL }}
3677 static const enum_val_t sequence_analysis_vals[] = {
3678 {"no-analysis", "No-Analysis", false},
3679 {"mac-only", "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3680 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3681 {NULL, NULL, -1}
3684 module_t *rlc_lte_module;
3685 expert_module_t* expert_rlc_lte;
3687 /* Register protocol. */
3688 proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3689 proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3690 proto_register_subtree_array(ett, array_length(ett));
3691 expert_rlc_lte = expert_register_protocol(proto_rlc_lte);
3692 expert_register_field_array(expert_rlc_lte, ei, array_length(ei));
3694 /* Allow other dissectors to find this one by name. */
3695 register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3697 /* Register the tap name */
3698 rlc_lte_tap = register_tap("rlc-3gpp");
3700 /* Preferences */
3701 rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3703 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3704 "Do sequence analysis for AM channels",
3705 "Attempt to keep track of PDUs for AM channels, and point out problems",
3706 &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, false);
3708 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3709 "Do sequence analysis for UM channels",
3710 "Attempt to keep track of PDUs for UM channels, and point out problems",
3711 &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, false);
3713 prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3714 "Call PDCP dissector for SRB PDUs",
3715 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
3716 "only be called for complete PDUs (i.e. not segmented over RLC)",
3717 &global_rlc_lte_call_pdcp_for_srb);
3719 prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3720 "Call PDCP dissector for DRB PDUs",
3721 "Call PDCP dissector for user-plane PDUs. Note that without reassembly, it can"
3722 "only be called for complete PDUs (i.e. not segmented over RLC)",
3723 &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, false);
3726 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3727 "Call RRC dissector for CCCH PDUs",
3728 "Call RRC dissector for CCCH PDUs",
3729 &global_rlc_lte_call_rrc_for_ccch);
3731 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_mcch",
3732 "Call RRC dissector for MCCH PDUs",
3733 "Call RRC dissector for MCCH PDUs Note that without reassembly, it can"
3734 "only be called for complete PDUs (i.e. not segmented over RLC)",
3735 &global_rlc_lte_call_rrc_for_mcch);
3737 prefs_register_bool_preference(rlc_lte_module, "call_ip_for_mtch",
3738 "Call IP dissector for MTCH PDUs",
3739 "Call ip dissector for MTCH PDUs Note that without reassembly, it can"
3740 "only be called for complete PDUs (i.e. not segmented over RLC)",
3741 &global_rlc_lte_call_ip_for_mtch);
3743 prefs_register_obsolete_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp");
3745 prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3746 "May see RLC headers only",
3747 "When enabled, if data is not present, don't report as an error, but instead "
3748 "add expert info to indicate that headers were omitted",
3749 &global_rlc_lte_headers_expected);
3751 prefs_register_bool_preference(rlc_lte_module, "reassembly",
3752 "Attempt SDU reassembly",
3753 "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3754 "more than one RLC PDU. Note: does not currently support out-of-order or "
3755 "re-segmentation. N.B. sequence analysis must also be turned on in order "
3756 "for reassembly to work",
3757 &global_rlc_lte_reassembly);
3759 ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3761 sequence_analysis_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3762 sequence_analysis_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3763 repeated_nack_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3764 repeated_nack_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3765 reassembly_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3768 void proto_reg_handoff_rlc_lte(void)
3770 /* Add as a heuristic UDP dissector */
3771 heur_dissector_add("udp", dissect_rlc_lte_heur, "RLC-LTE over UDP", "rlc_lte_udp", proto_rlc_lte, HEURISTIC_DISABLE);
3773 pdcp_lte_handle = find_dissector_add_dependency("pdcp-lte", proto_rlc_lte);
3774 ip_handle = find_dissector_add_dependency("ip", proto_rlc_lte);
3775 lte_rrc_mcch = find_dissector_add_dependency("lte_rrc.mcch", proto_rlc_lte);
3776 lte_rrc_ul_ccch = find_dissector_add_dependency("lte_rrc.ul_ccch", proto_rlc_lte);
3777 lte_rrc_dl_ccch = find_dissector_add_dependency("lte_rrc.dl_ccch", proto_rlc_lte);
3778 lte_rrc_bcch_bch = find_dissector_add_dependency("lte_rrc.bcch_bch", proto_rlc_lte);
3779 lte_rrc_bcch_dl_sch = find_dissector_add_dependency("lte_rrc.bcch_dl_sch", proto_rlc_lte);
3780 lte_rrc_pcch = find_dissector_add_dependency("lte_rrc.pcch", proto_rlc_lte);
3781 lte_rrc_ul_ccch_nb = find_dissector_add_dependency("lte_rrc.ul_ccch.nb", proto_rlc_lte);
3782 lte_rrc_dl_ccch_nb = find_dissector_add_dependency("lte_rrc.dl_ccch.nb", proto_rlc_lte);
3783 lte_rrc_bcch_bch_nb = find_dissector_add_dependency("lte_rrc.bcch_bch.nb", proto_rlc_lte);
3784 lte_rrc_bcch_dl_sch_nb = find_dissector_add_dependency("lte_rrc.bcch_dl_sch.nb", proto_rlc_lte);
3785 lte_rrc_pcch_nb = find_dissector_add_dependency("lte_rrc.pcch.nb", proto_rlc_lte);
3789 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3791 * Local variables:
3792 * c-basic-offset: 4
3793 * tab-width: 8
3794 * indent-tabs-mode: nil
3795 * End:
3797 * vi: set shiftwidth=4 tabstop=8 expandtab:
3798 * :indentSize=4:tabSize=8:noTabs=true: