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