1 /* Routines for LTE RLC disassembly
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/exceptions.h>
16 #include <epan/expert.h>
17 #include <epan/prefs.h>
19 #include <epan/proto_data.h>
20 #include "packet-mac-lte.h"
21 #include "packet-rlc-lte.h"
22 #include "packet-pdcp-lte.h"
26 * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA)
27 * Radio Link Control (RLC) Protocol specification v14.0.0
31 - add intermediate results to segments leading to final reassembly
32 - use multiple active rlc_channel_reassembly_info's per channel
33 - sequence analysis gets confused when we change cells and skip back
34 to SN 0. Maybe add cell-id to context and add to channel/result key?
37 void proto_register_rlc_lte(void);
38 void proto_reg_handoff_rlc_lte(void);
40 /********************************/
41 /* Preference settings */
43 #define SEQUENCE_ANALYSIS_MAC_ONLY 1
44 #define SEQUENCE_ANALYSIS_RLC_ONLY 2
46 /* By default do try to analyse the sequence of messages for AM/UM channels
48 static gint global_rlc_lte_am_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
49 static gint global_rlc_lte_um_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
51 /* By default do call PDCP/RRC dissectors for SDU data */
52 static gboolean global_rlc_lte_call_pdcp_for_srb = TRUE;
54 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};
55 static const enum_val_t pdcp_drb_col_vals[] = {
56 {"pdcp-drb-off", "Off", PDCP_drb_off},
57 {"pdcp-drb-sn-7", "7-bit SN", PDCP_drb_SN_7},
58 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
59 {"pdcp-drb-sn-15", "15-bit SN", PDCP_drb_SN_15},
60 {"pdcp-drb-sn-18", "18-bit SN", PDCP_drb_SN_18},
61 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
64 static gint global_rlc_lte_call_pdcp_for_drb = (gint)PDCP_drb_SN_signalled;
66 static gboolean global_rlc_lte_call_rrc_for_ccch = TRUE;
67 static gboolean global_rlc_lte_call_rrc_for_mcch = FALSE;
68 static gboolean global_rlc_lte_call_ip_for_mtch = FALSE;
70 /* Preference to expect RLC headers without payloads */
71 static gboolean global_rlc_lte_headers_expected = FALSE;
73 /* Re-assembly of segments */
74 static gboolean global_rlc_lte_reassembly = TRUE;
76 /* Tree storing UE related parameters */
80 typedef struct rlc_ue_parameters {
85 static wmem_tree_t *ue_parameters_tree;
87 /**************************************************/
88 /* Initialize the protocol and registered fields. */
89 int proto_rlc_lte = -1;
91 extern int proto_mac_lte;
92 extern int proto_pdcp_lte;
94 static dissector_handle_t pdcp_lte_handle;
95 static dissector_handle_t ip_handle;
96 static dissector_handle_t lte_rrc_mcch;
97 static dissector_handle_t lte_rrc_ul_ccch;
98 static dissector_handle_t lte_rrc_dl_ccch;
99 static dissector_handle_t lte_rrc_bcch_bch;
100 static dissector_handle_t lte_rrc_bcch_dl_sch;
101 static dissector_handle_t lte_rrc_pcch;
102 static dissector_handle_t lte_rrc_ul_ccch_nb;
103 static dissector_handle_t lte_rrc_dl_ccch_nb;
104 static dissector_handle_t lte_rrc_bcch_bch_nb;
105 static dissector_handle_t lte_rrc_bcch_dl_sch_nb;
106 static dissector_handle_t lte_rrc_pcch_nb;
109 static int rlc_lte_tap = -1;
111 /* Decoding context */
112 static int hf_rlc_lte_context = -1;
113 static int hf_rlc_lte_context_mode = -1;
114 static int hf_rlc_lte_context_direction = -1;
115 static int hf_rlc_lte_context_priority = -1;
116 static int hf_rlc_lte_context_ueid = -1;
117 static int hf_rlc_lte_context_channel_type = -1;
118 static int hf_rlc_lte_context_channel_id = -1;
119 static int hf_rlc_lte_context_pdu_length = -1;
120 static int hf_rlc_lte_context_um_sn_length = -1;
121 static int hf_rlc_lte_context_am_sn_length = -1;
123 /* Transparent mode fields */
124 static int hf_rlc_lte_tm = -1;
125 static int hf_rlc_lte_tm_data = -1;
127 /* Unacknowledged mode fields */
128 static int hf_rlc_lte_um = -1;
129 static int hf_rlc_lte_um_header = -1;
130 static int hf_rlc_lte_um_fi = -1;
131 static int hf_rlc_lte_um_fixed_e = -1;
132 static int hf_rlc_lte_um_sn = -1;
133 static int hf_rlc_lte_um_fixed_reserved = -1;
134 static int hf_rlc_lte_um_data = -1;
135 static int hf_rlc_lte_extension_part = -1;
137 /* Extended header (common to UM and AM) */
138 static int hf_rlc_lte_extension_e = -1;
139 static int hf_rlc_lte_extension_li = -1;
140 static int hf_rlc_lte_extension_padding = -1;
143 /* Acknowledged mode fields */
144 static int hf_rlc_lte_am = -1;
145 static int hf_rlc_lte_am_header = -1;
146 static int hf_rlc_lte_am_data_control = -1;
147 static int hf_rlc_lte_am_rf = -1;
148 static int hf_rlc_lte_am_p = -1;
149 static int hf_rlc_lte_am_fi = -1;
150 static int hf_rlc_lte_am_fixed_e = -1;
151 static int hf_rlc_lte_am_fixed_sn = -1;
152 static int hf_rlc_lte_am_fixed_reserved = -1;
153 static int hf_rlc_lte_am_segment_lsf16 = -1;
154 static int hf_rlc_lte_am_fixed_reserved2 = -1;
155 static int hf_rlc_lte_am_fixed_sn16 = -1;
156 static int hf_rlc_lte_am_segment_lsf = -1;
157 static int hf_rlc_lte_am_segment_so = -1;
158 static int hf_rlc_lte_am_segment_so16 = -1;
159 static int hf_rlc_lte_am_data = -1;
162 static int hf_rlc_lte_am_cpt = -1;
163 static int hf_rlc_lte_am_ack_sn = -1;
164 static int hf_rlc_lte_am_e1 = -1;
165 static int hf_rlc_lte_am_e2 = -1;
166 static int hf_rlc_lte_am_nack_sn = -1;
167 static int hf_rlc_lte_am_nacks = -1;
168 static int hf_rlc_lte_am_so_start = -1;
169 static int hf_rlc_lte_am_so_end = -1;
171 static int hf_rlc_lte_predefined_pdu = -1;
172 static int hf_rlc_lte_header_only = -1;
174 /* Sequence Analysis */
175 static int hf_rlc_lte_sequence_analysis = -1;
176 static int hf_rlc_lte_sequence_analysis_ok = -1;
177 static int hf_rlc_lte_sequence_analysis_previous_frame = -1;
178 static int hf_rlc_lte_sequence_analysis_next_frame = -1;
179 static int hf_rlc_lte_sequence_analysis_expected_sn = -1;
180 static int hf_rlc_lte_sequence_analysis_framing_info_correct = -1;
182 static int hf_rlc_lte_sequence_analysis_mac_retx = -1;
183 static int hf_rlc_lte_sequence_analysis_retx = -1;
184 static int hf_rlc_lte_sequence_analysis_repeated = -1;
185 static int hf_rlc_lte_sequence_analysis_skipped = -1;
187 static int hf_rlc_lte_sequence_analysis_repeated_nack = -1;
188 static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame = -1;
190 static int hf_rlc_lte_sequence_analysis_ack_out_of_range = -1;
191 static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = -1;
194 static int hf_rlc_lte_reassembly_source = -1;
195 static int hf_rlc_lte_reassembly_source_number_of_segments = -1;
196 static int hf_rlc_lte_reassembly_source_total_length = -1;
197 static int hf_rlc_lte_reassembly_source_segment = -1;
198 static int hf_rlc_lte_reassembly_source_segment_sn = -1;
199 static int hf_rlc_lte_reassembly_source_segment_framenum = -1;
200 static int hf_rlc_lte_reassembly_source_segment_length = -1;
203 static int ett_rlc_lte = -1;
204 static int ett_rlc_lte_context = -1;
205 static int ett_rlc_lte_um_header = -1;
206 static int ett_rlc_lte_am_header = -1;
207 static int ett_rlc_lte_extension_part = -1;
208 static int ett_rlc_lte_sequence_analysis = -1;
209 static int ett_rlc_lte_reassembly_source = -1;
210 static int ett_rlc_lte_reassembly_source_segment = -1;
212 static expert_field ei_rlc_lte_context_mode = EI_INIT;
213 static expert_field ei_rlc_lte_am_nack_sn = EI_INIT;
214 static expert_field ei_rlc_lte_am_nack_sn_ahead_ack = EI_INIT;
215 static expert_field ei_rlc_lte_um_sn_repeated = EI_INIT;
216 static expert_field ei_rlc_lte_am_nack_sn_ack_same = EI_INIT;
217 static expert_field ei_rlc_lte_am_cpt = EI_INIT;
218 static expert_field ei_rlc_lte_am_data_no_data = EI_INIT;
219 static expert_field ei_rlc_lte_sequence_analysis_last_segment_complete = EI_INIT;
220 static expert_field ei_rlc_lte_sequence_analysis_mac_retx = EI_INIT;
221 static expert_field ei_rlc_lte_am_nack_sn_partial = EI_INIT;
222 static expert_field ei_rlc_lte_sequence_analysis_repeated_nack = EI_INIT;
223 static expert_field ei_rlc_lte_bytes_after_status_pdu_complete = EI_INIT;
224 static expert_field ei_rlc_lte_sequence_analysis_repeated = EI_INIT;
225 static expert_field ei_rlc_lte_wrong_sequence_number = EI_INIT;
226 static expert_field ei_rlc_lte_sequence_analysis_retx = EI_INIT;
227 static expert_field ei_rlc_lte_am_sn_missing = EI_INIT;
228 static expert_field ei_rlc_lte_um_sn = EI_INIT;
229 static expert_field ei_rlc_lte_header_only = EI_INIT;
230 static expert_field ei_rlc_lte_am_data_no_data_beyond_extensions = EI_INIT;
231 static expert_field ei_rlc_lte_um_sn_missing = EI_INIT;
232 static expert_field ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = EI_INIT;
233 static expert_field ei_rlc_lte_sequence_analysis_last_segment_not_continued = EI_INIT;
234 static expert_field ei_rlc_lte_reserved_bits_not_zero = EI_INIT;
235 static expert_field ei_rlc_lte_no_per_frame_info = EI_INIT;
236 static expert_field ei_rlc_lte_unknown_udp_framing_tag = EI_INIT;
237 static expert_field ei_rlc_lte_missing_udp_framing_tag = EI_INIT;
240 static const value_string direction_vals[] =
242 { DIRECTION_UPLINK, "Uplink"},
243 { DIRECTION_DOWNLINK, "Downlink"},
247 static const value_string rlc_mode_short_vals[] =
249 { RLC_TM_MODE, "TM"},
250 { RLC_UM_MODE, "UM"},
251 { RLC_AM_MODE, "AM"},
252 { RLC_PREDEF, "PREDEFINED"}, /* For data testing */
256 static const value_string rlc_mode_vals[] =
258 { RLC_TM_MODE, "Transparent Mode"},
259 { RLC_UM_MODE, "Unacknowledged Mode"},
260 { RLC_AM_MODE, "Acknowledged Mode"},
264 static const value_string rlc_channel_type_vals[] =
266 { CHANNEL_TYPE_CCCH, "CCCH"},
267 { CHANNEL_TYPE_BCCH_BCH, "BCCH_BCH"},
268 { CHANNEL_TYPE_PCCH, "PCCH"},
269 { CHANNEL_TYPE_SRB, "SRB"},
270 { CHANNEL_TYPE_DRB, "DRB"},
271 { CHANNEL_TYPE_BCCH_DL_SCH, "BCCH_DL_SCH"},
272 { CHANNEL_TYPE_MCCH, "MCCH"},
273 { CHANNEL_TYPE_MTCH, "MTCH"},
277 static const value_string framing_info_vals[] =
279 { 0, "First byte begins a RLC SDU and last byte ends a RLC SDU"},
280 { 1, "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
281 { 2, "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
282 { 3, "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
286 static const value_string fixed_extension_vals[] =
288 { 0, "Data field follows from the octet following the fixed part of the header"},
289 { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"},
293 static const value_string extension_extension_vals[] =
295 { 0, "Data field follows from the octet following the LI field following this E field"},
296 { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"},
300 static const value_string data_or_control_vals[] =
307 static const value_string resegmentation_flag_vals[] =
310 { 1, "AMD PDU segment"},
314 static const value_string polling_bit_vals[] =
316 { 0, "Status report not requested"},
317 { 1, "Status report is requested"},
321 static const value_string lsf_vals[] =
323 { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
324 { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
328 static const value_string control_pdu_type_vals[] =
334 static const value_string am_e1_vals[] =
336 { 0, "A set of NACK_SN, E1 and E2 does not follow"},
337 { 1, "A set of NACK_SN, E1 and E2 follows"},
341 static const value_string am_e2_vals[] =
343 { 0, "A set of SOstart and SOend does not follow for this NACK_SN"},
344 { 1, "A set of SOstart and SOend follows for this NACK_SN"},
348 static const value_string header_only_vals[] =
350 { 0, "RLC PDU Headers and body present"},
351 { 1, "RLC PDU Headers only"},
357 /**********************************************************************************/
358 /* These are for keeping track of UM/AM extension headers, and the lengths found */
360 static guint8 s_number_of_extensions = 0;
361 #define MAX_RLC_SDUS 192
362 static guint16 s_lengths[MAX_RLC_SDUS];
365 /*********************************************************************/
366 /* UM/AM sequence analysis */
368 /* Types for RLC channel hash table */
369 /* This table is maintained during initial dissection of RLC */
370 /* frames, mapping from channel_hash_key -> sequence_analysis_report */
376 guint channelType : 3;
382 /******************************************************************/
383 /* State maintained for AM/UM reassembly */
385 typedef struct rlc_segment {
392 typedef struct rlc_channel_reassembly_info
394 guint16 number_of_segments;
395 #define RLC_MAX_SEGMENTS 100
396 rlc_segment segments[RLC_MAX_SEGMENTS];
397 } rlc_channel_reassembly_info;
402 /*******************************************************************/
403 /* Conversation-type status for sequence analysis on channel */
408 /* For UM, we always expect the SN to keep advancing, and these fields
410 For AM, these correspond to new data */
411 guint16 previousSequenceNumber;
412 guint32 previousFrameNum;
413 gboolean previousSegmentIncomplete;
415 /* Accumulate info about current segmented SDU */
416 struct rlc_channel_reassembly_info *reassembly_info;
417 } channel_sequence_analysis_status;
419 /* The sequence analysis channel hash table */
420 static wmem_map_t *sequence_analysis_channel_hash = NULL;
423 /* Types for sequence analysis frame report hash table */
424 /* This is a table from framenum -> state_report_in_frame */
425 /* This is necessary because the per-packet info is already being used */
426 /* for context information before the dissector is called */
428 /* Info to attach to frame when first read, recording what to show about sequence */
430 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window, SN_Error
431 } sequence_analysis_state;
436 gboolean sequenceExpectedCorrect;
437 guint16 sequenceExpected;
438 guint32 previousFrameNum;
439 gboolean previousSegmentIncomplete;
440 guint32 nextFrameNum;
446 sequence_analysis_state state;
447 } sequence_analysis_report;
450 /* The sequence analysis frame report hash table instance itself */
451 static wmem_map_t *sequence_analysis_report_hash = NULL;
454 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
455 rlc_lte_info *p_rlc_lte_info,
456 gboolean do_persist);
461 /* The reassembly result hash table */
462 static wmem_map_t *reassembly_report_hash = NULL;
465 /* Create a new struct for reassembly */
466 static void reassembly_reset(channel_sequence_analysis_status *status)
468 status->reassembly_info = wmem_new0(wmem_file_scope(), rlc_channel_reassembly_info);
471 /* Hide previous one */
472 static void reassembly_destroy(channel_sequence_analysis_status *status)
474 /* Just "leak" it. There seems to be no way to free this memory... */
475 status->reassembly_info = NULL;
478 /* Add a new segment to the accumulating segmented SDU */
479 static void reassembly_add_segment(channel_sequence_analysis_status *status,
480 guint16 SN, guint32 frame,
481 tvbuff_t *tvb, gint offset, gint length)
483 int segment_number = status->reassembly_info->number_of_segments;
484 guint8 *segment_data;
486 /* Give up if reach segment limit */
487 if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
488 reassembly_destroy(status);
492 segment_data = (guint8 *)tvb_memdup(wmem_file_scope(),tvb, offset, length);
494 /* Add new segment */
495 status->reassembly_info->segments[segment_number].frameNum = frame;
496 status->reassembly_info->segments[segment_number].SN = SN;
497 status->reassembly_info->segments[segment_number].data = segment_data;
498 status->reassembly_info->segments[segment_number].length = length;
500 status->reassembly_info->number_of_segments++;
504 /* Record the current & complete segmented SDU by mapping from this frame number to
505 struct with segment info. */
506 static void reassembly_record(channel_sequence_analysis_status *status, packet_info *pinfo,
507 guint16 SN, rlc_lte_info *p_rlc_lte_info)
509 /* Just store existing info in hash table */
510 wmem_map_insert(reassembly_report_hash,
511 get_report_hash_key(SN, pinfo->num, p_rlc_lte_info, TRUE),
512 status->reassembly_info);
515 /* Create and return a tvb based upon contents of reassembly info */
516 static tvbuff_t* reassembly_get_reassembled_tvb(rlc_channel_reassembly_info *reassembly_info,
517 tvbuff_t *parent_tvb, packet_info *pinfo)
520 guint combined_length = 0;
521 guint8 *combined_data;
522 guint combined_offset = 0;
523 tvbuff_t *reassembled_tvb;
525 /* Allocate buffer big enough to hold re-assembled data */
526 for (n=0; n < reassembly_info->number_of_segments; n++) {
527 combined_length += reassembly_info->segments[n].length;
529 combined_data = (guint8 *)wmem_alloc(pinfo->pool, combined_length);
531 /* Copy data into contiguous buffer */
532 for (n=0; n < reassembly_info->number_of_segments; n++) {
533 guint8 *data = reassembly_info->segments[n].data;
534 int length = reassembly_info->segments[n].length;
535 memcpy(combined_data+combined_offset, data, length);
536 combined_offset += length;
539 /* Create and return tvb with this data */
540 reassembled_tvb = tvb_new_child_real_data(parent_tvb, combined_data, combined_offset, combined_offset);
541 add_new_data_source(pinfo, reassembled_tvb, "Reassembled SDU");
542 return reassembled_tvb;
545 /* Show where the segments came from for a reassembled SDU */
546 static void reassembly_show_source(rlc_channel_reassembly_info *reassembly_info,
547 proto_tree *tree, tvbuff_t *tvb, gint offset)
550 proto_item *source_ti, *ti;
551 proto_tree *source_tree;
552 proto_item *segment_ti;
553 proto_tree *segment_tree;
554 guint total_length=0;
556 /* Create root of source info */
557 source_ti = proto_tree_add_item(tree,
558 hf_rlc_lte_reassembly_source,
559 tvb, 0, 0, ENC_ASCII|ENC_NA);
560 source_tree = proto_item_add_subtree(source_ti, ett_rlc_lte_reassembly_source);
561 PROTO_ITEM_SET_GENERATED(source_ti);
563 for (n=0; n < reassembly_info->number_of_segments; n++) {
564 total_length += reassembly_info->segments[n].length;
566 proto_item_append_text(source_ti, " %u segments, %u bytes", reassembly_info->number_of_segments,
569 /* Number of segments */
570 ti = proto_tree_add_uint(source_tree,
571 hf_rlc_lte_reassembly_source_number_of_segments,
572 tvb, 0, 0, reassembly_info->number_of_segments);
573 PROTO_ITEM_SET_GENERATED(ti);
576 ti = proto_tree_add_uint(source_tree,
577 hf_rlc_lte_reassembly_source_total_length,
578 tvb, 0, 0, total_length);
579 PROTO_ITEM_SET_GENERATED(ti);
581 /* Now add info about each segment in turn */
582 for (n=0; n < reassembly_info->number_of_segments; n++) {
584 /* Add next segment as a subtree */
585 rlc_segment *segment = &(reassembly_info->segments[n]);
586 proto_item_append_text(source_ti, " (SN=%u frame=%u len=%u)",
587 segment->SN, segment->frameNum, segment->length);
589 /* N.B. assume last segment from passed-in tvb! */
590 segment_ti = proto_tree_add_item(source_tree,
591 hf_rlc_lte_reassembly_source_segment,
593 (n == reassembly_info->number_of_segments-1) ? offset : 0,
594 (n == reassembly_info->number_of_segments-1) ? segment->length : 0,
596 segment_tree = proto_item_add_subtree(segment_ti, ett_rlc_lte_reassembly_source_segment);
597 proto_item_append_text(segment_ti, " (SN=%u frame=%u length=%u)",
598 segment->SN, segment->frameNum, segment->length);
599 PROTO_ITEM_SET_GENERATED(segment_ti);
601 /* Add details to segment tree */
602 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_sn,
603 tvb, 0, 0, segment->SN);
604 PROTO_ITEM_SET_GENERATED(ti);
605 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_framenum,
606 tvb, 0, 0, segment->frameNum);
607 PROTO_ITEM_SET_GENERATED(ti);
608 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_length,
609 tvb, 0, 0, segment->length);
610 PROTO_ITEM_SET_GENERATED(ti);
617 /******************************************************************/
618 /* Conversation-type status for repeated NACK checking on channel */
622 guint16 NACKs[MAX_NACKs];
624 } channel_repeated_nack_status;
626 static wmem_map_t *repeated_nack_channel_hash = NULL;
629 guint16 noOfNACKsRepeated;
630 guint16 repeatedNACKs[MAX_NACKs];
631 guint32 previousFrameNum;
632 } channel_repeated_nack_report;
634 static wmem_map_t *repeated_nack_report_hash = NULL;
638 /********************************************************/
639 /* Forward declarations & functions */
640 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing);
643 /* Write the given formatted text to:
645 - the top-level RLC PDU item
646 - another subtree item (if supplied) */
647 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
648 packet_info *pinfo, const char *format, ...)
650 #define MAX_INFO_BUFFER 256
651 static char info_buffer[MAX_INFO_BUFFER];
655 va_start(ap, format);
656 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
659 /* Add to indicated places */
660 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
661 proto_item_append_text(pdu_ti, "%s", info_buffer);
662 if (sub_ti != NULL) {
663 proto_item_append_text(sub_ti, "%s", info_buffer);
667 /* Version of function above, where no g_vsnprintf() call needed
669 - the top-level RLC PDU item
670 - another subtree item (if supplied) */
671 static void write_pdu_label_and_info_literal(proto_item *pdu_ti, proto_item *sub_ti,
672 packet_info *pinfo, const char *info_buffer)
674 /* Add to indicated places */
675 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
676 proto_item_append_text(pdu_ti, "%s", info_buffer);
677 if (sub_ti != NULL) {
678 proto_item_append_text(sub_ti, "%s", info_buffer);
684 /* Dissect extension headers (common to both UM and AM) */
685 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo _U_,
688 rlc_lte_info *p_rlc_lte_info)
691 guint64 extension = 1;
694 /* Reset this count */
695 s_number_of_extensions = 0;
697 while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
698 proto_tree *extension_part_tree;
699 proto_item *extension_part_ti;
701 /* Extension part subtree */
702 extension_part_ti = proto_tree_add_string_format(tree,
703 hf_rlc_lte_extension_part,
707 extension_part_tree = proto_item_add_subtree(extension_part_ti,
708 ett_rlc_lte_extension_part);
710 if (p_rlc_lte_info->extendedLiField == FALSE) {
711 isOdd = (s_number_of_extensions % 2);
713 /* Read next extension */
714 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
715 (offset*8) + ((isOdd) ? 4 : 0),
717 &extension, ENC_BIG_ENDIAN);
719 /* Read length field */
720 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
721 (offset*8) + ((isOdd) ? 5 : 1),
723 &length, ENC_BIG_ENDIAN);
725 /* Move on to byte of next extension */
732 /* Read next extension */
733 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
736 &extension, ENC_BIG_ENDIAN);
738 /* Read length field */
739 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
742 &length, ENC_BIG_ENDIAN);
744 /* Move on to byte of next extension */
748 proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length);
750 s_lengths[s_number_of_extensions++] = (guint16)length;
753 /* May need to skip padding after last extension part */
754 isOdd = (s_number_of_extensions % 2);
755 if (isOdd && (p_rlc_lte_info->extendedLiField == FALSE)) {
756 proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
757 tvb, offset++, 1, ENC_BIG_ENDIAN);
764 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
765 whether or not the beginning and end are included in this packet */
766 static void show_PDU_in_info(packet_info *pinfo,
769 gboolean first_includes_start,
770 gboolean last_includes_end)
772 /* Reflect this PDU in the info column */
774 write_pdu_label_and_info(top_ti, NULL, pinfo,
776 (first_includes_start) ? "[" : "..",
778 (length > 1) ? "s" : "",
779 (last_includes_end) ? "]" : "..");
782 write_pdu_label_and_info(top_ti, NULL, pinfo,
783 " %sunknown-bytes%s",
784 (first_includes_start) ? "[" : "..",
785 (last_includes_end) ? "]" : "..");
790 /* Show an SDU. If configured, pass to PDCP/RRC/IP dissector */
791 static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, gint offset, gint length,
792 rlc_lte_info *rlc_info, gboolean whole_pdu, rlc_channel_reassembly_info *reassembly_info,
793 sequence_analysis_state state)
795 wmem_tree_key_t key[3];
797 rlc_ue_parameters *params;
799 /* Add raw data (according to mode) */
800 proto_item *data_ti = proto_tree_add_item(tree,
801 (rlc_info->rlcMode == RLC_AM_MODE) ?
804 tvb, offset, length, ENC_NA);
806 if (whole_pdu || (reassembly_info != NULL)) {
807 if (((global_rlc_lte_call_pdcp_for_srb) && (rlc_info->channelType == CHANNEL_TYPE_SRB)) ||
808 ((global_rlc_lte_call_pdcp_for_drb != PDCP_drb_off) && (rlc_info->channelType == CHANNEL_TYPE_DRB))) {
809 /* Send whole PDU to PDCP */
811 /* TODO: made static to avoid compiler warning... */
812 static tvbuff_t *pdcp_tvb = NULL;
813 struct pdcp_lte_info *p_pdcp_lte_info;
815 /* Get tvb for passing to LTE PDCP dissector */
816 if (reassembly_info == NULL) {
817 pdcp_tvb = tvb_new_subset_length(tvb, offset, length);
820 /* Get combined tvb. */
821 pdcp_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
822 reassembly_show_source(reassembly_info, tree, tvb, offset);
825 /* Reuse or allocate struct */
826 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
827 if (p_pdcp_lte_info == NULL) {
828 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
829 /* Store info in packet */
830 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0, p_pdcp_lte_info);
833 p_pdcp_lte_info->ueid = rlc_info->ueid;
834 if (rlc_info->nbMode == rlc_nb_mode) {
835 p_pdcp_lte_info->channelType = Channel_DCCH_NB;
837 p_pdcp_lte_info->channelType = Channel_DCCH;
839 p_pdcp_lte_info->channelId = rlc_info->channelId;
840 p_pdcp_lte_info->direction = rlc_info->direction;
841 p_pdcp_lte_info->is_retx = (state != SN_OK);
843 /* Set plane and sequence number length */
844 p_pdcp_lte_info->no_header_pdu = FALSE;
845 if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
846 p_pdcp_lte_info->plane = SIGNALING_PLANE;
847 if ((rlc_info->nbMode == rlc_nb_mode) && (rlc_info->channelId == 3)) {
848 p_pdcp_lte_info->no_header_pdu = TRUE;
849 p_pdcp_lte_info->seqnum_length = 0;
851 p_pdcp_lte_info->seqnum_length = 5;
855 p_pdcp_lte_info->plane = USER_PLANE;
856 switch (global_rlc_lte_call_pdcp_for_drb) {
858 p_pdcp_lte_info->seqnum_length = 7;
861 p_pdcp_lte_info->seqnum_length = 12;
864 p_pdcp_lte_info->seqnum_length = 15;
867 p_pdcp_lte_info->seqnum_length = 18;
869 case PDCP_drb_SN_signalled:
870 /* Use whatever was signalled (e.g. in RRC) */
871 id = (rlc_info->channelId << 16) | rlc_info->ueid;
875 key[1].key = &pinfo->num;
879 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
880 if (params && (params->id != id)) {
884 p_pdcp_lte_info->seqnum_length = params->pdcp_sn_bits;
885 } else if (rlc_info->nbMode == rlc_nb_mode) {
886 p_pdcp_lte_info->seqnum_length = 7;
888 p_pdcp_lte_info->seqnum_length = 12;
893 DISSECTOR_ASSERT(FALSE);
899 call_dissector_only(pdcp_lte_handle, pdcp_tvb, pinfo, tree, NULL);
905 PROTO_ITEM_SET_HIDDEN(data_ti);
907 else if (global_rlc_lte_call_rrc_for_mcch && (rlc_info->channelType == CHANNEL_TYPE_MCCH)) {
908 /* Send whole PDU to RRC */
909 static tvbuff_t *rrc_tvb = NULL;
911 /* Get tvb for passing to LTE RRC dissector */
912 if (reassembly_info == NULL) {
913 rrc_tvb = tvb_new_subset_length(tvb, offset, length);
916 /* Get combined tvb. */
917 rrc_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
918 reassembly_show_source(reassembly_info, tree, tvb, offset);
922 call_dissector_only(lte_rrc_mcch, rrc_tvb, pinfo, tree, NULL);
928 PROTO_ITEM_SET_HIDDEN(data_ti);
930 else if (global_rlc_lte_call_ip_for_mtch && (rlc_info->channelType == CHANNEL_TYPE_MTCH)) {
931 /* Send whole PDU to IP */
932 static tvbuff_t *ip_tvb = NULL;
934 /* Get tvb for passing to IP dissector */
935 if (reassembly_info == NULL) {
936 ip_tvb = tvb_new_subset_length(tvb, offset, length);
939 /* Get combined tvb. */
940 ip_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
941 reassembly_show_source(reassembly_info, tree, tvb, offset);
945 call_dissector_only(ip_handle, ip_tvb, pinfo, tree, NULL);
951 PROTO_ITEM_SET_HIDDEN(data_ti);
956 /* Hash table functions for RLC channels */
959 static gint rlc_channel_equal(gconstpointer v, gconstpointer v2)
961 const channel_hash_key* val1 = (const channel_hash_key *)v;
962 const channel_hash_key* val2 = (const channel_hash_key *)v2;
964 /* All fields must match */
965 /* N.B. Currently fits into one word, so could return (*v == *v2)
966 if we're sure they're initialised to 0... */
967 return ((val1->ueId == val2->ueId) &&
968 (val1->channelType == val2->channelType) &&
969 (val1->channelId == val2->channelId) &&
970 (val1->direction == val2->direction));
973 /* Compute a hash value for a given key. */
974 static guint rlc_channel_hash_func(gconstpointer v)
976 const channel_hash_key* val1 = (const channel_hash_key *)v;
978 /* TODO: check/reduce multipliers */
979 return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
983 /*************************************************************************/
989 guint32 channelType : 2;
990 guint32 channelId: 5;
991 guint32 direction: 1;
992 } rlc_result_hash_key;
994 /* Compare 2 rlc_result_hash_key structs */
995 static gint rlc_result_hash_equal(gconstpointer v, gconstpointer v2)
997 const rlc_result_hash_key *val1 = (const rlc_result_hash_key *)v;
998 const rlc_result_hash_key *val2 = (const rlc_result_hash_key *)v2;
1000 /* All fields (and any padding...) must match */
1001 return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
1004 /* Compute a hash value for a given key. */
1005 static guint rlc_result_hash_func(gconstpointer v)
1007 const rlc_result_hash_key* val1 = (const rlc_result_hash_key *)v;
1009 /* Got rid of multipliers - no evidence that they reduced collisions */
1010 return val1->frameNumber + val1->SN +
1016 /* Convenience function to get a pointer for the hash_func to work with */
1017 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
1018 rlc_lte_info *p_rlc_lte_info,
1019 gboolean do_persist)
1021 static rlc_result_hash_key key;
1022 rlc_result_hash_key *p_key;
1024 /* Only allocate a struct when will be adding entry */
1026 p_key = wmem_new0(wmem_file_scope(), rlc_result_hash_key);
1029 memset(&key, 0, sizeof(rlc_result_hash_key));
1033 /* Fill in details, and return pointer */
1034 p_key->frameNumber = frameNumber;
1036 p_key->channelType = p_rlc_lte_info->channelType;
1037 p_key->channelId = p_rlc_lte_info->channelId;
1038 p_key->direction = p_rlc_lte_info->direction;
1043 static void checkFIconsistency(sequence_analysis_report *p,
1044 rlc_lte_info *p_rlc_lte_info,
1045 gboolean newSegmentStarted,
1046 proto_tree *seqnum_tree,
1047 packet_info *pinfo, tvbuff_t *tvb)
1051 if (p->previousSegmentIncomplete) {
1052 /* Previous segment was incomplete, so this PDU should continue it */
1053 if (newSegmentStarted) {
1054 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1056 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_not_continued,
1057 "Last segment of previous PDU was not continued for UE %u (%s-%u)",
1058 p_rlc_lte_info->ueid,
1059 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1060 p_rlc_lte_info->channelId);
1063 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1065 PROTO_ITEM_SET_HIDDEN(ti);
1069 /* Previous segment was complete, so this PDU should start a new one */
1070 if (!newSegmentStarted) {
1071 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1073 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_complete,
1074 "Last segment of previous PDU was complete, but new segment was not started on UE %u (%s-%u)",
1075 p_rlc_lte_info->ueid,
1076 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1077 p_rlc_lte_info->channelId);
1080 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1082 PROTO_ITEM_SET_HIDDEN(ti);
1085 PROTO_ITEM_SET_GENERATED(ti);
1088 /* Add to the tree values associated with sequence analysis for this frame */
1089 static void addChannelSequenceInfo(sequence_analysis_report *p,
1090 gboolean isControlFrame,
1091 rlc_lte_info *p_rlc_lte_info,
1092 guint16 sequenceNumber,
1093 gboolean newSegmentStarted,
1094 rlc_lte_tap_info *tap_info,
1095 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
1097 proto_tree *seqnum_tree;
1098 proto_item *seqnum_ti;
1101 /* Create subtree */
1102 seqnum_ti = proto_tree_add_string_format(tree,
1103 hf_rlc_lte_sequence_analysis,
1105 "", "Sequence Analysis");
1106 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1107 ett_rlc_lte_sequence_analysis);
1108 PROTO_ITEM_SET_GENERATED(seqnum_ti);
1110 if (p->previousFrameNum != 0) {
1111 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1112 tvb, 0, 0, p->previousFrameNum);
1113 PROTO_ITEM_SET_GENERATED(ti);
1116 switch (p_rlc_lte_info->rlcMode) {
1119 /********************************************/
1121 /********************************************/
1125 if (isControlFrame) {
1129 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1131 PROTO_ITEM_SET_GENERATED(ti);
1132 proto_item_append_text(seqnum_ti, " - OK");
1134 /* Link to next SN in channel (if known) */
1135 if (p->nextFrameNum != 0) {
1136 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1137 tvb, 0, 0, p->nextFrameNum);
1139 /* Correct sequence number, so check frame indication bits consistent */
1140 /* Deactivated for now as it gets confused by resegmentation */
1141 /* checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb); */
1145 if (isControlFrame) {
1149 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1151 PROTO_ITEM_SET_GENERATED(ti);
1152 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1154 PROTO_ITEM_SET_GENERATED(ti);
1155 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1156 "AM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1157 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1158 p_rlc_lte_info->ueid,
1159 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1160 p_rlc_lte_info->channelId);
1161 proto_item_append_text(seqnum_ti, " - MAC retx of SN %u", p->firstSN);
1165 if (isControlFrame) {
1169 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1171 PROTO_ITEM_SET_GENERATED(ti);
1172 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
1174 PROTO_ITEM_SET_GENERATED(ti);
1175 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_retx,
1176 "AM Frame retransmitted for %s on UE %u - most likely in response to NACK (%s-%u)",
1177 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1178 p_rlc_lte_info->ueid,
1179 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1180 p_rlc_lte_info->channelId);
1181 proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
1185 if (isControlFrame) {
1189 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1191 PROTO_ITEM_SET_GENERATED(ti);
1192 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1194 PROTO_ITEM_SET_GENERATED(ti);
1195 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated,
1196 "AM SN Repeated for %s for UE %u - probably because didn't receive Status PDU? (%s-%u)",
1197 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1198 p_rlc_lte_info->ueid,
1199 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1200 p_rlc_lte_info->channelId);
1201 proto_item_append_text(seqnum_ti, "- SN %u Repeated", p->firstSN);
1205 if (isControlFrame) {
1209 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1211 PROTO_ITEM_SET_GENERATED(ti);
1212 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1214 PROTO_ITEM_SET_GENERATED(ti);
1215 if (p->lastSN != p->firstSN) {
1216 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1217 "AM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1218 p->firstSN, p->lastSN,
1219 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1220 p_rlc_lte_info->ueid,
1221 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1222 p_rlc_lte_info->channelId);
1223 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1224 p->firstSN, p->lastSN);
1225 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1226 tap_info->missingSNs = ((65536 + (guint32)p->lastSN - (guint32)p->firstSN) % 65536) + 1;
1228 tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1232 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1233 "AM SN (%u) missing for %s on UE %u (%s-%u)",
1235 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1236 p_rlc_lte_info->ueid,
1237 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1238 p_rlc_lte_info->channelId);
1239 proto_item_append_text(seqnum_ti, " - SN missing (%u)", p->firstSN);
1240 tap_info->missingSNs = 1;
1244 case ACK_Out_of_Window:
1245 if (!isControlFrame) {
1251 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1254 PROTO_ITEM_SET_GENERATED(ti);
1255 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1257 PROTO_ITEM_SET_GENERATED(ti);
1259 /* Link back to last seen SN in other direction */
1260 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1261 tvb, 0, 0, p->previousFrameNum);
1262 PROTO_ITEM_SET_GENERATED(ti);
1265 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1266 "AM ACK for SN %u - but last received SN in other direction is %u for UE %u (%s-%u)",
1267 p->firstSN, p->sequenceExpected,
1268 p_rlc_lte_info->ueid,
1269 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1270 p_rlc_lte_info->channelId);
1271 proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1272 p->firstSN, p->sequenceExpected);
1283 /********************************************/
1285 /********************************************/
1287 /* Expected sequence number */
1288 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
1289 tvb, 0, 0, p->sequenceExpected);
1290 PROTO_ITEM_SET_GENERATED(ti);
1291 if (p->sequenceExpectedCorrect) {
1292 PROTO_ITEM_SET_HIDDEN(ti);
1295 if (!p->sequenceExpectedCorrect) {
1296 /* Work out SN wrap (in case needed below) */
1298 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1307 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1309 PROTO_ITEM_SET_GENERATED(ti);
1310 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1312 PROTO_ITEM_SET_GENERATED(ti);
1313 if (p->lastSN != p->firstSN) {
1314 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1315 "UM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1316 p->firstSN, p->lastSN,
1317 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1318 p_rlc_lte_info->ueid,
1319 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1320 p_rlc_lte_info->channelId);
1321 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1322 p->firstSN, p->lastSN);
1323 tap_info->missingSNs = ((snLimit + p->lastSN - p->firstSN) % snLimit) + 1;
1326 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1327 "UM SN (%u) missing for %s on UE %u (%s-%u)",
1329 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1330 p_rlc_lte_info->ueid,
1331 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1332 p_rlc_lte_info->channelId);
1333 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
1335 tap_info->missingSNs = 1;
1340 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1342 PROTO_ITEM_SET_GENERATED(ti);
1343 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1345 PROTO_ITEM_SET_GENERATED(ti);
1346 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_repeated,
1347 "UM SN (%u) repeated for %s for UE %u (%s-%u)",
1349 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1350 p_rlc_lte_info->ueid,
1351 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1352 p_rlc_lte_info->channelId);
1353 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
1358 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1360 PROTO_ITEM_SET_GENERATED(ti);
1361 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1363 PROTO_ITEM_SET_GENERATED(ti);
1364 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1365 "UM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1366 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1367 p_rlc_lte_info->ueid,
1368 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1369 p_rlc_lte_info->channelId);
1373 /* Incorrect sequence number */
1374 expert_add_info_format(pinfo, ti, &ei_rlc_lte_wrong_sequence_number,
1375 "Wrong Sequence Number for %s on UE %u - got %u, expected %u (%s-%u)",
1376 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1377 p_rlc_lte_info->ueid, sequenceNumber, p->sequenceExpected,
1378 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1379 p_rlc_lte_info->channelId);
1386 /* Correct sequence number, so check frame indication bits consistent */
1387 checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb);
1390 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1392 PROTO_ITEM_SET_GENERATED(ti);
1393 proto_item_append_text(seqnum_ti, " - OK");
1396 /* Next channel frame */
1397 if (p->nextFrameNum != 0) {
1398 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1399 tvb, 0, 0, p->nextFrameNum);
1400 PROTO_ITEM_SET_GENERATED(ti);
1405 /* Update the channel status and set report for this frame */
1406 static sequence_analysis_state checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
1407 rlc_lte_info *p_rlc_lte_info,
1408 gboolean isControlFrame,
1409 guint8 number_of_segments,
1410 guint16 firstSegmentOffset,
1411 guint16 firstSegmentLength,
1412 guint16 lastSegmentOffset,
1413 guint16 sequenceNumber,
1414 gboolean first_includes_start, gboolean last_includes_end,
1415 gboolean is_resegmented _U_,
1416 rlc_lte_tap_info *tap_info,
1419 channel_hash_key channel_key;
1420 channel_hash_key *p_channel_key;
1421 channel_sequence_analysis_status *p_channel_status;
1422 sequence_analysis_report *p_report_in_frame = NULL;
1423 gboolean createdChannel = FALSE;
1424 guint16 expectedSequenceNumber = 0;
1425 guint32 snLimit = 0;
1427 /* If find stat_report_in_frame already, use that and get out */
1428 if (pinfo->fd->flags.visited) {
1429 p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1430 get_report_hash_key(sequenceNumber,
1434 if (p_report_in_frame != NULL) {
1435 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
1436 sequenceNumber, first_includes_start,
1437 tap_info, pinfo, tree, tvb);
1438 return p_report_in_frame->state;
1441 /* Don't just give up here... */
1445 /**************************************************/
1446 /* Create or find an entry for this channel state */
1447 channel_key.ueId = p_rlc_lte_info->ueid;
1448 channel_key.channelType = p_rlc_lte_info->channelType;
1449 channel_key.channelId = p_rlc_lte_info->channelId;
1450 channel_key.direction = p_rlc_lte_info->direction;
1452 /* Do the table lookup */
1453 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1455 /* Create table entry if necessary */
1456 if (p_channel_status == NULL) {
1457 createdChannel = TRUE;
1459 /* Allocate a new value and duplicate key contents */
1460 p_channel_status = wmem_new0(wmem_file_scope(), channel_sequence_analysis_status);
1461 p_channel_key = (channel_hash_key *)wmem_memdup(wmem_file_scope(), &channel_key, sizeof(channel_hash_key));
1464 p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1467 wmem_map_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1470 /* Create space for frame state_report */
1471 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1474 /* Deal with according to channel mode */
1475 switch (p_channel_status->rlcMode) {
1478 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1485 /* Work out expected sequence number */
1486 if (!createdChannel) {
1487 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1490 /* Whatever we got is fine.. */
1491 expectedSequenceNumber = sequenceNumber;
1494 if ((sequenceNumber == 0) &&
1495 ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH))) {
1496 /* With eMBMS, SN restarts to 0 at each MCH Scheduling Period so we cannot deduce easily whether
1497 there was a PDU loss or not without analysing the Frame Indicator; assume no loss when seeing 0 */
1498 expectedSequenceNumber = 0;
1501 /* Set report for this frame */
1502 /* For UM, sequence number is always expectedSequence number */
1503 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
1505 /* For wrong sequence number... */
1506 if (!p_report_in_frame->sequenceExpectedCorrect) {
1508 /* Don't get confused by MAC (HARQ) retx */
1509 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1510 p_report_in_frame->state = SN_MAC_Retx;
1511 p_report_in_frame->firstSN = sequenceNumber;
1513 /* No channel state to update */
1517 /* Frames are not missing if we get an earlier sequence number again */
1518 /* TODO: taking time into account would give better idea of whether missing or repeated... */
1519 else if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH) ||
1520 (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10)) {
1521 reassembly_destroy(p_channel_status);
1523 p_report_in_frame->state = SN_Missing;
1524 tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
1525 p_report_in_frame->firstSN = expectedSequenceNumber;
1526 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
1528 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1529 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1530 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1532 /* Update channel status to remember *this* frame */
1533 p_channel_status->previousFrameNum = pinfo->num;
1534 p_channel_status->previousSequenceNumber = sequenceNumber;
1535 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1538 /* An SN has been repeated */
1539 p_report_in_frame->state = SN_Repeated;
1540 p_report_in_frame->firstSN = sequenceNumber;
1542 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1543 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1548 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1549 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1550 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1552 /* Update channel status to remember *this* frame */
1553 p_channel_status->previousFrameNum = pinfo->num;
1554 p_channel_status->previousSequenceNumber = sequenceNumber;
1555 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1557 if (p_channel_status->reassembly_info) {
1558 /* Add next segment to reassembly info */
1559 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1560 tvb, firstSegmentOffset, firstSegmentLength);
1562 /* The end of existing reassembly? */
1563 if (!first_includes_start &&
1564 ((number_of_segments > 1) || last_includes_end)) {
1566 reassembly_record(p_channel_status, pinfo, sequenceNumber, p_rlc_lte_info);
1567 reassembly_destroy(p_channel_status);
1571 /* The start of a new reassembly? */
1572 if (!last_includes_end &&
1573 ((number_of_segments > 1) || first_includes_start)) {
1575 guint16 lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1577 if (global_rlc_lte_reassembly) {
1578 reassembly_reset(p_channel_status);
1579 reassembly_add_segment(p_channel_status, sequenceNumber,
1581 tvb, lastSegmentOffset, lastSegmentLength);
1585 if (p_report_in_frame->previousFrameNum != 0) {
1586 /* Get report for previous frame */
1587 sequence_analysis_report *p_previous_report;
1588 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1595 /* Look up report for previous SN */
1596 p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1597 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1598 p_report_in_frame->previousFrameNum,
1601 /* It really shouldn't be NULL... */
1602 if (p_previous_report != NULL) {
1603 /* Point it forward to this one */
1604 p_previous_report->nextFrameNum = pinfo->num;
1613 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1619 /* Work out expected sequence number */
1620 if (!createdChannel) {
1621 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1624 /* Whatever we got is fine.. */
1625 expectedSequenceNumber = sequenceNumber;
1629 - expected Sequence number OR
1630 - previous frame repeated
1631 - old SN being sent (in response to NACK)
1632 - new SN, but with frames missed out
1633 Assume window whose front is at expectedSequenceNumber */
1635 /* First of all, check to see whether frame is judged to be MAC Retx */
1636 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1637 /* Just report that this is a MAC Retx */
1638 p_report_in_frame->state = SN_MAC_Retx;
1639 p_report_in_frame->firstSN = sequenceNumber;
1641 /* No channel state to update */
1645 if (sequenceNumber != expectedSequenceNumber) {
1646 /* Don't trash reassembly info if this looks like a close retx... */
1647 if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 50) {
1648 reassembly_destroy(p_channel_status);
1653 if (sequenceNumber == expectedSequenceNumber) {
1654 /* Set report for this frame */
1655 p_report_in_frame->sequenceExpectedCorrect = TRUE;
1656 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1657 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1658 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1659 p_report_in_frame->state = SN_OK;
1661 /* Update channel status */
1662 p_channel_status->previousSequenceNumber = sequenceNumber;
1663 p_channel_status->previousFrameNum = pinfo->num;
1664 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1667 if (p_channel_status->reassembly_info) {
1669 /* Add next segment to reassembly info */
1670 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1671 tvb, firstSegmentOffset, firstSegmentLength);
1673 /* The end of existing reassembly? */
1674 if (!first_includes_start &&
1675 ((number_of_segments > 1) || last_includes_end)) {
1677 reassembly_record(p_channel_status, pinfo,
1678 sequenceNumber, p_rlc_lte_info);
1679 reassembly_destroy(p_channel_status);
1683 /* The start of a new reassembly? */
1684 if (!last_includes_end &&
1685 ((number_of_segments > 1) || first_includes_start)) {
1687 guint16 lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1688 if (global_rlc_lte_reassembly) {
1689 reassembly_reset(p_channel_status);
1690 reassembly_add_segment(p_channel_status, sequenceNumber,
1692 tvb, lastSegmentOffset, lastSegmentLength);
1696 if (p_report_in_frame->previousFrameNum != 0) {
1697 /* Get report for previous frame */
1698 sequence_analysis_report *p_previous_report;
1699 p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1700 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1701 p_report_in_frame->previousFrameNum,
1704 /* It really shouldn't be NULL... */
1705 if (p_previous_report != NULL) {
1706 /* Point it forward to this one */
1707 p_previous_report->nextFrameNum = pinfo->num;
1713 /* Previous subframe repeated? */
1714 else if (((sequenceNumber+1) % snLimit) == expectedSequenceNumber) {
1715 p_report_in_frame->state = SN_Repeated;
1717 /* Set report for this frame */
1718 p_report_in_frame->sequenceExpectedCorrect = FALSE;
1719 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1720 p_report_in_frame->firstSN = sequenceNumber;
1721 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1722 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1725 /* Really should be nothing to update... */
1726 p_channel_status->previousSequenceNumber = sequenceNumber;
1727 p_channel_status->previousFrameNum = pinfo->num;
1728 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1732 /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1733 gint delta = (snLimit + expectedSequenceNumber - sequenceNumber) % snLimit;
1735 /* Rx window is 512/32768, so check to see if this is a retx */
1736 if (delta < (gint)(snLimit>>1)) {
1737 /* Probably a retx due to receiving NACK */
1738 p_report_in_frame->state = SN_Retx;
1740 p_report_in_frame->firstSN = sequenceNumber;
1741 /* Don't update anything in channel state */
1745 /* Ahead of expected SN. Assume frames have been missed */
1746 p_report_in_frame->state = SN_Missing;
1748 p_report_in_frame->firstSN = expectedSequenceNumber;
1749 p_report_in_frame->lastSN = (snLimit + sequenceNumber-1) % snLimit;
1751 /* Update channel state - forget about missed SNs */
1752 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1753 p_channel_status->previousSequenceNumber = sequenceNumber;
1754 p_channel_status->previousFrameNum = pinfo->num;
1755 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1761 /* Shouldn't get here! */
1765 /* Associate with this frame number */
1766 wmem_map_insert(sequence_analysis_report_hash,
1767 get_report_hash_key(sequenceNumber, pinfo->num, p_rlc_lte_info, TRUE),
1770 /* Add state report for this frame into tree */
1771 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1772 first_includes_start, tap_info, pinfo, tree, tvb);
1774 return p_report_in_frame->state;
1778 /* Add to the tree values associated with sequence analysis for this frame */
1779 static void addChannelRepeatedNACKInfo(channel_repeated_nack_report *p,
1780 rlc_lte_info *p_rlc_lte_info,
1781 packet_info *pinfo, proto_tree *tree,
1784 proto_tree *seqnum_tree;
1785 proto_item *seqnum_ti;
1789 /* Create subtree */
1790 seqnum_ti = proto_tree_add_string_format(tree,
1791 hf_rlc_lte_sequence_analysis,
1793 "", "Sequence Analysis");
1794 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1795 ett_rlc_lte_sequence_analysis);
1796 PROTO_ITEM_SET_GENERATED(seqnum_ti);
1799 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1801 PROTO_ITEM_SET_GENERATED(ti);
1803 /* Add each repeated NACK as item & expert info */
1804 for (n=0; n < p->noOfNACKsRepeated; n++) {
1806 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
1807 tvb, 0, 0, p->repeatedNACKs[n]);
1808 PROTO_ITEM_SET_GENERATED(ti);
1810 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated_nack,
1811 "Same SN (%u) NACKd for %s on UE %u in successive Status PDUs",
1812 p->repeatedNACKs[n],
1813 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1814 p_rlc_lte_info->ueid);
1817 /* Link back to previous status report */
1818 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
1819 tvb, 0, 0, p->previousFrameNum);
1820 PROTO_ITEM_SET_GENERATED(ti);
1822 /* Append count to sequence analysis root */
1823 proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
1824 p->noOfNACKsRepeated);
1828 /* Update the channel repeated NACK status and set report for this frame */
1829 static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
1830 rlc_lte_info *p_rlc_lte_info,
1831 rlc_lte_tap_info *tap_info,
1835 channel_hash_key channel_key;
1836 channel_hash_key *p_channel_key;
1837 channel_repeated_nack_status *p_channel_status;
1838 channel_repeated_nack_report *p_report_in_frame = NULL;
1840 guint16 noOfNACKsRepeated = 0;
1841 guint16 repeatedNACKs[MAX_NACKs];
1844 /* If find state_report_in_frame already, use that and get out */
1845 if (pinfo->fd->flags.visited) {
1846 p_report_in_frame = (channel_repeated_nack_report*)wmem_map_lookup(repeated_nack_report_hash,
1847 get_report_hash_key(0, pinfo->num,
1848 p_rlc_lte_info, FALSE));
1849 if (p_report_in_frame != NULL) {
1850 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1855 /* Give up - we must have tried already... */
1861 /**************************************************/
1862 /* Create or find an entry for this channel state */
1863 channel_key.ueId = p_rlc_lte_info->ueid;
1864 channel_key.channelType = p_rlc_lte_info->channelType;
1865 channel_key.channelId = p_rlc_lte_info->channelId;
1866 channel_key.direction = p_rlc_lte_info->direction;
1867 memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1869 /* Do the table lookup */
1870 p_channel_status = (channel_repeated_nack_status*)wmem_map_lookup(repeated_nack_channel_hash, &channel_key);
1872 /* Create table entry if necessary */
1873 if (p_channel_status == NULL) {
1875 /* Allocate a new key and value */
1876 p_channel_key = wmem_new(wmem_file_scope(), channel_hash_key);
1877 p_channel_status = wmem_new0(wmem_file_scope(), channel_repeated_nack_status);
1879 /* Copy key contents */
1880 memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1882 /* Add entry to table */
1883 wmem_map_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1886 /* Compare NACKs in channel status with NACKs in tap_info.
1887 Note any that are repeated */
1888 for (i=0; i < p_channel_status->noOfNACKs; i++) {
1889 for (j=0; j < MIN(tap_info->noOfNACKs, MAX_NACKs); j++) {
1890 if (tap_info->NACKs[j] == p_channel_status->NACKs[i]) {
1891 /* Don't add the same repeated NACK twice! */
1892 if ((noOfNACKsRepeated == 0) ||
1893 (repeatedNACKs[noOfNACKsRepeated-1] != p_channel_status->NACKs[i])) {
1895 repeatedNACKs[noOfNACKsRepeated++] = p_channel_status->NACKs[i];
1901 /* Copy NACKs from tap_info into channel status for next time! */
1902 p_channel_status->noOfNACKs = 0;
1903 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1904 p_channel_status->NACKs[p_channel_status->noOfNACKs++] = tap_info->NACKs[n];
1907 if (noOfNACKsRepeated >= 1) {
1908 /* Create space for frame state_report */
1909 p_report_in_frame = wmem_new(wmem_file_scope(), channel_repeated_nack_report);
1911 /* Copy in found duplicates */
1912 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1913 p_report_in_frame->repeatedNACKs[n] = repeatedNACKs[n];
1915 p_report_in_frame->noOfNACKsRepeated = noOfNACKsRepeated;
1917 p_report_in_frame->previousFrameNum = p_channel_status->frameNum;
1919 /* Associate with this frame number */
1920 wmem_map_insert(repeated_nack_report_hash,
1921 get_report_hash_key(0, pinfo->num,
1922 p_rlc_lte_info, TRUE),
1925 /* Add state report for this frame into tree */
1926 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1930 /* Save frame number for next comparison */
1931 p_channel_status->frameNum = pinfo->num;
1934 /* Check that the ACK is consistent with data the expected sequence number
1935 in the other direction */
1936 static void checkChannelACKWindow(guint16 ack_sn,
1938 rlc_lte_info *p_rlc_lte_info,
1939 rlc_lte_tap_info *tap_info,
1943 channel_hash_key channel_key;
1944 channel_sequence_analysis_status *p_channel_status;
1945 sequence_analysis_report *p_report_in_frame = NULL;
1948 /* If find stat_report_in_frame already, use that and get out */
1949 if (pinfo->fd->flags.visited) {
1950 p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1951 get_report_hash_key(0, pinfo->num,
1954 if (p_report_in_frame != NULL) {
1955 /* Add any info to tree */
1956 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info,
1958 tap_info, pinfo, tree, tvb);
1962 /* Give up - we must have tried already... */
1967 /*******************************************************************/
1968 /* Find an entry for this channel state (in the opposite direction */
1969 channel_key.ueId = p_rlc_lte_info->ueid;
1970 channel_key.channelType = p_rlc_lte_info->channelType;
1971 channel_key.channelId = p_rlc_lte_info->channelId;
1972 channel_key.direction =
1973 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1975 /* Do the table lookup */
1976 p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1978 /* Create table entry if necessary */
1979 if (p_channel_status == NULL) {
1983 /* Is it in the rx window? This test will catch if it's ahead, but we don't
1984 really know what the back of the tx window is... */
1985 snLimit = (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) ? 65536 : 1024;
1986 if (((snLimit + (guint32)p_channel_status->previousSequenceNumber+1 - ack_sn) % snLimit) > (snLimit>>1)) {
1989 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1990 p_report_in_frame->state = ACK_Out_of_Window;
1991 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1992 p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1993 p_report_in_frame->firstSN = ack_sn;
1995 /* Associate with this frame number */
1996 wmem_map_insert(sequence_analysis_report_hash,
1997 get_report_hash_key(0, pinfo->num,
1998 p_rlc_lte_info, TRUE),
2001 /* Add state report for this frame into tree */
2002 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info, 0,
2003 FALSE, tap_info, pinfo, tree, tvb);
2010 /***************************************************/
2011 /* Transparent mode PDU. Call RRC if configured to */
2012 static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
2015 rlc_lte_info *p_rlc_lte_info,
2018 proto_item *raw_tm_ti;
2021 /* Create hidden TM root */
2022 tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
2023 tvb, offset, 0, "", "TM");
2024 PROTO_ITEM_SET_HIDDEN(tm_ti);
2026 /* Remaining bytes are all data */
2027 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, ENC_NA);
2028 if (!global_rlc_lte_call_rrc_for_ccch) {
2029 write_pdu_label_and_info(top_ti, NULL, pinfo,
2030 " [%u-bytes]", tvb_reported_length_remaining(tvb, offset));
2033 if (global_rlc_lte_call_rrc_for_ccch) {
2034 tvbuff_t *rrc_tvb = tvb_new_subset_remaining(tvb, offset);
2035 volatile dissector_handle_t protocol_handle;
2037 switch (p_rlc_lte_info->channelType) {
2038 case CHANNEL_TYPE_CCCH:
2039 if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
2040 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2041 lte_rrc_ul_ccch_nb : lte_rrc_ul_ccch;
2044 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2045 lte_rrc_dl_ccch_nb : lte_rrc_dl_ccch;
2049 case CHANNEL_TYPE_BCCH_BCH:
2050 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2051 lte_rrc_bcch_bch_nb : lte_rrc_bcch_bch;
2053 case CHANNEL_TYPE_BCCH_DL_SCH:
2054 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2055 lte_rrc_bcch_dl_sch_nb : lte_rrc_bcch_dl_sch;
2057 case CHANNEL_TYPE_PCCH:
2058 protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2059 lte_rrc_pcch_nb : lte_rrc_pcch;
2062 case CHANNEL_TYPE_SRB:
2063 case CHANNEL_TYPE_DRB:
2064 case CHANNEL_TYPE_MCCH:
2065 case CHANNEL_TYPE_MTCH:
2068 /* Shouldn't happen, just return... */
2072 /* Hide raw view of bytes */
2073 PROTO_ITEM_SET_HIDDEN(raw_tm_ti);
2075 /* Call it (catch exceptions) */
2077 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
2087 /***************************************************/
2088 /* Unacknowledged mode PDU */
2089 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
2092 rlc_lte_info *p_rlc_lte_info,
2094 rlc_lte_tap_info *tap_info)
2096 guint64 framing_info;
2097 gboolean first_includes_start;
2098 gboolean last_includes_end;
2099 guint64 fixed_extension;
2101 gint start_offset = offset;
2103 proto_tree *um_header_tree;
2104 proto_item *um_header_ti;
2105 gboolean is_truncated = FALSE;
2106 proto_item *truncated_ti;
2107 rlc_channel_reassembly_info *reassembly_info = NULL;
2108 sequence_analysis_state seq_anal_state = SN_OK;
2110 /* Hidden UM root */
2111 um_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um,
2112 tvb, offset, 0, "", "UM");
2113 PROTO_ITEM_SET_HIDDEN(um_ti);
2115 /* Add UM header subtree */
2116 um_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um_header,
2119 um_header_tree = proto_item_add_subtree(um_header_ti,
2120 ett_rlc_lte_um_header);
2123 /*******************************/
2124 /* Fixed UM header */
2125 if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
2126 /* Framing info (2 bits) */
2127 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2129 &framing_info, ENC_BIG_ENDIAN);
2131 /* Extension (1 bit) */
2132 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2134 &fixed_extension, ENC_BIG_ENDIAN);
2136 /* Sequence Number (5 bit) */
2137 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2139 &sn, ENC_BIG_ENDIAN);
2142 else if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_10_BITS) {
2146 /* Check 3 Reserved bits */
2147 reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5;
2148 ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
2149 if (reserved != 0) {
2150 expert_add_info_format(pinfo, ti, &ei_rlc_lte_reserved_bits_not_zero,
2151 "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
2154 /* Framing info (2 bits) */
2155 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2156 tvb, (offset*8)+3, 2,
2157 &framing_info, ENC_BIG_ENDIAN);
2159 /* Extension (1 bit) */
2160 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2162 &fixed_extension, ENC_BIG_ENDIAN);
2164 /* Sequence Number (10 bits) */
2165 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2167 &sn, ENC_BIG_ENDIAN);
2171 /* Invalid length of sequence number */
2172 proto_tree_add_expert_format(um_header_tree, pinfo, &ei_rlc_lte_um_sn, tvb, 0, 0,
2173 "Invalid sequence number length (%u bits)",
2174 p_rlc_lte_info->sequenceNumberLength);
2178 tap_info->sequenceNumber = (guint16)sn;
2180 /* Show SN in info column */
2181 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2182 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (guint16)sn);
2185 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (guint16)sn);
2188 proto_item_set_len(um_header_ti, offset-start_offset);
2191 /*************************************/
2192 /* UM header extension */
2193 if (fixed_extension) {
2194 offset = dissect_rlc_lte_extension_header(tvb, pinfo, um_header_tree, offset, p_rlc_lte_info);
2197 /* Extract these 2 flags from framing_info */
2198 first_includes_start = ((guint8)framing_info & 0x02) == 0;
2199 last_includes_end = ((guint8)framing_info & 0x01) == 0;
2201 if (global_rlc_lte_headers_expected) {
2202 /* There might not be any data, if only headers (plus control data) were logged */
2203 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2204 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2208 PROTO_ITEM_SET_GENERATED(truncated_ti);
2209 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2211 /* Show in the info column how long the data would be */
2212 for (n=0; n < s_number_of_extensions; n++) {
2213 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2214 (n==0) ? first_includes_start : TRUE,
2216 offset += s_lengths[n];
2219 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2220 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2224 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2228 /* Show number of extensions in header root */
2229 if (s_number_of_extensions > 0) {
2230 proto_item_append_text(um_header_ti, " (%u extensions)", s_number_of_extensions);
2233 /* Call sequence analysis function now */
2234 if (((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2235 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2236 ((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2237 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2239 guint16 lastSegmentOffset = offset;
2240 if (s_number_of_extensions >= 1) {
2242 lastSegmentOffset = offset;
2243 for (n=0; n < s_number_of_extensions; n++) {
2244 lastSegmentOffset += s_lengths[n];
2248 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
2250 s_number_of_extensions+1,
2252 s_number_of_extensions ?
2254 p_rlc_lte_info->pduLength - offset,
2256 (guint16)sn, first_includes_start, last_includes_end,
2257 FALSE, /* UM doesn't re-segment */
2258 tap_info, um_header_tree);
2265 /*************************************/
2268 reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2269 get_report_hash_key((guint16)sn, pinfo->num,
2270 p_rlc_lte_info, FALSE));
2272 if (s_number_of_extensions > 0) {
2273 /* Show each data segment separately */
2275 for (n=0; n < s_number_of_extensions; n++) {
2276 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2277 (n==0) ? first_includes_start : TRUE,
2278 (n==0) ? reassembly_info : NULL,
2280 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2281 (n==0) ? first_includes_start : TRUE,
2283 /* Make sure we don't lose the summary of this SDU */
2284 col_append_str(pinfo->cinfo, COL_INFO, " | ");
2285 col_set_fence(pinfo->cinfo, COL_INFO);
2287 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2288 offset += s_lengths[n];
2292 /* Final data element */
2293 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2294 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2295 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2297 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_reported_length_remaining(tvb, offset),
2298 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2304 /* Dissect an AM STATUS PDU */
2305 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
2308 proto_item *status_ti,
2311 rlc_lte_info *p_rlc_lte_info,
2312 rlc_lte_tap_info *tap_info)
2314 guint8 cpt, sn_size, so_size;
2316 guint64 ack_sn, nack_sn;
2317 guint16 nack_count = 0, so_end_of_pdu;
2318 guint64 e1 = 0, e2 = 0;
2319 guint64 so_start, so_end;
2320 int bit_offset = offset * 8;
2323 /****************************************************************/
2324 /* Part of RLC control PDU header */
2326 /* Control PDU Type (CPT) */
2327 cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
2328 ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN);
2330 /* Protest and stop - only know about STATUS PDUs */
2331 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_cpt,
2332 "RLC Control frame type %u not handled", cpt);
2336 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2340 so_end_of_pdu = 0xffff;
2345 so_end_of_pdu = 0x7fff;
2348 /* The Status PDU itself starts 4 bits into the byte */
2352 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2353 bit_offset, sn_size, &ack_sn, ENC_BIG_ENDIAN);
2354 bit_offset += sn_size;
2355 write_pdu_label_and_info(top_ti, status_ti, pinfo, " ACK_SN=%-4u", (guint16)ack_sn);
2357 tap_info->ACKNo = (guint16)ack_sn;
2360 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2361 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2363 /* Skip another bit to byte-align the next bit... */
2366 /* Optional, extra fields */
2369 proto_item *nack_ti;
2371 /****************************/
2372 /* Read NACK_SN, E1, E2 */
2375 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
2376 bit_offset, sn_size, &nack_sn, ENC_BIG_ENDIAN);
2377 bit_offset += sn_size;
2378 write_pdu_label_and_info(top_ti, NULL, pinfo, " NACK_SN=%-4u", (guint16)nack_sn);
2380 /* We shouldn't NACK the ACK_SN! */
2381 if (nack_sn == ack_sn) {
2382 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ack_same,
2383 "Status PDU shouldn't ACK and NACK the same sequence number (%" G_GINT64_MODIFIER "u)",
2387 /* NACK should always be 'behind' the ACK */
2388 if ((sn_limit + ack_sn - nack_sn) % sn_limit > (sn_limit>>1)) {
2389 expert_add_info(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ahead_ack);
2392 /* Copy into struct, but don't exceed buffer */
2393 if (nack_count < MAX_NACKs) {
2394 tap_info->NACKs[nack_count++] = (guint16)nack_sn;
2397 /* Let it get bigger than the array for accurate stats... */
2402 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2403 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2407 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
2408 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
2410 /* Report as expert info */
2412 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_partial,
2413 "Status PDU reports NACK (partial) on %s for UE %u",
2414 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2415 p_rlc_lte_info->ueid);
2418 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn,
2419 "Status PDU reports NACK on %s for UE %u",
2420 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2421 p_rlc_lte_info->ueid);
2428 /* Read SOstart, SOend */
2429 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
2430 bit_offset, so_size, &so_start, ENC_BIG_ENDIAN);
2431 bit_offset += so_size;
2433 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
2434 bit_offset, so_size, &so_end, ENC_BIG_ENDIAN);
2435 bit_offset += so_size;
2438 if ((guint16)so_end == so_end_of_pdu) {
2439 write_pdu_label_and_info(top_ti, NULL, pinfo,
2440 " (SOstart=%u SOend=<END-OF_PDU>)",
2444 write_pdu_label_and_info(top_ti, NULL, pinfo,
2445 " (SOstart=%u SOend=%u)",
2446 (guint16)so_start, (guint16)so_end);
2449 /* Reset this flag here */
2454 if (nack_count > 0) {
2455 proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
2456 PROTO_ITEM_SET_GENERATED(count_ti);
2457 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
2458 tap_info->noOfNACKs = nack_count;
2461 /* Check that we've reached the end of the PDU. If not, show malformed */
2462 offset = (bit_offset+7) / 8;
2463 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2464 expert_add_info_format(pinfo, status_ti, &ei_rlc_lte_bytes_after_status_pdu_complete,
2465 "%cL %u bytes remaining after Status PDU complete",
2466 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2467 tvb_reported_length_remaining(tvb, offset));
2470 /* Set selected length of control tree */
2471 proto_item_set_len(status_ti, offset);
2473 /* Repeated NACK analysis & check ACK-SN is in range */
2474 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2475 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2476 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2477 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2479 if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2480 checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2481 checkChannelACKWindow((guint16)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2487 /***************************************************/
2488 /* Acknowledged mode PDU */
2489 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
2492 rlc_lte_info *p_rlc_lte_info,
2494 rlc_lte_tap_info *tap_info)
2497 guint8 is_resegmented;
2499 guint8 fixed_extension;
2500 guint8 framing_info;
2501 gboolean first_includes_start;
2502 gboolean last_includes_end;
2504 proto_tree *am_header_tree;
2505 proto_item *am_header_ti;
2506 gint start_offset = offset;
2508 gboolean is_truncated = FALSE;
2509 proto_item *truncated_ti;
2510 rlc_channel_reassembly_info *reassembly_info = NULL;
2511 sequence_analysis_state seq_anal_state = SN_OK;
2513 wmem_tree_key_t key[3];
2514 rlc_ue_parameters *params;
2516 /* Hidden AM root */
2517 am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2518 tvb, offset, 0, "", "AM");
2519 PROTO_ITEM_SET_HIDDEN(am_ti);
2521 /* Add AM header subtree */
2522 am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2525 am_header_tree = proto_item_add_subtree(am_header_ti,
2526 ett_rlc_lte_am_header);
2528 /* First bit is Data/Control flag */
2529 is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
2530 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN);
2531 tap_info->isControlPDU = !is_data;
2534 /**********************/
2536 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
2538 /* Control PDUs are a completely separate format */
2539 dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2541 p_rlc_lte_info, tap_info);
2545 /******************************/
2546 /* Data PDU fixed header */
2548 /* Re-segmentation Flag (RF) field */
2549 is_resegmented = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
2550 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, ENC_BIG_ENDIAN);
2551 tap_info->isResegmented = is_resegmented;
2553 write_pdu_label_and_info_literal(top_ti, NULL, pinfo,
2554 (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2557 polling = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
2558 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, ENC_BIG_ENDIAN);
2560 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : " ");
2562 proto_item_append_text(am_header_ti, " (P) ");
2566 framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3;
2567 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, ENC_BIG_ENDIAN);
2570 fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2;
2571 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, ENC_BIG_ENDIAN);
2573 /* Sequence Number */
2574 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2577 if (is_resegmented) {
2578 /* Last Segment Field (LSF) */
2579 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf16, tvb, offset, 1, ENC_BIG_ENDIAN);
2581 am_ti = proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN);
2582 reserved = tvb_get_guint8(tvb, offset) & 0x01;
2585 am_ti = proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
2586 reserved = tvb_get_guint8(tvb, offset) & 0x03;
2588 if (reserved != 0) {
2589 expert_add_info_format(pinfo, am_ti, &ei_rlc_lte_reserved_bits_not_zero,
2590 "RLC AM Fixed header Reserved bits not zero (found 0x%x)", reserved);
2593 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn16, tvb, offset, 2, ENC_BIG_ENDIAN);
2594 sn = tvb_get_ntohs(tvb, offset);
2597 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN);
2598 sn = tvb_get_ntohs(tvb, offset) & 0x03ff;
2601 tap_info->sequenceNumber = sn;
2603 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2605 /***************************************/
2606 /* Dissect extra segment header fields */
2607 if (is_resegmented) {
2608 guint16 segmentOffset;
2610 if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2612 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so16, tvb, offset, 2, ENC_BIG_ENDIAN);
2613 segmentOffset = tvb_get_ntohs(tvb, offset);
2615 /* Last Segment Field (LSF) */
2616 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2619 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN);
2620 segmentOffset = tvb_get_ntohs(tvb, offset) & 0x7fff;
2622 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2626 /*************************************/
2627 /* AM header extension */
2628 if (fixed_extension) {
2629 if (!PINFO_FD_VISITED(pinfo)) {
2630 id = (p_rlc_lte_info->channelId << 16) | p_rlc_lte_info->ueid;
2634 key[1].key = &pinfo->num;
2637 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
2638 if (params && (params->id == id)) {
2639 p_rlc_lte_info->extendedLiField = (p_rlc_lte_info->direction == DIRECTION_UPLINK) ?
2640 (params->ext_li_field & UL_EXT_LI): (params->ext_li_field & DL_EXT_LI);
2643 offset = dissect_rlc_lte_extension_header(tvb, pinfo, am_header_tree, offset, p_rlc_lte_info);
2646 /* Header is now complete */
2647 proto_item_set_len(am_header_ti, offset-start_offset);
2649 /* Show number of extensions in header root */
2650 if (s_number_of_extensions > 0) {
2651 proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2654 /* Extract these 2 flags from framing_info */
2655 first_includes_start = (framing_info & 0x02) == 0;
2656 last_includes_end = (framing_info & 0x01) == 0;
2658 /* There might not be any data, if only headers (plus control data) were logged */
2659 if (global_rlc_lte_headers_expected) {
2660 is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2661 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2665 PROTO_ITEM_SET_GENERATED(truncated_ti);
2666 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2667 /* Show in the info column how long the data would be */
2668 for (n=0; n < s_number_of_extensions; n++) {
2669 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2670 (n==0) ? first_includes_start : TRUE,
2672 offset += s_lengths[n];
2675 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2676 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2680 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2684 /* Call sequence analysis function now */
2685 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2686 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2687 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2688 (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2690 guint16 firstSegmentLength;
2691 guint16 lastSegmentOffset = offset;
2692 if (s_number_of_extensions >= 1) {
2694 for (n=0; n < s_number_of_extensions; n++) {
2695 lastSegmentOffset += s_lengths[n];
2698 firstSegmentLength = s_lengths[0];
2701 firstSegmentLength = tvb_reported_length_remaining(tvb, offset);
2704 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, FALSE,
2705 s_number_of_extensions+1,
2706 offset, firstSegmentLength,
2709 first_includes_start, last_includes_end,
2710 is_resegmented, tap_info, tree);
2717 /*************************************/
2720 if (!first_includes_start) {
2721 reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2722 get_report_hash_key((guint16)sn,
2728 if (s_number_of_extensions > 0) {
2729 /* Show each data segment separately */
2731 for (n=0; n < s_number_of_extensions; n++) {
2732 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2733 (n==0) ? first_includes_start : TRUE,
2734 (n==0) ? reassembly_info : NULL,
2736 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2737 (n==0) ? first_includes_start : TRUE,
2739 /* Make sure we don't lose the summary of this SDU */
2740 col_append_str(pinfo->cinfo, COL_INFO, " | ");
2741 col_set_fence(pinfo->cinfo, COL_INFO);
2743 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2744 offset += s_lengths[n];
2748 /* Final data element */
2749 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2750 show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2751 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2752 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2754 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_reported_length_remaining(tvb, offset),
2755 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2759 /* Report that expected data was missing (unless we know it might happen) */
2760 if (!global_rlc_lte_headers_expected) {
2761 if (s_number_of_extensions > 0) {
2762 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data_beyond_extensions);
2765 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data);
2771 static void report_heur_error(proto_tree *tree, packet_info *pinfo, expert_field *eiindex,
2772 tvbuff_t *tvb, gint start, gint length)
2775 proto_tree *subtree;
2777 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2778 col_clear(pinfo->cinfo, COL_INFO);
2779 ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, 0, -1, ENC_NA);
2780 subtree = proto_item_add_subtree(ti, ett_rlc_lte);
2781 proto_tree_add_expert(subtree, pinfo, eiindex, tvb, start, length);
2784 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2785 static gboolean dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
2786 proto_tree *tree, void *data _U_)
2789 struct rlc_lte_info *p_rlc_lte_info;
2792 gboolean seqNumLengthTagPresent = FALSE;
2794 /* Needs to be at least as long as:
2795 - the signature string
2796 - fixed header bytes
2798 - at least one byte of RLC PDU payload */
2799 if (tvb_captured_length_remaining(tvb, offset) < (gint)(strlen(RLC_LTE_START_STRING)+1+2)) {
2803 /* OK, compare with signature string */
2804 if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (gint)strlen(RLC_LTE_START_STRING)) != 0) {
2807 offset += (gint)strlen(RLC_LTE_START_STRING);
2810 /* If redissecting, use previous info struct (if available) */
2811 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2812 if (p_rlc_lte_info == NULL) {
2813 /* Allocate new info struct for this frame */
2814 p_rlc_lte_info = wmem_new0(wmem_file_scope(), struct rlc_lte_info);
2816 /* Read fixed fields */
2817 p_rlc_lte_info->rlcMode = tvb_get_guint8(tvb, offset++);
2818 if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2819 p_rlc_lte_info->sequenceNumberLength = AM_SN_LENGTH_10_BITS;
2822 /* Read optional fields */
2823 while (tag != RLC_LTE_PAYLOAD_TAG) {
2824 /* Process next tag */
2825 tag = tvb_get_guint8(tvb, offset++);
2827 case RLC_LTE_SN_LENGTH_TAG:
2828 p_rlc_lte_info->sequenceNumberLength = tvb_get_guint8(tvb, offset);
2830 seqNumLengthTagPresent = TRUE;
2832 case RLC_LTE_DIRECTION_TAG:
2833 p_rlc_lte_info->direction = tvb_get_guint8(tvb, offset);
2836 case RLC_LTE_PRIORITY_TAG:
2837 p_rlc_lte_info->priority = tvb_get_guint8(tvb, offset);
2840 case RLC_LTE_UEID_TAG:
2841 p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
2844 case RLC_LTE_CHANNEL_TYPE_TAG:
2845 p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
2848 case RLC_LTE_CHANNEL_ID_TAG:
2849 p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
2852 case RLC_LTE_EXT_LI_FIELD_TAG:
2853 p_rlc_lte_info->extendedLiField = TRUE;
2855 case RLC_LTE_NB_MODE_TAG:
2856 p_rlc_lte_info->nbMode =
2857 (rlc_lte_nb_mode)tvb_get_guint8(tvb, offset);
2861 case RLC_LTE_PAYLOAD_TAG:
2862 /* Have reached data, so set payload length and get out of loop */
2863 p_rlc_lte_info->pduLength = tvb_reported_length_remaining(tvb, offset);
2867 /* It must be a recognised tag */
2868 report_heur_error(tree, pinfo, &ei_rlc_lte_unknown_udp_framing_tag, tvb, offset-1, 1);
2869 wmem_free(wmem_file_scope(), p_rlc_lte_info);
2874 if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (seqNumLengthTagPresent == FALSE)) {
2875 /* Conditional field is not present */
2876 report_heur_error(tree, pinfo, &ei_rlc_lte_missing_udp_framing_tag, tvb, 0, offset);
2877 wmem_free(wmem_file_scope(), p_rlc_lte_info);
2881 /* Store info in packet */
2882 p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0, p_rlc_lte_info);
2885 offset = tvb_reported_length(tvb) - p_rlc_lte_info->pduLength;
2888 /**************************************/
2889 /* OK, now dissect as RLC LTE */
2891 /* Create tvb that starts at actual RLC PDU */
2892 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
2893 dissect_rlc_lte_common(rlc_tvb, pinfo, tree, TRUE);
2899 /*****************************/
2900 /* Main dissection function. */
2901 /*****************************/
2903 static int dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2905 dissect_rlc_lte_common(tvb, pinfo, tree, FALSE);
2906 return tvb_captured_length(tvb);
2909 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing)
2911 proto_tree *rlc_lte_tree;
2912 proto_tree *context_tree;
2914 proto_item *context_ti;
2916 proto_item *mode_ti;
2918 struct rlc_lte_info *p_rlc_lte_info = NULL;
2920 /* Allocate and Zero tap struct */
2921 rlc_lte_tap_info *tap_info = wmem_new0(wmem_packet_scope(), rlc_lte_tap_info);
2923 /* Set protocol name */
2924 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2926 /* Create protocol tree. */
2927 top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2928 rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2931 /* Look for packet info! */
2932 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2934 /* Can't dissect anything without it... */
2935 if (p_rlc_lte_info == NULL) {
2936 proto_tree_add_expert(rlc_lte_tree, pinfo, &ei_rlc_lte_no_per_frame_info, tvb, offset, -1);
2940 /* Clear info column when using UDP framing */
2941 if (is_udp_framing) {
2942 col_clear(pinfo->cinfo, COL_INFO);
2945 /*****************************************/
2946 /* Show context information */
2948 /* Create context root */
2949 context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2950 tvb, offset, 0, "", "Context");
2951 context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2952 PROTO_ITEM_SET_GENERATED(context_ti);
2954 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2955 tvb, 0, 0, p_rlc_lte_info->direction);
2956 PROTO_ITEM_SET_GENERATED(ti);
2958 mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2959 tvb, 0, 0, p_rlc_lte_info->rlcMode);
2960 PROTO_ITEM_SET_GENERATED(mode_ti);
2962 if (p_rlc_lte_info->ueid != 0) {
2963 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_ueid,
2964 tvb, 0, 0, p_rlc_lte_info->ueid);
2965 PROTO_ITEM_SET_GENERATED(ti);
2968 if ((p_rlc_lte_info->priority >= 1) && (p_rlc_lte_info->priority <=16)) {
2969 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_priority,
2970 tvb, 0, 0, p_rlc_lte_info->priority);
2971 PROTO_ITEM_SET_GENERATED(ti);
2974 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2975 tvb, 0, 0, p_rlc_lte_info->channelType);
2976 PROTO_ITEM_SET_GENERATED(ti);
2978 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2979 (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB) ||
2980 (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2981 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2982 tvb, 0, 0, p_rlc_lte_info->channelId);
2983 PROTO_ITEM_SET_GENERATED(ti);
2986 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2987 tvb, 0, 0, p_rlc_lte_info->pduLength);
2988 PROTO_ITEM_SET_GENERATED(ti);
2990 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
2991 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_um_sn_length,
2992 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2993 PROTO_ITEM_SET_GENERATED(ti);
2996 if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2997 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_am_sn_length,
2998 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength ?
2999 p_rlc_lte_info->sequenceNumberLength : 10);
3000 PROTO_ITEM_SET_GENERATED(ti);
3003 /* Append highlights to top-level item */
3004 if (p_rlc_lte_info->ueid != 0) {
3005 proto_item_append_text(top_ti, " UEId=%u", p_rlc_lte_info->ueid);
3006 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%-4u ", p_rlc_lte_info->ueid);
3009 /* Append context highlights to info column */
3010 write_pdu_label_and_info(top_ti, NULL, pinfo,
3012 (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
3013 val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
3015 if (p_rlc_lte_info->channelId == 0) {
3016 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s ",
3017 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
3020 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
3021 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
3022 p_rlc_lte_info->channelId);
3025 /* Set context-info parts of tap struct */
3026 tap_info->rlcMode = p_rlc_lte_info->rlcMode;
3027 tap_info->direction = p_rlc_lte_info->direction;
3028 tap_info->priority = p_rlc_lte_info->priority;
3029 tap_info->ueid = p_rlc_lte_info->ueid;
3030 tap_info->channelType = p_rlc_lte_info->channelType;
3031 tap_info->channelId = p_rlc_lte_info->channelId;
3032 tap_info->pduLength = p_rlc_lte_info->pduLength;
3033 tap_info->sequenceNumberLength = p_rlc_lte_info->sequenceNumberLength;
3034 tap_info->loggedInMACFrame = (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL);
3036 tap_info->rlc_lte_time = pinfo->abs_ts;
3038 /* Reset this count */
3039 s_number_of_extensions = 0;
3041 /* Dissect the RLC PDU itself. Format depends upon mode... */
3042 switch (p_rlc_lte_info->rlcMode) {
3045 dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
3049 dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3054 dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3059 /* Predefined data (i.e. not containing a valid RLC header */
3060 proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, ENC_NA);
3061 write_pdu_label_and_info(top_ti, NULL, pinfo, " [%u-bytes]",
3062 tvb_reported_length_remaining(tvb, offset));
3066 /* Error - unrecognised mode */
3067 expert_add_info_format(pinfo, mode_ti, &ei_rlc_lte_context_mode,
3068 "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
3072 /* Queue tap info */
3073 tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
3078 /* Configure number of PDCP SN bits to use for DRB channels */
3079 void set_rlc_lte_drb_pdcp_seqnum_length(packet_info *pinfo, guint16 ueid, guint8 drbid,
3080 guint8 userplane_seqnum_length)
3082 wmem_tree_key_t key[3];
3084 rlc_ue_parameters *params;
3086 if (PINFO_FD_VISITED(pinfo)) {
3090 id = (drbid << 16) | ueid;
3094 key[1].key = &pinfo->num;
3098 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3099 if (params && (params->id != id)) {
3102 if (params == NULL) {
3103 params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3105 params->ext_li_field = NO_EXT_LI;
3106 wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3108 params->pdcp_sn_bits = userplane_seqnum_length;
3111 /*Configure LI field for AM DRB channels */
3112 void set_rlc_lte_drb_li_field(packet_info *pinfo, guint16 ueid, guint8 drbid,
3113 gboolean ul_ext_li_field, gboolean dl_ext_li_field)
3115 wmem_tree_key_t key[3];
3117 rlc_ue_parameters *params;
3119 if (PINFO_FD_VISITED(pinfo)) {
3123 id = (drbid << 16) | ueid;
3127 key[1].key = &pinfo->num;
3131 params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3132 if (params && (params->id != id)) {
3135 if (params == NULL) {
3136 params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3138 params->pdcp_sn_bits = 12;
3139 wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3141 params->ext_li_field = ul_ext_li_field ? UL_EXT_LI : NO_EXT_LI;
3142 params->ext_li_field |= dl_ext_li_field ? DL_EXT_LI : NO_EXT_LI;
3145 void proto_register_rlc_lte(void)
3147 static hf_register_info hf[] =
3149 /**********************************/
3150 /* Items for decoding context */
3151 { &hf_rlc_lte_context,
3153 "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
3157 { &hf_rlc_lte_context_mode,
3159 "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
3163 { &hf_rlc_lte_context_direction,
3165 "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
3166 "Direction of message", HFILL
3169 { &hf_rlc_lte_context_priority,
3171 "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
3175 { &hf_rlc_lte_context_ueid,
3177 "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
3178 "User Equipment Identifier associated with message", HFILL
3181 { &hf_rlc_lte_context_channel_type,
3183 "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
3184 "Channel Type associated with message", HFILL
3187 { &hf_rlc_lte_context_channel_id,
3189 "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
3190 "Channel ID associated with message", HFILL
3193 { &hf_rlc_lte_context_pdu_length,
3195 "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
3196 "Length of PDU (in bytes)", HFILL
3199 { &hf_rlc_lte_context_um_sn_length,
3200 { "UM Sequence number length",
3201 "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3202 "Length of UM sequence number in bits", HFILL
3205 { &hf_rlc_lte_context_am_sn_length,
3206 { "AM Sequence number length",
3207 "rlc-lte.am-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3208 "Length of AM sequence number in bits", HFILL
3212 /* Transparent mode fields */
3215 "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
3216 "Transparent Mode", HFILL
3219 { &hf_rlc_lte_tm_data,
3221 "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
3222 "Transparent Mode Data", HFILL
3226 /* Unacknowledged mode fields */
3229 "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
3230 "Unacknowledged Mode", HFILL
3233 { &hf_rlc_lte_um_header,
3235 "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
3236 "Unacknowledged Mode Header", HFILL
3239 { &hf_rlc_lte_um_fi,
3241 "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
3245 { &hf_rlc_lte_um_fixed_e,
3247 "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
3248 "Extension in fixed part of UM header", HFILL
3251 { &hf_rlc_lte_um_sn,
3252 { "Sequence number",
3253 "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
3254 "Unacknowledged Mode Sequence Number", HFILL
3257 { &hf_rlc_lte_um_fixed_reserved,
3259 "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
3260 "Unacknowledged Mode Fixed header reserved bits", HFILL
3263 { &hf_rlc_lte_um_data,
3265 "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
3266 "Unacknowledged Mode Data", HFILL
3269 { &hf_rlc_lte_extension_part,
3271 "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
3275 { &hf_rlc_lte_extension_e,
3277 "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
3278 "Extension in extended part of the header", HFILL
3281 { &hf_rlc_lte_extension_li,
3282 { "Length Indicator",
3283 "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
3287 { &hf_rlc_lte_extension_padding,
3289 "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
3290 "Extension header padding", HFILL
3294 /* Acknowledged mode fields */
3297 "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
3298 "Acknowledged Mode", HFILL
3301 { &hf_rlc_lte_am_header,
3303 "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
3304 "Acknowledged Mode Header", HFILL
3307 { &hf_rlc_lte_am_data_control,
3309 "rlc-lte.am.frame-type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80,
3310 "AM Frame Type (Control or Data)", HFILL
3313 { &hf_rlc_lte_am_rf,
3314 { "Re-segmentation Flag",
3315 "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
3316 "AM Re-segmentation Flag", HFILL
3321 "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
3325 { &hf_rlc_lte_am_fi,
3327 "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
3328 "AM Framing Info", HFILL
3331 { &hf_rlc_lte_am_fixed_e,
3333 "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
3334 "Fixed Extension Bit", HFILL
3337 { &hf_rlc_lte_am_fixed_sn,
3338 { "Sequence Number",
3339 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
3340 "AM Fixed Sequence Number", HFILL
3343 { &hf_rlc_lte_am_fixed_reserved,
3345 "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x03,
3346 "Acknowledged Mode Fixed header reserved bits", HFILL
3349 { &hf_rlc_lte_am_segment_lsf16,
3350 { "Last Segment Flag",
3351 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x02,
3355 { &hf_rlc_lte_am_fixed_reserved2,
3357 "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x01,
3358 "Acknowledged Mode Fixed header reserved bit", HFILL
3361 { &hf_rlc_lte_am_fixed_sn16,
3362 { "Sequence Number",
3363 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0xffff,
3364 "AM Fixed Sequence Number", HFILL
3367 { &hf_rlc_lte_am_segment_lsf,
3368 { "Last Segment Flag",
3369 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3373 { &hf_rlc_lte_am_segment_so,
3375 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3379 { &hf_rlc_lte_am_segment_so16,
3381 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0xffff,
3385 { &hf_rlc_lte_am_data,
3387 "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3388 "Acknowledged Mode Data", HFILL
3392 { &hf_rlc_lte_am_cpt,
3393 { "Control PDU Type",
3394 "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3395 "AM Control PDU Type", HFILL
3398 { &hf_rlc_lte_am_ack_sn,
3399 { "ACK Sequence Number",
3400 "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3401 "Sequence Number we expect to receive next", HFILL
3404 { &hf_rlc_lte_am_e1,
3405 { "Extension bit 1",
3406 "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3410 { &hf_rlc_lte_am_e2,
3411 { "Extension bit 2",
3412 "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3416 { &hf_rlc_lte_am_nacks,
3417 { "Number of NACKs",
3418 "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3419 "Number of NACKs in this status PDU", HFILL
3422 { &hf_rlc_lte_am_nack_sn,
3423 { "NACK Sequence Number",
3424 "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3425 "Negative Acknowledgement Sequence Number", HFILL
3428 { &hf_rlc_lte_am_so_start,
3430 "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3431 "Segment Offset Start byte index", HFILL
3434 { &hf_rlc_lte_am_so_end,
3436 "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3437 "Segment Offset End byte index", HFILL
3441 { &hf_rlc_lte_predefined_pdu,
3442 { "Predefined data",
3443 "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3444 "Predefined test data", HFILL
3448 /* Sequence analysis fields */
3449 { &hf_rlc_lte_sequence_analysis,
3450 { "Sequence Analysis",
3451 "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3455 { &hf_rlc_lte_sequence_analysis_ok,
3457 "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3461 { &hf_rlc_lte_sequence_analysis_previous_frame,
3462 { "Previous frame for channel",
3463 "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3467 { &hf_rlc_lte_sequence_analysis_next_frame,
3468 { "Next frame for channel",
3469 "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3473 { &hf_rlc_lte_sequence_analysis_expected_sn,
3475 "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3479 { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3480 { "Frame info continued correctly",
3481 "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3485 { &hf_rlc_lte_sequence_analysis_mac_retx,
3486 { "Frame retransmitted by MAC",
3487 "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3491 { &hf_rlc_lte_sequence_analysis_retx,
3492 { "Retransmitted frame",
3493 "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3497 { &hf_rlc_lte_sequence_analysis_skipped,
3499 "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3503 { &hf_rlc_lte_sequence_analysis_repeated,
3505 "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3509 { &hf_rlc_lte_sequence_analysis_repeated_nack,
3511 "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3515 { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3516 { "Frame with previous status PDU",
3517 "rlc-lte.sequence-analysis.repeated-nack.original-frame", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_DUP_ACK), 0x0,
3522 { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3523 { "Out of range ACK",
3524 "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3528 { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3529 { "Frame with most recent SN",
3530 "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3535 /* Reassembly fields */
3536 { &hf_rlc_lte_reassembly_source,
3537 { "Reassembly Source",
3538 "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3542 { &hf_rlc_lte_reassembly_source_number_of_segments,
3543 { "Number of segments",
3544 "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3548 { &hf_rlc_lte_reassembly_source_total_length,
3550 "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3554 { &hf_rlc_lte_reassembly_source_segment,
3556 "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3560 { &hf_rlc_lte_reassembly_source_segment_sn,
3562 "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3566 { &hf_rlc_lte_reassembly_source_segment_framenum,
3568 "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3572 { &hf_rlc_lte_reassembly_source_segment_length,
3574 "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3579 { &hf_rlc_lte_header_only,
3580 { "RLC PDU Header only",
3581 "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3587 static gint *ett[] =
3590 &ett_rlc_lte_context,
3591 &ett_rlc_lte_um_header,
3592 &ett_rlc_lte_am_header,
3593 &ett_rlc_lte_extension_part,
3594 &ett_rlc_lte_sequence_analysis,
3595 &ett_rlc_lte_reassembly_source,
3596 &ett_rlc_lte_reassembly_source_segment
3599 static ei_register_info ei[] = {
3600 { &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 }},
3601 { &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 }},
3602 { &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 }},
3603 { &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 }},
3604 { &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 }},
3605 { &ei_rlc_lte_am_sn_missing, { "rlc-lte.sequence-analysis.am-sn.missing", PI_SEQUENCE, PI_WARN, "AM SNs missing", EXPFILL }},
3606 { &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 }},
3607 { &ei_rlc_lte_um_sn_missing, { "rlc-lte.sequence-analysis.um-sn.missing", PI_SEQUENCE, PI_WARN, "UM SNs missing", EXPFILL }},
3608 { &ei_rlc_lte_um_sn_repeated, { "rlc-lte.sequence-analysis.um-sn.repeated", PI_SEQUENCE, PI_WARN, "UM SN repeated", EXPFILL }},
3609 { &ei_rlc_lte_wrong_sequence_number, { "rlc-lte.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
3610 { &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 }},
3611 { &ei_rlc_lte_reserved_bits_not_zero, { "rlc-lte.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
3612 { &ei_rlc_lte_um_sn, { "rlc-lte.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
3613 { &ei_rlc_lte_header_only, { "rlc-lte.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3614 { &ei_rlc_lte_am_cpt, { "rlc-lte.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
3615 { &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 }},
3616 { &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 }},
3617 { &ei_rlc_lte_am_nack_sn_partial, { "rlc-lte.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
3618 { &ei_rlc_lte_am_nack_sn, { "rlc-lte.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
3619 { &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 }},
3620 { &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 }},
3621 { &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 }},
3622 { &ei_rlc_lte_context_mode, { "rlc-lte.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
3623 { &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 }},
3624 { &ei_rlc_lte_unknown_udp_framing_tag, { "rlc-lte.unknown-udp-framing-tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }},
3625 { &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 }}
3628 static const enum_val_t sequence_analysis_vals[] = {
3629 {"no-analysis", "No-Analysis", FALSE},
3630 {"mac-only", "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3631 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3635 module_t *rlc_lte_module;
3636 expert_module_t* expert_rlc_lte;
3638 /* Register protocol. */
3639 proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3640 proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3641 proto_register_subtree_array(ett, array_length(ett));
3642 expert_rlc_lte = expert_register_protocol(proto_rlc_lte);
3643 expert_register_field_array(expert_rlc_lte, ei, array_length(ei));
3645 /* Allow other dissectors to find this one by name. */
3646 register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3648 /* Register the tap name */
3649 rlc_lte_tap = register_tap("rlc-lte");
3652 rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3654 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3655 "Do sequence analysis for AM channels",
3656 "Attempt to keep track of PDUs for AM channels, and point out problems",
3657 &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, FALSE);
3659 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3660 "Do sequence analysis for UM channels",
3661 "Attempt to keep track of PDUs for UM channels, and point out problems",
3662 &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, FALSE);
3664 prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3665 "Call PDCP dissector for SRB PDUs",
3666 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
3667 "only be called for complete PDUs (i.e. not segmented over RLC)",
3668 &global_rlc_lte_call_pdcp_for_srb);
3670 prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3671 "Call PDCP dissector for DRB PDUs",
3672 "Call PDCP dissector for user-plane PDUs. Note that without reassembly, it can"
3673 "only be called for complete PDUs (i.e. not segmented over RLC)",
3674 &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, FALSE);
3677 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3678 "Call RRC dissector for CCCH PDUs",
3679 "Call RRC dissector for CCCH PDUs",
3680 &global_rlc_lte_call_rrc_for_ccch);
3682 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_mcch",
3683 "Call RRC dissector for MCCH PDUs",
3684 "Call RRC dissector for MCCH PDUs Note that without reassembly, it can"
3685 "only be called for complete PDUs (i.e. not segmented over RLC)",
3686 &global_rlc_lte_call_rrc_for_mcch);
3688 prefs_register_bool_preference(rlc_lte_module, "call_ip_for_mtch",
3689 "Call IP dissector for MTCH PDUs",
3690 "Call ip dissector for MTCH PDUs Note that without reassembly, it can"
3691 "only be called for complete PDUs (i.e. not segmented over RLC)",
3692 &global_rlc_lte_call_ip_for_mtch);
3694 prefs_register_obsolete_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp");
3696 prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3697 "May see RLC headers only",
3698 "When enabled, if data is not present, don't report as an error, but instead "
3699 "add expert info to indicate that headers were omitted",
3700 &global_rlc_lte_headers_expected);
3702 prefs_register_bool_preference(rlc_lte_module, "reassembly",
3703 "Attempt SDU reassembly",
3704 "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3705 "more than one RLC PDU. Note: does not currently support out-of-order or "
3706 "re-segmentation. N.B. sequence analysis must also be turned on in order "
3707 "for reassembly to work",
3708 &global_rlc_lte_reassembly);
3710 ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3712 sequence_analysis_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3713 sequence_analysis_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3714 repeated_nack_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3715 repeated_nack_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3716 reassembly_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3719 void proto_reg_handoff_rlc_lte(void)
3721 /* Add as a heuristic UDP dissector */
3722 heur_dissector_add("udp", dissect_rlc_lte_heur, "RLC-LTE over UDP", "rlc_lte_udp", proto_rlc_lte, HEURISTIC_DISABLE);
3724 pdcp_lte_handle = find_dissector_add_dependency("pdcp-lte", proto_rlc_lte);
3725 ip_handle = find_dissector_add_dependency("ip", proto_rlc_lte);
3726 lte_rrc_mcch = find_dissector_add_dependency("lte_rrc.mcch", proto_rlc_lte);
3727 lte_rrc_ul_ccch = find_dissector_add_dependency("lte_rrc.ul_ccch", proto_rlc_lte);
3728 lte_rrc_dl_ccch = find_dissector_add_dependency("lte_rrc.dl_dcch", proto_rlc_lte);
3729 lte_rrc_bcch_bch = find_dissector_add_dependency("lte_rrc.bcch_bch", proto_rlc_lte);
3730 lte_rrc_bcch_dl_sch = find_dissector_add_dependency("lte_rrc.bcch_dl_sch", proto_rlc_lte);
3731 lte_rrc_pcch = find_dissector_add_dependency("lte_rrc.pcch", proto_rlc_lte);
3732 lte_rrc_ul_ccch_nb = find_dissector_add_dependency("lte_rrc.ul_ccch.nb", proto_rlc_lte);
3733 lte_rrc_dl_ccch_nb = find_dissector_add_dependency("lte_rrc.dl_ccch.nb", proto_rlc_lte);
3734 lte_rrc_bcch_bch_nb = find_dissector_add_dependency("lte_rrc.bcch_bch.nb", proto_rlc_lte);
3735 lte_rrc_bcch_dl_sch_nb = find_dissector_add_dependency("lte_rrc.bcch_dl_sch.nb", proto_rlc_lte);
3736 lte_rrc_pcch_nb = find_dissector_add_dependency("lte_rrc.pcch.nb", proto_rlc_lte);
3740 * Editor modelines - http://www.wireshark.org/tools/modelines.html
3745 * indent-tabs-mode: nil
3748 * vi: set shiftwidth=4 tabstop=8 expandtab:
3749 * :indentSize=4:tabSize=8:noTabs=true: