FIXUP: WIP: verification_trailer
[wireshark-wip.git] / epan / dissectors / packet-rlc-lte.c
blob29533de8588c5f747062c9105c6d5201e9e0c660
1 /* Routines for LTE RLC disassembly
3 * Martin Mathieson
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <string.h>
30 #include <epan/packet.h>
31 #include <epan/exceptions.h>
32 #include <epan/conversation.h>
33 #include <epan/expert.h>
34 #include <epan/prefs.h>
35 #include <epan/tap.h>
36 #include <epan/wmem/wmem.h>
38 #include "packet-mac-lte.h"
39 #include "packet-rlc-lte.h"
40 #include "packet-pdcp-lte.h"
43 /* Described in:
44 * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA)
45 * Radio Link Control (RLC) Protocol specification v9.3.0
48 /* TODO:
49 - add intermediate results to segments leading to final reassembly
50 - use multiple active rlc_channel_reassembly_info's per channel
51 - sequence analysis gets confused when we change cells and skip back
52 to SN 0. Maybe add cell-id to context and add to channel/result key?
55 /********************************/
56 /* Preference settings */
58 #define SEQUENCE_ANALYSIS_MAC_ONLY 1
59 #define SEQUENCE_ANALYSIS_RLC_ONLY 2
61 /* By default do try to analyse the sequence of messages for AM/UM channels
62 using MAC PDUs */
63 static gint global_rlc_lte_am_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
64 static gint global_rlc_lte_um_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
66 /* By default do call PDCP/RRC dissectors for SDU data */
67 static gboolean global_rlc_lte_call_pdcp_for_srb = TRUE;
69 enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12, PDCP_drb_SN_signalled, PDCP_drb_SN_15};
70 static const enum_val_t pdcp_drb_col_vals[] = {
71 {"pdcp-drb-off", "Off", PDCP_drb_off},
72 {"pdcp-drb-sn-7", "7-bit SN", PDCP_drb_SN_7},
73 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
74 {"pdcp-drb-sn-15", "15-bit SN", PDCP_drb_SN_15},
75 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
76 {NULL, NULL, -1}
78 static gint global_rlc_lte_call_pdcp_for_drb = (gint)PDCP_drb_SN_12;
79 static gint signalled_pdcp_sn_bits = 12;
81 static gboolean global_rlc_lte_call_rrc_for_ccch = TRUE;
82 static gboolean global_rlc_lte_call_rrc_for_mcch = FALSE;
83 static gboolean global_rlc_lte_call_ip_for_mtch = FALSE;
85 /* Preference to expect RLC headers without payloads */
86 static gboolean global_rlc_lte_headers_expected = FALSE;
88 /* Heuristic dissection */
89 static gboolean global_rlc_lte_heur = FALSE;
91 /* Re-assembly of segments */
92 static gboolean global_rlc_lte_reassembly = TRUE;
94 /**************************************************/
95 /* Initialize the protocol and registered fields. */
96 int proto_rlc_lte = -1;
98 extern int proto_mac_lte;
99 extern int proto_pdcp_lte;
101 static dissector_handle_t pdcp_lte_handle;
102 static dissector_handle_t ip_handle;
104 static int rlc_lte_tap = -1;
106 /* Decoding context */
107 static int hf_rlc_lte_context = -1;
108 static int hf_rlc_lte_context_mode = -1;
109 static int hf_rlc_lte_context_direction = -1;
110 static int hf_rlc_lte_context_priority = -1;
111 static int hf_rlc_lte_context_ueid = -1;
112 static int hf_rlc_lte_context_channel_type = -1;
113 static int hf_rlc_lte_context_channel_id = -1;
114 static int hf_rlc_lte_context_pdu_length = -1;
115 static int hf_rlc_lte_context_um_sn_length = -1;
117 /* Transparent mode fields */
118 static int hf_rlc_lte_tm = -1;
119 static int hf_rlc_lte_tm_data = -1;
121 /* Unacknowledged mode fields */
122 static int hf_rlc_lte_um = -1;
123 static int hf_rlc_lte_um_header = -1;
124 static int hf_rlc_lte_um_fi = -1;
125 static int hf_rlc_lte_um_fixed_e = -1;
126 static int hf_rlc_lte_um_sn = -1;
127 static int hf_rlc_lte_um_fixed_reserved = -1;
128 static int hf_rlc_lte_um_data = -1;
129 static int hf_rlc_lte_extension_part = -1;
131 /* Extended header (common to UM and AM) */
132 static int hf_rlc_lte_extension_e = -1;
133 static int hf_rlc_lte_extension_li = -1;
134 static int hf_rlc_lte_extension_padding = -1;
137 /* Acknowledged mode fields */
138 static int hf_rlc_lte_am = -1;
139 static int hf_rlc_lte_am_header = -1;
140 static int hf_rlc_lte_am_data_control = -1;
141 static int hf_rlc_lte_am_rf = -1;
142 static int hf_rlc_lte_am_p = -1;
143 static int hf_rlc_lte_am_fi = -1;
144 static int hf_rlc_lte_am_fixed_e = -1;
145 static int hf_rlc_lte_am_fixed_sn = -1;
146 static int hf_rlc_lte_am_segment_lsf = -1;
147 static int hf_rlc_lte_am_segment_so = -1;
148 static int hf_rlc_lte_am_data = -1;
150 /* Control fields */
151 static int hf_rlc_lte_am_cpt = -1;
152 static int hf_rlc_lte_am_ack_sn = -1;
153 static int hf_rlc_lte_am_e1 = -1;
154 static int hf_rlc_lte_am_e2 = -1;
155 static int hf_rlc_lte_am_nack_sn = -1;
156 static int hf_rlc_lte_am_nacks = -1;
157 static int hf_rlc_lte_am_so_start = -1;
158 static int hf_rlc_lte_am_so_end = -1;
160 static int hf_rlc_lte_predefined_pdu = -1;
161 static int hf_rlc_lte_header_only = -1;
163 /* Sequence Analysis */
164 static int hf_rlc_lte_sequence_analysis = -1;
165 static int hf_rlc_lte_sequence_analysis_ok = -1;
166 static int hf_rlc_lte_sequence_analysis_previous_frame = -1;
167 static int hf_rlc_lte_sequence_analysis_next_frame = -1;
168 static int hf_rlc_lte_sequence_analysis_expected_sn = -1;
169 static int hf_rlc_lte_sequence_analysis_framing_info_correct = -1;
171 static int hf_rlc_lte_sequence_analysis_mac_retx = -1;
172 static int hf_rlc_lte_sequence_analysis_retx = -1;
173 static int hf_rlc_lte_sequence_analysis_repeated = -1;
174 static int hf_rlc_lte_sequence_analysis_skipped = -1;
176 static int hf_rlc_lte_sequence_analysis_repeated_nack = -1;
177 static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame = -1;
179 static int hf_rlc_lte_sequence_analysis_ack_out_of_range = -1;
180 static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = -1;
182 /* Reassembly */
183 static int hf_rlc_lte_reassembly_source = -1;
184 static int hf_rlc_lte_reassembly_source_number_of_segments = -1;
185 static int hf_rlc_lte_reassembly_source_total_length = -1;
186 static int hf_rlc_lte_reassembly_source_segment = -1;
187 static int hf_rlc_lte_reassembly_source_segment_sn = -1;
188 static int hf_rlc_lte_reassembly_source_segment_framenum = -1;
189 static int hf_rlc_lte_reassembly_source_segment_length = -1;
191 /* Subtrees. */
192 static int ett_rlc_lte = -1;
193 static int ett_rlc_lte_context = -1;
194 static int ett_rlc_lte_um_header = -1;
195 static int ett_rlc_lte_am_header = -1;
196 static int ett_rlc_lte_extension_part = -1;
197 static int ett_rlc_lte_sequence_analysis = -1;
198 static int ett_rlc_lte_reassembly_source = -1;
199 static int ett_rlc_lte_reassembly_source_segment = -1;
201 static expert_field ei_rlc_lte_context_mode = EI_INIT;
202 static expert_field ei_rlc_lte_am_nack_sn = EI_INIT;
203 static expert_field ei_rlc_lte_am_nack_sn_ahead_ack = EI_INIT;
204 static expert_field ei_rlc_lte_um_sn_repeated = EI_INIT;
205 static expert_field ei_rlc_lte_am_nack_sn_ack_same = EI_INIT;
206 static expert_field ei_rlc_lte_am_cpt = EI_INIT;
207 static expert_field ei_rlc_lte_am_data_no_data = EI_INIT;
208 static expert_field ei_rlc_lte_sequence_analysis_last_segment_complete = EI_INIT;
209 static expert_field ei_rlc_lte_sequence_analysis_mac_retx = EI_INIT;
210 static expert_field ei_rlc_lte_am_nack_sn_partial = EI_INIT;
211 static expert_field ei_rlc_lte_sequence_analysis_repeated_nack = EI_INIT;
212 static expert_field ei_rlc_lte_bytes_after_status_pdu_complete = EI_INIT;
213 static expert_field ei_rlc_lte_sequence_analysis_repeated = EI_INIT;
214 static expert_field ei_rlc_lte_wrong_sequence_number = EI_INIT;
215 static expert_field ei_rlc_lte_sequence_analysis_retx = EI_INIT;
216 static expert_field ei_rlc_lte_am_sn_missing = EI_INIT;
217 static expert_field ei_rlc_lte_um_sn = EI_INIT;
218 static expert_field ei_rlc_lte_header_only = EI_INIT;
219 static expert_field ei_rlc_lte_am_data_no_data_beyond_extensions = EI_INIT;
220 static expert_field ei_rlc_lte_um_sn_missing = EI_INIT;
221 static expert_field ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = EI_INIT;
222 static expert_field ei_rlc_lte_sequence_analysis_last_segment_not_continued = EI_INIT;
223 static expert_field ei_rlc_lte_reserved_bits_not_zero = EI_INIT;
225 /* Value-strings */
226 static const value_string direction_vals[] =
228 { DIRECTION_UPLINK, "Uplink"},
229 { DIRECTION_DOWNLINK, "Downlink"},
230 { 0, NULL }
233 static const value_string rlc_mode_short_vals[] =
235 { RLC_TM_MODE, "TM"},
236 { RLC_UM_MODE, "UM"},
237 { RLC_AM_MODE, "AM"},
238 { RLC_PREDEF, "PREDEFINED"}, /* For data testing */
239 { 0, NULL }
242 static const value_string rlc_mode_vals[] =
244 { RLC_TM_MODE, "Transparent Mode"},
245 { RLC_UM_MODE, "Unacknowledged Mode"},
246 { RLC_AM_MODE, "Acknowledged Mode"},
247 { 0, NULL }
250 static const value_string rlc_channel_type_vals[] =
252 { CHANNEL_TYPE_CCCH, "CCCH"},
253 { CHANNEL_TYPE_BCCH_BCH, "BCCH_BCH"},
254 { CHANNEL_TYPE_PCCH, "PCCH"},
255 { CHANNEL_TYPE_SRB, "SRB"},
256 { CHANNEL_TYPE_DRB, "DRB"},
257 { CHANNEL_TYPE_BCCH_DL_SCH, "BCCH_DL_SCH"},
258 { CHANNEL_TYPE_MCCH, "MCCH"},
259 { CHANNEL_TYPE_MTCH, "MTCH"},
260 { 0, NULL }
263 static const value_string framing_info_vals[] =
265 { 0, "First byte begins a RLC SDU and last byte ends a RLC SDU"},
266 { 1, "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
267 { 2, "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
268 { 3, "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
269 { 0, NULL }
272 static const value_string fixed_extension_vals[] =
274 { 0, "Data field follows from the octet following the fixed part of the header"},
275 { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"},
276 { 0, NULL }
279 static const value_string extension_extension_vals[] =
281 { 0, "Data field follows from the octet following the LI field following this E field"},
282 { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"},
283 { 0, NULL }
286 static const value_string data_or_control_vals[] =
288 { 0, "Control PDU"},
289 { 1, "Data PDU"},
290 { 0, NULL }
293 static const value_string resegmentation_flag_vals[] =
295 { 0, "AMD PDU"},
296 { 1, "AMD PDU segment"},
297 { 0, NULL }
300 static const value_string polling_bit_vals[] =
302 { 0, "Status report not requested"},
303 { 1, "Status report is requested"},
304 { 0, NULL }
307 static const value_string lsf_vals[] =
309 { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
310 { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
311 { 0, NULL }
314 static const value_string control_pdu_type_vals[] =
316 { 0, "STATUS PDU"},
317 { 0, NULL }
320 static const value_string am_e1_vals[] =
322 { 0, "A set of NACK_SN, E1 and E2 does not follow"},
323 { 1, "A set of NACK_SN, E1 and E2 follows"},
324 { 0, NULL }
327 static const value_string am_e2_vals[] =
329 { 0, "A set of SOstart and SOend does not follow for this NACK_SN"},
330 { 1, "A set of SOstart and SOend follows for this NACK_SN"},
331 { 0, NULL }
334 static const value_string header_only_vals[] =
336 { 0, "RLC PDU Headers and body present"},
337 { 1, "RLC PDU Headers only"},
338 { 0, NULL }
343 /**********************************************************************************/
344 /* These are for keeping track of UM/AM extension headers, and the lengths found */
345 /* in them */
346 static guint8 s_number_of_extensions = 0;
347 #define MAX_RLC_SDUS 64
348 static guint16 s_lengths[MAX_RLC_SDUS];
351 /*********************************************************************/
352 /* UM/AM sequence analysis */
354 /* Types for RLC channel hash table */
355 /* This table is maintained during initial dissection of RLC */
356 /* frames, mapping from channel_hash_key -> sequence_analysis_report */
358 /* Channel key */
359 typedef struct
361 guint ueId : 16;
362 guint channelType : 3;
363 guint channelId : 5;
364 guint direction : 1;
365 } channel_hash_key;
368 /******************************************************************/
369 /* State maintained for AM/UM reassembly */
371 typedef struct rlc_segment {
372 guint32 frameNum;
373 guint16 SN;
374 guint8 *data;
375 guint16 length;
376 } rlc_segment;
378 typedef struct rlc_channel_reassembly_info
380 guint16 number_of_segments;
381 #define RLC_MAX_SEGMENTS 100
382 rlc_segment segments[RLC_MAX_SEGMENTS];
383 } rlc_channel_reassembly_info;
388 /*******************************************************************/
389 /* Conversation-type status for sequence analysis on channel */
390 typedef struct
392 guint8 rlcMode;
394 /* For UM, we always expect the SN to keep advancing, and these fields
395 keep track of this.
396 For AM, these correspond to new data */
397 guint16 previousSequenceNumber;
398 guint32 previousFrameNum;
399 gboolean previousSegmentIncomplete;
401 /* Accumulate info about current segmented SDU */
402 struct rlc_channel_reassembly_info *reassembly_info;
403 } channel_sequence_analysis_status;
405 /* The sequence analysis channel hash table */
406 static GHashTable *sequence_analysis_channel_hash = NULL;
409 /* Types for sequence analysis frame report hash table */
410 /* This is a table from framenum -> state_report_in_frame */
411 /* This is necessary because the per-packet info is already being used */
412 /* for context information before the dissector is called */
414 /* Info to attach to frame when first read, recording what to show about sequence */
415 typedef enum {
416 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window, SN_Error
417 } sequence_analysis_state;
420 typedef struct
422 gboolean sequenceExpectedCorrect;
423 guint16 sequenceExpected;
424 guint32 previousFrameNum;
425 gboolean previousSegmentIncomplete;
426 guint32 nextFrameNum;
428 guint16 firstSN;
429 guint16 lastSN;
431 /* AM/UM */
432 sequence_analysis_state state;
433 } sequence_analysis_report;
436 /* The sequence analysis frame report hash table instance itself */
437 static GHashTable *sequence_analysis_report_hash = NULL;
440 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
441 rlc_lte_info *p_rlc_lte_info,
442 gboolean do_persist);
447 /* The reassembly result hash table */
448 static GHashTable *reassembly_report_hash = NULL;
451 /* Create a new struct for reassembly */
452 static void reassembly_reset(channel_sequence_analysis_status *status)
454 status->reassembly_info = wmem_new0(wmem_file_scope(), rlc_channel_reassembly_info);
457 /* Hide previous one */
458 static void reassembly_destroy(channel_sequence_analysis_status *status)
460 /* Just "leak" it. There seems to be no way to free this memory... */
461 status->reassembly_info = NULL;
464 /* Add a new segment to the accumulating segmented SDU */
465 static void reassembly_add_segment(channel_sequence_analysis_status *status,
466 guint16 SN, guint32 frame,
467 tvbuff_t *tvb, gint offset, gint length)
469 int segment_number = status->reassembly_info->number_of_segments;
470 guint8 *segment_data;
472 /* Give up if reach segment limit */
473 if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
474 reassembly_destroy(status);
475 return;
478 segment_data = (guint8 *)wmem_alloc(wmem_file_scope(), length);
479 /* TODO: is there a better way to do this? */
480 memcpy(segment_data, tvb_get_ptr(tvb, offset, length), length);
482 /* Add new segment */
483 status->reassembly_info->segments[segment_number].frameNum = frame;
484 status->reassembly_info->segments[segment_number].SN = SN;
485 status->reassembly_info->segments[segment_number].data = segment_data;
486 status->reassembly_info->segments[segment_number].length = length;
488 status->reassembly_info->number_of_segments++;
492 /* Record the current & complete segmented SDU by mapping from this frame number to
493 struct with segment info. */
494 static void reassembly_record(channel_sequence_analysis_status *status, packet_info *pinfo,
495 guint16 SN, rlc_lte_info *p_rlc_lte_info)
497 /* Just store existing info in hash table */
498 g_hash_table_insert(reassembly_report_hash,
499 get_report_hash_key(SN, pinfo->fd->num, p_rlc_lte_info, TRUE),
500 status->reassembly_info);
503 /* Create and return a tvb based upon contents of reassembly info */
504 static tvbuff_t* reassembly_get_reassembled_tvb(rlc_channel_reassembly_info *reassembly_info,
505 tvbuff_t *parent_tvb, packet_info *pinfo)
507 gint n;
508 guint combined_length = 0;
509 guint8 *combined_data;
510 guint combined_offset = 0;
511 tvbuff_t *reassembled_tvb;
513 /* Allocate buffer big enough to hold re-assembled data */
514 for (n=0; n < reassembly_info->number_of_segments; n++) {
515 combined_length += reassembly_info->segments[n].length;
517 combined_data = (guint8 *)g_malloc(combined_length);
519 /* Copy data into contiguous buffer */
520 for (n=0; n < reassembly_info->number_of_segments; n++) {
521 guint8 *data = reassembly_info->segments[n].data;
522 int length = reassembly_info->segments[n].length;
523 memcpy(combined_data+combined_offset, data, length);
524 combined_offset += length;
527 /* Create and return tvb with this data */
528 reassembled_tvb = tvb_new_child_real_data(parent_tvb, combined_data, combined_offset, combined_offset);
529 tvb_set_free_cb(reassembled_tvb, g_free);
530 add_new_data_source(pinfo, reassembled_tvb, "Reassembled SDU");
531 return reassembled_tvb;
534 /* Show where the segments came from for a reassembled SDU */
535 static void reassembly_show_source(rlc_channel_reassembly_info *reassembly_info,
536 proto_tree *tree, tvbuff_t *tvb, gint offset)
538 int n;
539 proto_item *source_ti, *ti;
540 proto_tree *source_tree;
541 proto_item *segment_ti;
542 proto_tree *segment_tree;
543 guint total_length=0;
545 /* Create root of source info */
546 source_ti = proto_tree_add_item(tree,
547 hf_rlc_lte_reassembly_source,
548 tvb, 0, 0, ENC_ASCII|ENC_NA);
549 source_tree = proto_item_add_subtree(source_ti, ett_rlc_lte_reassembly_source);
550 PROTO_ITEM_SET_GENERATED(source_ti);
552 for (n=0; n < reassembly_info->number_of_segments; n++) {
553 total_length += reassembly_info->segments[n].length;
555 proto_item_append_text(source_ti, " %u segments, %u bytes", reassembly_info->number_of_segments,
556 total_length);
558 /* Number of segments */
559 ti = proto_tree_add_uint(source_tree,
560 hf_rlc_lte_reassembly_source_number_of_segments,
561 tvb, 0, 0, reassembly_info->number_of_segments);
562 PROTO_ITEM_SET_GENERATED(ti);
564 /* Total length */
565 ti = proto_tree_add_uint(source_tree,
566 hf_rlc_lte_reassembly_source_total_length,
567 tvb, 0, 0, total_length);
568 PROTO_ITEM_SET_GENERATED(ti);
570 /* Now add info about each segment in turn */
571 for (n=0; n < reassembly_info->number_of_segments; n++) {
573 /* Add next segment as a subtree */
574 rlc_segment *segment = &(reassembly_info->segments[n]);
575 proto_item_append_text(source_ti, " (SN=%u frame=%u len=%u)",
576 segment->SN, segment->frameNum, segment->length);
578 /* N.B. assume last segment from passed-in tvb! */
579 segment_ti = proto_tree_add_item(source_tree,
580 hf_rlc_lte_reassembly_source_segment,
581 tvb,
582 (n == reassembly_info->number_of_segments-1) ? offset : 0,
583 (n == reassembly_info->number_of_segments-1) ? segment->length : 0,
584 ENC_NA);
585 segment_tree = proto_item_add_subtree(segment_ti, ett_rlc_lte_reassembly_source_segment);
586 proto_item_append_text(segment_ti, " (SN=%u frame=%u length=%u)",
587 segment->SN, segment->frameNum, segment->length);
588 PROTO_ITEM_SET_GENERATED(segment_ti);
590 /* Add details to segment tree */
591 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_sn,
592 tvb, 0, 0, segment->SN);
593 PROTO_ITEM_SET_GENERATED(ti);
594 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_framenum,
595 tvb, 0, 0, segment->frameNum);
596 PROTO_ITEM_SET_GENERATED(ti);
597 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_length,
598 tvb, 0, 0, segment->length);
599 PROTO_ITEM_SET_GENERATED(ti);
606 /******************************************************************/
607 /* Conversation-type status for repeated NACK checking on channel */
608 typedef struct
610 guint16 noOfNACKs;
611 guint16 NACKs[MAX_NACKs];
612 guint32 frameNum;
613 } channel_repeated_nack_status;
615 static GHashTable *repeated_nack_channel_hash = NULL;
617 typedef struct {
618 guint16 noOfNACKsRepeated;
619 guint16 repeatedNACKs[MAX_NACKs];
620 guint32 previousFrameNum;
621 } channel_repeated_nack_report;
623 static GHashTable *repeated_nack_report_hash = NULL;
627 /********************************************************/
628 /* Forward declarations & functions */
629 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing);
632 /* Write the given formatted text to:
633 - the info column
634 - the top-level RLC PDU item
635 - another subtree item (if supplied) */
636 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
637 packet_info *pinfo, const char *format, ...)
639 #define MAX_INFO_BUFFER 256
640 static char info_buffer[MAX_INFO_BUFFER];
642 va_list ap;
644 va_start(ap, format);
645 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
646 va_end(ap);
648 /* Add to indicated places */
649 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
650 proto_item_append_text(pdu_ti, "%s", info_buffer);
651 if (sub_ti != NULL) {
652 proto_item_append_text(sub_ti, "%s", info_buffer);
656 /* Version of function above, where no g_vsnprintf() call needed
657 - the info column
658 - the top-level RLC PDU item
659 - another subtree item (if supplied) */
660 static void write_pdu_label_and_info_literal(proto_item *pdu_ti, proto_item *sub_ti,
661 packet_info *pinfo, const char *info_buffer)
663 /* Add to indicated places */
664 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
665 proto_item_append_text(pdu_ti, "%s", info_buffer);
666 if (sub_ti != NULL) {
667 proto_item_append_text(sub_ti, "%s", info_buffer);
673 /* Dissect extension headers (common to both UM and AM) */
674 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo _U_,
675 proto_tree *tree,
676 int offset)
678 guint8 isOdd;
679 guint64 extension = 1;
680 guint64 length;
682 /* Reset this count */
683 s_number_of_extensions = 0;
685 while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
686 proto_tree *extension_part_tree;
687 proto_item *extension_part_ti;
689 isOdd = (s_number_of_extensions % 2);
691 /* Extension part subtree */
692 extension_part_ti = proto_tree_add_string_format(tree,
693 hf_rlc_lte_extension_part,
694 tvb, offset, 2,
696 "Extension Part");
697 extension_part_tree = proto_item_add_subtree(extension_part_ti,
698 ett_rlc_lte_extension_part);
700 /* Read next extension */
701 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
702 (offset*8) + ((isOdd) ? 4 : 0),
704 &extension, ENC_BIG_ENDIAN);
706 /* Read length field */
707 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
708 (offset*8) + ((isOdd) ? 5 : 1),
710 &length, ENC_BIG_ENDIAN);
712 proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length);
714 /* Move on to byte of next extension */
715 if (isOdd) {
716 offset += 2;
717 } else {
718 offset++;
721 s_lengths[s_number_of_extensions++] = (guint16)length;
724 /* May need to skip padding after last extension part */
725 isOdd = (s_number_of_extensions % 2);
726 if (isOdd) {
727 proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
728 tvb, offset++, 1, ENC_BIG_ENDIAN);
731 return offset;
735 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
736 whether or not the beginning and end are included in this packet */
737 static void show_PDU_in_info(packet_info *pinfo,
738 proto_item *top_ti,
739 gint32 length,
740 gboolean first_includes_start,
741 gboolean last_includes_end)
743 /* Reflect this PDU in the info column */
744 if (length > 0) {
745 write_pdu_label_and_info(top_ti, NULL, pinfo,
746 " %s%u-byte%s%s",
747 (first_includes_start) ? "[" : "..",
748 length,
749 (length > 1) ? "s" : "",
750 (last_includes_end) ? "]" : "..");
752 else {
753 write_pdu_label_and_info(top_ti, NULL, pinfo,
754 " %sunknown-bytes%s",
755 (first_includes_start) ? "[" : "..",
756 (last_includes_end) ? "]" : "..");
761 /* Show an SDU. If configured, pass to PDCP/RRC/IP dissector */
762 static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, gint offset, gint length,
763 rlc_lte_info *rlc_info, gboolean whole_pdu, rlc_channel_reassembly_info *reassembly_info,
764 sequence_analysis_state state)
766 /* Add raw data (according to mode) */
767 proto_item *data_ti = proto_tree_add_item(tree,
768 (rlc_info->rlcMode == RLC_AM_MODE) ?
769 hf_rlc_lte_am_data :
770 hf_rlc_lte_um_data,
771 tvb, offset, length, ENC_NA);
773 if (whole_pdu || (reassembly_info != NULL)) {
774 if (((global_rlc_lte_call_pdcp_for_srb) && (rlc_info->channelType == CHANNEL_TYPE_SRB)) ||
775 ((global_rlc_lte_call_pdcp_for_drb != PDCP_drb_off) && (rlc_info->channelType == CHANNEL_TYPE_DRB))) {
776 /* Send whole PDU to PDCP */
778 /* TODO: made static to avoid compiler warning... */
779 static tvbuff_t *pdcp_tvb = NULL;
780 struct pdcp_lte_info *p_pdcp_lte_info;
782 /* Get tvb for passing to LTE PDCP dissector */
783 if (reassembly_info == NULL) {
784 pdcp_tvb = tvb_new_subset(tvb, offset, length, length);
786 else {
787 /* Get combined tvb. */
788 pdcp_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
789 reassembly_show_source(reassembly_info, tree, tvb, offset);
792 /* Reuse or allocate struct */
793 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(pinfo->fd, proto_pdcp_lte, 0);
794 if (p_pdcp_lte_info == NULL) {
795 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
796 /* Store info in packet */
797 p_add_proto_data(pinfo->fd, proto_pdcp_lte, 0, p_pdcp_lte_info);
800 p_pdcp_lte_info->ueid = rlc_info->ueid;
801 p_pdcp_lte_info->channelType = Channel_DCCH;
802 p_pdcp_lte_info->channelId = rlc_info->channelId;
803 p_pdcp_lte_info->direction = rlc_info->direction;
804 p_pdcp_lte_info->is_retx = (state != SN_OK);
806 /* Set plane and sequence number length */
807 p_pdcp_lte_info->no_header_pdu = FALSE;
808 if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
809 p_pdcp_lte_info->plane = SIGNALING_PLANE;
810 p_pdcp_lte_info->seqnum_length = 5;
812 else {
813 p_pdcp_lte_info->plane = USER_PLANE;
814 switch (global_rlc_lte_call_pdcp_for_drb) {
815 case PDCP_drb_SN_7:
816 p_pdcp_lte_info->seqnum_length = 7;
817 break;
818 case PDCP_drb_SN_12:
819 p_pdcp_lte_info->seqnum_length = 12;
820 break;
821 case PDCP_drb_SN_15:
822 p_pdcp_lte_info->seqnum_length = 15;
823 break;
824 case PDCP_drb_SN_signalled:
825 /* Use whatever was signalled (e.g. in RRC) */
826 p_pdcp_lte_info->seqnum_length = signalled_pdcp_sn_bits;
827 break;
829 default:
830 DISSECTOR_ASSERT(FALSE);
831 break;
835 p_pdcp_lte_info->rohc.rohc_compression = FALSE;
837 TRY {
838 call_dissector_only(pdcp_lte_handle, pdcp_tvb, pinfo, tree, NULL);
840 CATCH_ALL {
842 ENDTRY
844 PROTO_ITEM_SET_HIDDEN(data_ti);
846 else if (global_rlc_lte_call_rrc_for_mcch && (rlc_info->channelType == CHANNEL_TYPE_MCCH)) {
847 /* Send whole PDU to RRC */
848 static tvbuff_t *rrc_tvb = NULL;
849 volatile dissector_handle_t protocol_handle;
851 /* Get tvb for passing to LTE RRC dissector */
852 if (reassembly_info == NULL) {
853 rrc_tvb = tvb_new_subset(tvb, offset, length, length);
855 else {
856 /* Get combined tvb. */
857 rrc_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
858 reassembly_show_source(reassembly_info, tree, tvb, offset);
861 /* Get dissector handle */
862 protocol_handle = find_dissector("lte_rrc.mcch");
864 TRY {
865 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
867 CATCH_ALL {
869 ENDTRY
871 PROTO_ITEM_SET_HIDDEN(data_ti);
873 else if (global_rlc_lte_call_ip_for_mtch && (rlc_info->channelType == CHANNEL_TYPE_MTCH)) {
874 /* Send whole PDU to IP */
875 static tvbuff_t *ip_tvb = NULL;
877 /* Get tvb for passing to IP dissector */
878 if (reassembly_info == NULL) {
879 ip_tvb = tvb_new_subset(tvb, offset, length, length);
881 else {
882 /* Get combined tvb. */
883 ip_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
884 reassembly_show_source(reassembly_info, tree, tvb, offset);
887 TRY {
888 call_dissector_only(ip_handle, ip_tvb, pinfo, tree, NULL);
890 CATCH_ALL {
892 ENDTRY
894 PROTO_ITEM_SET_HIDDEN(data_ti);
899 /* Hash table functions for RLC channels */
901 /* Equal keys */
902 static gint rlc_channel_equal(gconstpointer v, gconstpointer v2)
904 const channel_hash_key* val1 = (const channel_hash_key *)v;
905 const channel_hash_key* val2 = (const channel_hash_key *)v2;
907 /* All fields must match */
908 /* N.B. Currently fits into one word, so could return (*v == *v2)
909 if we're sure they're initialised to 0... */
910 return ((val1->ueId == val2->ueId) &&
911 (val1->channelType == val2->channelType) &&
912 (val1->channelId == val2->channelId) &&
913 (val1->direction == val2->direction));
916 /* Compute a hash value for a given key. */
917 static guint rlc_channel_hash_func(gconstpointer v)
919 const channel_hash_key* val1 = (const channel_hash_key *)v;
921 /* TODO: check/reduce multipliers */
922 return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
926 /*************************************************************************/
927 /* Result hash */
929 typedef struct {
930 guint32 frameNumber;
931 guint32 SN : 10;
932 guint32 channelType : 2;
933 guint32 channelId: 5;
934 guint32 direction: 1;
935 } rlc_result_hash_key;
937 /* Compare 2 rlc_result_hash_key structs */
938 static gint rlc_result_hash_equal(gconstpointer v, gconstpointer v2)
940 const rlc_result_hash_key *val1 = (const rlc_result_hash_key *)v;
941 const rlc_result_hash_key *val2 = (const rlc_result_hash_key *)v2;
943 /* All fields (and any padding...) must match */
944 return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
947 /* Compute a hash value for a given key. */
948 static guint rlc_result_hash_func(gconstpointer v)
950 const rlc_result_hash_key* val1 = (const rlc_result_hash_key *)v;
952 /* Got rid of multipliers - no evidence that they reduced collisions */
953 return val1->frameNumber + val1->SN +
954 val1->channelType +
955 val1->channelId +
956 val1->direction;
959 /* Convenience function to get a pointer for the hash_func to work with */
960 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
961 rlc_lte_info *p_rlc_lte_info,
962 gboolean do_persist)
964 static rlc_result_hash_key key;
965 rlc_result_hash_key *p_key;
967 /* Only allocate a struct when will be adding entry */
968 if (do_persist) {
969 p_key = wmem_new0(wmem_file_scope(), rlc_result_hash_key);
971 else {
972 memset(&key, 0, sizeof(rlc_result_hash_key));
973 p_key = &key;
976 /* Fill in details, and return pointer */
977 p_key->frameNumber = frameNumber;
978 p_key->SN = SN;
979 p_key->channelType = p_rlc_lte_info->channelType;
980 p_key->channelId = p_rlc_lte_info->channelId;
981 p_key->direction = p_rlc_lte_info->direction;
983 return p_key;
986 static void checkFIconsistency(sequence_analysis_report *p,
987 rlc_lte_info *p_rlc_lte_info,
988 gboolean newSegmentStarted,
989 proto_tree *seqnum_tree,
990 packet_info *pinfo, tvbuff_t *tvb)
992 proto_item *ti;
994 if (p->previousSegmentIncomplete) {
995 /* Previous segment was incomplete, so this PDU should continue it */
996 if (newSegmentStarted) {
997 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
998 tvb, 0, 0, FALSE);
999 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_not_continued,
1000 "Last segment of previous PDU was not continued for UE %u (%s-%u)",
1001 p_rlc_lte_info->ueid,
1002 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1003 p_rlc_lte_info->channelId);
1005 else {
1006 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1007 tvb, 0, 0, TRUE);
1008 PROTO_ITEM_SET_HIDDEN(ti);
1011 else {
1012 /* Previous segment was complete, so this PDU should start a new one */
1013 if (!newSegmentStarted) {
1014 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1015 tvb, 0, 0, FALSE);
1016 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_complete,
1017 "Last segment of previous PDU was complete, but new segment was not started on UE %u (%s-%u)",
1018 p_rlc_lte_info->ueid,
1019 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1020 p_rlc_lte_info->channelId);
1022 else {
1023 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1024 tvb, 0, 0, TRUE);
1025 PROTO_ITEM_SET_HIDDEN(ti);
1028 PROTO_ITEM_SET_GENERATED(ti);
1031 /* Add to the tree values associated with sequence analysis for this frame */
1032 static void addChannelSequenceInfo(sequence_analysis_report *p,
1033 gboolean isControlFrame,
1034 rlc_lte_info *p_rlc_lte_info,
1035 guint16 sequenceNumber,
1036 gboolean newSegmentStarted,
1037 rlc_lte_tap_info *tap_info,
1038 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
1040 proto_tree *seqnum_tree;
1041 proto_item *seqnum_ti;
1042 proto_item *ti;
1044 /* Create subtree */
1045 seqnum_ti = proto_tree_add_string_format(tree,
1046 hf_rlc_lte_sequence_analysis,
1047 tvb, 0, 0,
1048 "", "Sequence Analysis");
1049 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1050 ett_rlc_lte_sequence_analysis);
1051 PROTO_ITEM_SET_GENERATED(seqnum_ti);
1053 if (p->previousFrameNum != 0) {
1054 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1055 tvb, 0, 0, p->previousFrameNum);
1056 PROTO_ITEM_SET_GENERATED(ti);
1059 switch (p_rlc_lte_info->rlcMode) {
1060 case RLC_AM_MODE:
1062 /********************************************/
1063 /* AM */
1064 /********************************************/
1066 switch (p->state) {
1067 case SN_OK:
1068 if (isControlFrame) {
1069 return;
1072 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1073 tvb, 0, 0, TRUE);
1074 PROTO_ITEM_SET_GENERATED(ti);
1075 proto_item_append_text(seqnum_ti, " - OK");
1077 /* Link to next SN in channel (if known) */
1078 if (p->nextFrameNum != 0) {
1079 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1080 tvb, 0, 0, p->nextFrameNum);
1082 /* Correct sequence number, so check frame indication bits consistent */
1083 /* Deactivated for now as it gets confused by resegmentation */
1084 /* checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb); */
1085 break;
1087 case SN_MAC_Retx:
1088 if (isControlFrame) {
1089 return;
1092 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1093 tvb, 0, 0, FALSE);
1094 PROTO_ITEM_SET_GENERATED(ti);
1095 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1096 tvb, 0, 0, TRUE);
1097 PROTO_ITEM_SET_GENERATED(ti);
1098 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1099 "AM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1100 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1101 p_rlc_lte_info->ueid,
1102 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1103 p_rlc_lte_info->channelId);
1104 proto_item_append_text(seqnum_ti, " - MAC retx of SN %u", p->firstSN);
1105 break;
1107 case SN_Retx:
1108 if (isControlFrame) {
1109 return;
1112 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1113 tvb, 0, 0, FALSE);
1114 PROTO_ITEM_SET_GENERATED(ti);
1115 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
1116 tvb, 0, 0, TRUE);
1117 PROTO_ITEM_SET_GENERATED(ti);
1118 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_retx,
1119 "AM Frame retransmitted for %s on UE %u - most likely in response to NACK (%s-%u)",
1120 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1121 p_rlc_lte_info->ueid,
1122 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1123 p_rlc_lte_info->channelId);
1124 proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
1125 break;
1127 case SN_Repeated:
1128 if (isControlFrame) {
1129 return;
1132 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1133 tvb, 0, 0, FALSE);
1134 PROTO_ITEM_SET_GENERATED(ti);
1135 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1136 tvb, 0, 0, TRUE);
1137 PROTO_ITEM_SET_GENERATED(ti);
1138 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated,
1139 "AM SN Repeated for %s for UE %u - probably because didn't receive Status PDU? (%s-%u)",
1140 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1141 p_rlc_lte_info->ueid,
1142 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1143 p_rlc_lte_info->channelId);
1144 proto_item_append_text(seqnum_ti, "- SN %u Repeated", p->firstSN);
1145 break;
1147 case SN_Missing:
1148 if (isControlFrame) {
1149 return;
1152 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1153 tvb, 0, 0, FALSE);
1154 PROTO_ITEM_SET_GENERATED(ti);
1155 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1156 tvb, 0, 0, TRUE);
1157 PROTO_ITEM_SET_GENERATED(ti);
1158 if (p->lastSN != p->firstSN) {
1159 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1160 "AM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1161 p->firstSN, p->lastSN,
1162 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1163 p_rlc_lte_info->ueid,
1164 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1165 p_rlc_lte_info->channelId);
1166 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1167 p->firstSN, p->lastSN);
1168 tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1170 else {
1171 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1172 "AM SN (%u) missing for %s on UE %u (%s-%u)",
1173 p->firstSN,
1174 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1175 p_rlc_lte_info->ueid,
1176 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1177 p_rlc_lte_info->channelId);
1178 proto_item_append_text(seqnum_ti, " - SN missing (%u)", p->firstSN);
1179 tap_info->missingSNs = 1;
1181 break;
1183 case ACK_Out_of_Window:
1184 if (!isControlFrame) {
1185 return;
1189 /* Not OK */
1190 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1191 tvb, 0, 0, FALSE);
1192 /* Out of range */
1193 PROTO_ITEM_SET_GENERATED(ti);
1194 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1195 tvb, 0, 0, TRUE);
1196 PROTO_ITEM_SET_GENERATED(ti);
1198 /* Link back to last seen SN in other direction */
1199 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1200 tvb, 0, 0, p->previousFrameNum);
1201 PROTO_ITEM_SET_GENERATED(ti);
1203 /* Expert error */
1204 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1205 "AM ACK for SN %u - but last received SN in other direction is %u for UE %u (%s-%u)",
1206 p->firstSN, p->sequenceExpected,
1207 p_rlc_lte_info->ueid,
1208 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1209 p_rlc_lte_info->channelId);
1210 proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1211 p->firstSN, p->sequenceExpected);
1213 break;
1215 default:
1216 return;
1218 break;
1220 case RLC_UM_MODE:
1222 /********************************************/
1223 /* UM */
1224 /********************************************/
1226 /* Expected sequence number */
1227 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
1228 tvb, 0, 0, p->sequenceExpected);
1229 PROTO_ITEM_SET_GENERATED(ti);
1230 if (p->sequenceExpectedCorrect) {
1231 PROTO_ITEM_SET_HIDDEN(ti);
1234 if (!p->sequenceExpectedCorrect) {
1235 /* Work out SN wrap (in case needed below) */
1236 guint16 snLimit;
1237 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1238 snLimit = 32;
1240 else {
1241 snLimit = 1024;
1244 switch (p->state) {
1245 case SN_Missing:
1246 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1247 tvb, 0, 0, FALSE);
1248 PROTO_ITEM_SET_GENERATED(ti);
1249 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1250 tvb, 0, 0, TRUE);
1251 PROTO_ITEM_SET_GENERATED(ti);
1252 if (p->lastSN != p->firstSN) {
1253 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1254 "UM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1255 p->firstSN, p->lastSN,
1256 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1257 p_rlc_lte_info->ueid,
1258 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1259 p_rlc_lte_info->channelId);
1260 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1261 p->firstSN, p->lastSN);
1262 tap_info->missingSNs = ((snLimit + p->lastSN - p->firstSN) % snLimit) + 1;
1264 else {
1265 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1266 "UM SN (%u) missing for %s on UE %u (%s-%u)",
1267 p->firstSN,
1268 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1269 p_rlc_lte_info->ueid,
1270 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1271 p_rlc_lte_info->channelId);
1272 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
1273 p->firstSN);
1274 tap_info->missingSNs = 1;
1276 break;
1278 case SN_Repeated:
1279 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1280 tvb, 0, 0, FALSE);
1281 PROTO_ITEM_SET_GENERATED(ti);
1282 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1283 tvb, 0, 0, TRUE);
1284 PROTO_ITEM_SET_GENERATED(ti);
1285 expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_repeated,
1286 "UM SN (%u) repeated for %s for UE %u (%s-%u)",
1287 p->firstSN,
1288 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1289 p_rlc_lte_info->ueid,
1290 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1291 p_rlc_lte_info->channelId);
1292 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
1293 p->firstSN);
1294 break;
1296 case SN_MAC_Retx:
1297 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1298 tvb, 0, 0, FALSE);
1299 PROTO_ITEM_SET_GENERATED(ti);
1300 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1301 tvb, 0, 0, TRUE);
1302 PROTO_ITEM_SET_GENERATED(ti);
1303 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1304 "UM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1305 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1306 p_rlc_lte_info->ueid,
1307 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1308 p_rlc_lte_info->channelId);
1309 break;
1311 default:
1312 /* Incorrect sequence number */
1313 expert_add_info_format(pinfo, ti, &ei_rlc_lte_wrong_sequence_number,
1314 "Wrong Sequence Number for %s on UE %u - got %u, expected %u (%s-%u)",
1315 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1316 p_rlc_lte_info->ueid, sequenceNumber, p->sequenceExpected,
1317 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1318 p_rlc_lte_info->channelId);
1320 break;
1324 else {
1325 /* Correct sequence number, so check frame indication bits consistent */
1326 checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb);
1328 /* Set OK here! */
1329 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1330 tvb, 0, 0, TRUE);
1331 PROTO_ITEM_SET_GENERATED(ti);
1332 proto_item_append_text(seqnum_ti, " - OK");
1335 /* Next channel frame */
1336 if (p->nextFrameNum != 0) {
1337 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1338 tvb, 0, 0, p->nextFrameNum);
1339 PROTO_ITEM_SET_GENERATED(ti);
1344 /* Update the channel status and set report for this frame */
1345 static sequence_analysis_state checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
1346 rlc_lte_info *p_rlc_lte_info,
1347 gboolean isControlFrame,
1348 guint8 number_of_segments,
1349 guint16 firstSegmentOffset,
1350 guint16 firstSegmentLength,
1351 guint16 lastSegmentOffset,
1352 guint16 sequenceNumber,
1353 gboolean first_includes_start, gboolean last_includes_end,
1354 gboolean is_resegmented _U_,
1355 rlc_lte_tap_info *tap_info,
1356 proto_tree *tree)
1358 channel_hash_key channel_key;
1359 channel_hash_key *p_channel_key;
1360 channel_sequence_analysis_status *p_channel_status;
1361 sequence_analysis_report *p_report_in_frame = NULL;
1362 gboolean createdChannel = FALSE;
1363 guint16 expectedSequenceNumber = 0;
1364 guint16 snLimit = 0;
1366 /* If find stat_report_in_frame already, use that and get out */
1367 if (pinfo->fd->flags.visited) {
1368 p_report_in_frame = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1369 get_report_hash_key(sequenceNumber,
1370 pinfo->fd->num,
1371 p_rlc_lte_info,
1372 FALSE));
1373 if (p_report_in_frame != NULL) {
1374 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
1375 sequenceNumber, first_includes_start,
1376 tap_info, pinfo, tree, tvb);
1377 return p_report_in_frame->state;
1380 /* Don't just give up here... */
1384 /**************************************************/
1385 /* Create or find an entry for this channel state */
1386 channel_key.ueId = p_rlc_lte_info->ueid;
1387 channel_key.channelType = p_rlc_lte_info->channelType;
1388 channel_key.channelId = p_rlc_lte_info->channelId;
1389 channel_key.direction = p_rlc_lte_info->direction;
1391 /* Do the table lookup */
1392 p_channel_status = (channel_sequence_analysis_status*)g_hash_table_lookup(sequence_analysis_channel_hash, &channel_key);
1394 /* Create table entry if necessary */
1395 if (p_channel_status == NULL) {
1396 createdChannel = TRUE;
1398 /* Allocate a new value and duplicate key contents */
1399 p_channel_status = wmem_new0(wmem_file_scope(), channel_sequence_analysis_status);
1400 p_channel_key = (channel_hash_key *)wmem_memdup(wmem_file_scope(), &channel_key, sizeof(channel_hash_key));
1402 /* Set mode */
1403 p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1405 /* Add entry */
1406 g_hash_table_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1409 /* Create space for frame state_report */
1410 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1413 /* Deal with according to channel mode */
1414 switch (p_channel_status->rlcMode) {
1415 case RLC_UM_MODE:
1417 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1418 snLimit = 32;
1420 else {
1421 snLimit = 1024;
1424 /* Work out expected sequence number */
1425 if (!createdChannel) {
1426 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1428 else {
1429 /* Whatever we got is fine.. */
1430 expectedSequenceNumber = sequenceNumber;
1433 if ((sequenceNumber == 0) &&
1434 ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH))) {
1435 /* With eMBMS, SN restarts to 0 at each MCH Scheduling Period so we cannot deduce easily whether
1436 there was a PDU loss or not without analysing the Frame Indicator; assume no loss when seeing 0 */
1437 expectedSequenceNumber = 0;
1440 /* Set report for this frame */
1441 /* For UM, sequence number is always expectedSequence number */
1442 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
1444 /* For wrong sequence number... */
1445 if (!p_report_in_frame->sequenceExpectedCorrect) {
1447 /* Don't get confused by MAC (HARQ) retx */
1448 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1449 p_report_in_frame->state = SN_MAC_Retx;
1450 p_report_in_frame->firstSN = sequenceNumber;
1452 /* No channel state to update */
1453 break;
1456 /* Frames are not missing if we get an earlier sequence number again */
1457 /* TODO: taking time into account would give better idea of whether missing or repeated... */
1458 else if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH) ||
1459 (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10)) {
1460 reassembly_destroy(p_channel_status);
1462 p_report_in_frame->state = SN_Missing;
1463 tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
1464 p_report_in_frame->firstSN = expectedSequenceNumber;
1465 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
1467 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1468 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1469 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1471 /* Update channel status to remember *this* frame */
1472 p_channel_status->previousFrameNum = pinfo->fd->num;
1473 p_channel_status->previousSequenceNumber = sequenceNumber;
1474 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1476 else {
1477 /* An SN has been repeated */
1478 p_report_in_frame->state = SN_Repeated;
1479 p_report_in_frame->firstSN = sequenceNumber;
1481 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1482 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1485 else {
1486 /* SN was OK */
1487 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1488 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1489 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1491 /* Update channel status to remember *this* frame */
1492 p_channel_status->previousFrameNum = pinfo->fd->num;
1493 p_channel_status->previousSequenceNumber = sequenceNumber;
1494 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1496 if (p_channel_status->reassembly_info) {
1497 /* Add next segment to reassembly info */
1498 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->fd->num,
1499 tvb, firstSegmentOffset, firstSegmentLength);
1501 /* The end of existing reassembly? */
1502 if (!first_includes_start &&
1503 ((number_of_segments > 1) || last_includes_end)) {
1505 reassembly_record(p_channel_status, pinfo, sequenceNumber, p_rlc_lte_info);
1506 reassembly_destroy(p_channel_status);
1510 /* The start of a new reassembly? */
1511 if (!last_includes_end &&
1512 ((number_of_segments > 1) || first_includes_start)) {
1514 guint16 lastSegmentLength = tvb_length(tvb)-lastSegmentOffset;
1516 if (global_rlc_lte_reassembly) {
1517 reassembly_reset(p_channel_status);
1518 reassembly_add_segment(p_channel_status, sequenceNumber,
1519 pinfo->fd->num,
1520 tvb, lastSegmentOffset, lastSegmentLength);
1524 if (p_report_in_frame->previousFrameNum != 0) {
1525 /* Get report for previous frame */
1526 sequence_analysis_report *p_previous_report;
1527 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1528 snLimit = 32;
1530 else {
1531 snLimit = 1024;
1534 /* Look up report for previous SN */
1535 p_previous_report = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1536 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1537 p_report_in_frame->previousFrameNum,
1538 p_rlc_lte_info,
1539 FALSE));
1540 /* It really shouldn't be NULL... */
1541 if (p_previous_report != NULL) {
1542 /* Point it forward to this one */
1543 p_previous_report->nextFrameNum = pinfo->fd->num;
1548 break;
1550 case RLC_AM_MODE:
1552 /* Work out expected sequence number */
1553 if (!createdChannel) {
1554 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % 1024;
1556 else {
1557 /* Whatever we got is fine.. */
1558 expectedSequenceNumber = sequenceNumber;
1561 /* For AM, may be:
1562 - expected Sequence number OR
1563 - previous frame repeated
1564 - old SN being sent (in response to NACK)
1565 - new SN, but with frames missed out
1566 Assume window whose front is at expectedSequenceNumber */
1568 /* First of all, check to see whether frame is judged to be MAC Retx */
1569 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1570 /* Just report that this is a MAC Retx */
1571 p_report_in_frame->state = SN_MAC_Retx;
1572 p_report_in_frame->firstSN = sequenceNumber;
1574 /* No channel state to update */
1575 break;
1578 if (sequenceNumber != expectedSequenceNumber) {
1579 /* Don't trash reassembly info if this looks like a close retx... */
1580 if (((1024 + sequenceNumber - expectedSequenceNumber) % 1024) < 50) {
1581 reassembly_destroy(p_channel_status);
1585 /* Expected? */
1586 if (sequenceNumber == expectedSequenceNumber) {
1587 /* Set report for this frame */
1588 p_report_in_frame->sequenceExpectedCorrect = TRUE;
1589 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1590 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1591 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1592 p_report_in_frame->state = SN_OK;
1594 /* Update channel status */
1595 p_channel_status->previousSequenceNumber = sequenceNumber;
1596 p_channel_status->previousFrameNum = pinfo->fd->num;
1597 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1600 if (p_channel_status->reassembly_info) {
1602 /* Add next segment to reassembly info */
1603 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->fd->num,
1604 tvb, firstSegmentOffset, firstSegmentLength);
1606 /* The end of existing reassembly? */
1607 if (!first_includes_start &&
1608 ((number_of_segments > 1) || last_includes_end)) {
1610 reassembly_record(p_channel_status, pinfo,
1611 sequenceNumber, p_rlc_lte_info);
1612 reassembly_destroy(p_channel_status);
1616 /* The start of a new reassembly? */
1617 if (!last_includes_end &&
1618 ((number_of_segments > 1) || first_includes_start)) {
1620 guint16 lastSegmentLength = tvb_length(tvb)-lastSegmentOffset;
1621 if (global_rlc_lte_reassembly) {
1622 reassembly_reset(p_channel_status);
1623 reassembly_add_segment(p_channel_status, sequenceNumber,
1624 pinfo->fd->num,
1625 tvb, lastSegmentOffset, lastSegmentLength);
1629 if (p_report_in_frame->previousFrameNum != 0) {
1630 /* Get report for previous frame */
1631 sequence_analysis_report *p_previous_report;
1632 p_previous_report = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1633 get_report_hash_key((sequenceNumber+1023) % 1024,
1634 p_report_in_frame->previousFrameNum,
1635 p_rlc_lte_info,
1636 FALSE));
1637 /* It really shouldn't be NULL... */
1638 if (p_previous_report != NULL) {
1639 /* Point it forward to this one */
1640 p_previous_report->nextFrameNum = pinfo->fd->num;
1646 /* Previous subframe repeated? */
1647 else if (((sequenceNumber+1) % 1024) == expectedSequenceNumber) {
1648 p_report_in_frame->state = SN_Repeated;
1650 /* Set report for this frame */
1651 p_report_in_frame->sequenceExpectedCorrect = FALSE;
1652 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1653 p_report_in_frame->firstSN = sequenceNumber;
1654 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1655 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1658 /* Really should be nothing to update... */
1659 p_channel_status->previousSequenceNumber = sequenceNumber;
1660 p_channel_status->previousFrameNum = pinfo->fd->num;
1661 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1664 else {
1665 /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1666 int delta = (1024 + expectedSequenceNumber - sequenceNumber) % 1024;
1668 /* Rx window is 512, so check to see if this is a retx */
1669 if (delta < 512) {
1670 /* Probably a retx due to receiving NACK */
1671 p_report_in_frame->state = SN_Retx;
1673 p_report_in_frame->firstSN = sequenceNumber;
1674 /* Don't update anything in channel state */
1677 else {
1678 /* Ahead of expected SN. Assume frames have been missed */
1679 p_report_in_frame->state = SN_Missing;
1681 p_report_in_frame->firstSN = expectedSequenceNumber;
1682 p_report_in_frame->lastSN = (1024 + sequenceNumber-1) % 1024;
1684 /* Update channel state - forget about missed SNs */
1685 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1686 p_channel_status->previousSequenceNumber = sequenceNumber;
1687 p_channel_status->previousFrameNum = pinfo->fd->num;
1688 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1691 break;
1693 default:
1694 /* Shouldn't get here! */
1695 return SN_Error;
1698 /* Associate with this frame number */
1699 g_hash_table_insert(sequence_analysis_report_hash,
1700 get_report_hash_key(sequenceNumber, pinfo->fd->num, p_rlc_lte_info, TRUE),
1701 p_report_in_frame);
1703 /* Add state report for this frame into tree */
1704 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1705 first_includes_start, tap_info, pinfo, tree, tvb);
1707 return p_report_in_frame->state;
1711 /* Add to the tree values associated with sequence analysis for this frame */
1712 static void addChannelRepeatedNACKInfo(channel_repeated_nack_report *p,
1713 rlc_lte_info *p_rlc_lte_info,
1714 packet_info *pinfo, proto_tree *tree,
1715 tvbuff_t *tvb)
1717 proto_tree *seqnum_tree;
1718 proto_item *seqnum_ti;
1719 proto_item *ti;
1720 gint n;
1722 /* Create subtree */
1723 seqnum_ti = proto_tree_add_string_format(tree,
1724 hf_rlc_lte_sequence_analysis,
1725 tvb, 0, 0,
1726 "", "Sequence Analysis");
1727 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1728 ett_rlc_lte_sequence_analysis);
1729 PROTO_ITEM_SET_GENERATED(seqnum_ti);
1731 /* OK = FALSE */
1732 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1733 tvb, 0, 0, FALSE);
1734 PROTO_ITEM_SET_GENERATED(ti);
1736 /* Add each repeated NACK as item & expert info */
1737 for (n=0; n < p->noOfNACKsRepeated; n++) {
1739 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
1740 tvb, 0, 0, p->repeatedNACKs[n]);
1741 PROTO_ITEM_SET_GENERATED(ti);
1743 expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated_nack,
1744 "Same SN (%u) NACKd for %s on UE %u in successive Status PDUs",
1745 p->repeatedNACKs[n],
1746 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1747 p_rlc_lte_info->ueid);
1750 /* Link back to previous status report */
1751 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
1752 tvb, 0, 0, p->previousFrameNum);
1753 PROTO_ITEM_SET_GENERATED(ti);
1755 /* Append count to sequence analysis root */
1756 proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
1757 p->noOfNACKsRepeated);
1761 /* Update the channel repeated NACK status and set report for this frame */
1762 static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
1763 rlc_lte_info *p_rlc_lte_info,
1764 rlc_lte_tap_info *tap_info,
1765 proto_tree *tree,
1766 tvbuff_t *tvb)
1768 channel_hash_key channel_key;
1769 channel_hash_key *p_channel_key;
1770 channel_repeated_nack_status *p_channel_status;
1771 channel_repeated_nack_report *p_report_in_frame = NULL;
1773 guint16 noOfNACKsRepeated = 0;
1774 guint16 repeatedNACKs[MAX_NACKs];
1775 gint n, i, j;
1777 /* If find state_report_in_frame already, use that and get out */
1778 if (pinfo->fd->flags.visited) {
1779 p_report_in_frame = (channel_repeated_nack_report*)g_hash_table_lookup(repeated_nack_report_hash,
1780 get_report_hash_key(0, pinfo->fd->num,
1781 p_rlc_lte_info, FALSE));
1782 if (p_report_in_frame != NULL) {
1783 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1784 pinfo, tree, tvb);
1785 return;
1787 else {
1788 /* Give up - we must have tried already... */
1789 return;
1794 /**************************************************/
1795 /* Create or find an entry for this channel state */
1796 channel_key.ueId = p_rlc_lte_info->ueid;
1797 channel_key.channelType = p_rlc_lte_info->channelType;
1798 channel_key.channelId = p_rlc_lte_info->channelId;
1799 channel_key.direction = p_rlc_lte_info->direction;
1800 memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1802 /* Do the table lookup */
1803 p_channel_status = (channel_repeated_nack_status*)g_hash_table_lookup(repeated_nack_channel_hash, &channel_key);
1805 /* Create table entry if necessary */
1806 if (p_channel_status == NULL) {
1808 /* Allocate a new key and value */
1809 p_channel_key = wmem_new(wmem_file_scope(), channel_hash_key);
1810 p_channel_status = wmem_new0(wmem_file_scope(), channel_repeated_nack_status);
1812 /* Copy key contents */
1813 memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1815 /* Add entry to table */
1816 g_hash_table_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1819 /* Compare NACKs in channel status with NACKs in tap_info.
1820 Note any that are repeated */
1821 for (i=0; i < p_channel_status->noOfNACKs; i++) {
1822 for (j=0; j < MIN(tap_info->noOfNACKs, MAX_NACKs); j++) {
1823 if (tap_info->NACKs[j] == p_channel_status->NACKs[i]) {
1824 /* Don't add the same repeated NACK twice! */
1825 if ((noOfNACKsRepeated == 0) ||
1826 (repeatedNACKs[noOfNACKsRepeated-1] != p_channel_status->NACKs[i])) {
1828 repeatedNACKs[noOfNACKsRepeated++] = p_channel_status->NACKs[i];
1834 /* Copy NACKs from tap_info into channel status for next time! */
1835 p_channel_status->noOfNACKs = 0;
1836 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1837 p_channel_status->NACKs[p_channel_status->noOfNACKs++] = tap_info->NACKs[n];
1840 if (noOfNACKsRepeated >= 1) {
1841 /* Create space for frame state_report */
1842 p_report_in_frame = wmem_new(wmem_file_scope(), channel_repeated_nack_report);
1844 /* Copy in found duplicates */
1845 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1846 p_report_in_frame->repeatedNACKs[n] = repeatedNACKs[n];
1848 p_report_in_frame->noOfNACKsRepeated = noOfNACKsRepeated;
1850 p_report_in_frame->previousFrameNum = p_channel_status->frameNum;
1852 /* Associate with this frame number */
1853 g_hash_table_insert(repeated_nack_report_hash,
1854 get_report_hash_key(0, pinfo->fd->num,
1855 p_rlc_lte_info, TRUE),
1856 p_report_in_frame);
1858 /* Add state report for this frame into tree */
1859 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1860 pinfo, tree, tvb);
1863 /* Save frame number for next comparison */
1864 p_channel_status->frameNum = pinfo->fd->num;
1867 /* Check that the ACK is consistent with data the expected sequence number
1868 in the other direction */
1869 static void checkChannelACKWindow(guint16 ack_sn,
1870 packet_info *pinfo,
1871 rlc_lte_info *p_rlc_lte_info,
1872 rlc_lte_tap_info *tap_info,
1873 proto_tree *tree,
1874 tvbuff_t *tvb)
1876 channel_hash_key channel_key;
1877 channel_sequence_analysis_status *p_channel_status;
1878 sequence_analysis_report *p_report_in_frame = NULL;
1880 /* If find stat_report_in_frame already, use that and get out */
1881 if (pinfo->fd->flags.visited) {
1882 p_report_in_frame = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1883 get_report_hash_key(0, pinfo->fd->num,
1884 p_rlc_lte_info,
1885 FALSE));
1886 if (p_report_in_frame != NULL) {
1887 /* Add any info to tree */
1888 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info,
1889 0, FALSE,
1890 tap_info, pinfo, tree, tvb);
1891 return;
1893 else {
1894 /* Give up - we must have tried already... */
1895 return;
1899 /*******************************************************************/
1900 /* Find an entry for this channel state (in the opposite direction */
1901 channel_key.ueId = p_rlc_lte_info->ueid;
1902 channel_key.channelType = p_rlc_lte_info->channelType;
1903 channel_key.channelId = p_rlc_lte_info->channelId;
1904 channel_key.direction =
1905 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1907 /* Do the table lookup */
1908 p_channel_status = (channel_sequence_analysis_status*)g_hash_table_lookup(sequence_analysis_channel_hash, &channel_key);
1910 /* Create table entry if necessary */
1911 if (p_channel_status == NULL) {
1912 return;
1915 /* Is it in the rx window? This test will catch if it's ahead, but we don't
1916 really know what the back of the tx window is... */
1917 if (((1024 + p_channel_status->previousSequenceNumber+1 - ack_sn) % 1024) > 512) {
1919 /* Set result */
1920 p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1921 p_report_in_frame->state = ACK_Out_of_Window;
1922 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1923 p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1924 p_report_in_frame->firstSN = ack_sn;
1926 /* Associate with this frame number */
1927 g_hash_table_insert(sequence_analysis_report_hash,
1928 get_report_hash_key(0, pinfo->fd->num,
1929 p_rlc_lte_info, TRUE),
1930 p_report_in_frame);
1932 /* Add state report for this frame into tree */
1933 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info, 0,
1934 FALSE, tap_info, pinfo, tree, tvb);
1941 /***************************************************/
1942 /* Transparent mode PDU. Call RRC if configured to */
1943 static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
1944 proto_tree *tree,
1945 int offset,
1946 rlc_lte_info *p_rlc_lte_info,
1947 proto_item *top_ti)
1949 proto_item *raw_tm_ti;
1950 proto_item *tm_ti;
1952 /* Create hidden TM root */
1953 tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
1954 tvb, offset, 0, "", "TM");
1955 PROTO_ITEM_SET_HIDDEN(tm_ti);
1957 /* Remaining bytes are all data */
1958 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, ENC_NA);
1959 if (!global_rlc_lte_call_rrc_for_ccch) {
1960 write_pdu_label_and_info(top_ti, NULL, pinfo,
1961 " [%u-bytes]", tvb_length_remaining(tvb, offset));
1964 if (global_rlc_lte_call_rrc_for_ccch) {
1965 tvbuff_t *rrc_tvb = tvb_new_subset_remaining(tvb, offset);
1966 volatile dissector_handle_t protocol_handle = 0;
1968 switch (p_rlc_lte_info->channelType) {
1969 case CHANNEL_TYPE_CCCH:
1970 if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
1971 protocol_handle = find_dissector("lte_rrc.ul_ccch");
1973 else {
1974 protocol_handle = find_dissector("lte_rrc.dl_ccch");
1976 break;
1978 case CHANNEL_TYPE_BCCH_BCH:
1979 protocol_handle = find_dissector("lte_rrc.bcch_bch");
1980 break;
1981 case CHANNEL_TYPE_BCCH_DL_SCH:
1982 protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
1983 break;
1984 case CHANNEL_TYPE_PCCH:
1985 protocol_handle = find_dissector("lte_rrc.pcch");
1986 break;
1988 case CHANNEL_TYPE_SRB:
1989 case CHANNEL_TYPE_DRB:
1990 case CHANNEL_TYPE_MCCH:
1991 case CHANNEL_TYPE_MTCH:
1993 default:
1994 /* Shouldn't happen, just return... */
1995 return;
1998 /* Hide raw view of bytes */
1999 PROTO_ITEM_SET_HIDDEN(raw_tm_ti);
2001 /* Call it (catch exceptions) */
2002 TRY {
2003 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
2005 CATCH_ALL {
2007 ENDTRY
2013 /***************************************************/
2014 /* Unacknowledged mode PDU */
2015 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
2016 proto_tree *tree,
2017 int offset,
2018 rlc_lte_info *p_rlc_lte_info,
2019 proto_item *top_ti,
2020 rlc_lte_tap_info *tap_info)
2022 guint64 framing_info;
2023 gboolean first_includes_start;
2024 gboolean last_includes_end;
2025 guint64 fixed_extension;
2026 guint64 sn;
2027 gint start_offset = offset;
2028 proto_item *um_ti;
2029 proto_tree *um_header_tree;
2030 proto_item *um_header_ti;
2031 gboolean is_truncated = FALSE;
2032 proto_item *truncated_ti;
2033 rlc_channel_reassembly_info *reassembly_info = NULL;
2034 sequence_analysis_state seq_anal_state = SN_OK;
2036 /* Hidden UM root */
2037 um_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um,
2038 tvb, offset, 0, "", "UM");
2039 PROTO_ITEM_SET_HIDDEN(um_ti);
2041 /* Add UM header subtree */
2042 um_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um_header,
2043 tvb, offset, 0,
2044 "", "UM header");
2045 um_header_tree = proto_item_add_subtree(um_header_ti,
2046 ett_rlc_lte_um_header);
2049 /*******************************/
2050 /* Fixed UM header */
2051 if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_5_BITS) {
2052 /* Framing info (2 bits) */
2053 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2054 tvb, offset*8, 2,
2055 &framing_info, ENC_BIG_ENDIAN);
2057 /* Extension (1 bit) */
2058 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2059 (offset*8) + 2, 1,
2060 &fixed_extension, ENC_BIG_ENDIAN);
2062 /* Sequence Number (5 bit) */
2063 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2064 (offset*8) + 3, 5,
2065 &sn, ENC_BIG_ENDIAN);
2066 offset++;
2068 else if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_10_BITS) {
2069 guint8 reserved;
2070 proto_item *ti;
2072 /* Check 3 Reserved bits */
2073 reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5;
2074 ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
2075 if (reserved != 0) {
2076 expert_add_info_format(pinfo, ti, &ei_rlc_lte_reserved_bits_not_zero,
2077 "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
2080 /* Framing info (2 bits) */
2081 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2082 tvb, (offset*8)+3, 2,
2083 &framing_info, ENC_BIG_ENDIAN);
2085 /* Extension (1 bit) */
2086 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2087 (offset*8) + 5, 1,
2088 &fixed_extension, ENC_BIG_ENDIAN);
2090 /* Sequence Number (10 bits) */
2091 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2092 (offset*8) + 6, 10,
2093 &sn, ENC_BIG_ENDIAN);
2094 offset += 2;
2096 else {
2097 /* Invalid length of sequence number */
2098 proto_tree_add_expert_format(um_header_tree, pinfo, &ei_rlc_lte_um_sn, tvb, 0, 0,
2099 "Invalid sequence number length (%u bits)",
2100 p_rlc_lte_info->UMSequenceNumberLength);
2101 return;
2104 tap_info->sequenceNumber = (guint16)sn;
2106 /* Show SN in info column */
2107 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2108 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (guint16)sn);
2110 else {
2111 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " sn=%-4u", (guint16)sn);
2114 proto_item_set_len(um_header_ti, offset-start_offset);
2117 /*************************************/
2118 /* UM header extension */
2119 if (fixed_extension) {
2120 offset = dissect_rlc_lte_extension_header(tvb, pinfo, um_header_tree, offset);
2123 /* Extract these 2 flags from framing_info */
2124 first_includes_start = ((guint8)framing_info & 0x02) == 0;
2125 last_includes_end = ((guint8)framing_info & 0x01) == 0;
2127 if (global_rlc_lte_headers_expected) {
2128 /* There might not be any data, if only headers (plus control data) were logged */
2129 is_truncated = (tvb_length_remaining(tvb, offset) == 0);
2130 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2131 is_truncated);
2132 if (is_truncated) {
2133 int n;
2134 PROTO_ITEM_SET_GENERATED(truncated_ti);
2135 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2137 /* Show in the info column how long the data would be */
2138 for (n=0; n < s_number_of_extensions; n++) {
2139 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2140 (n==0) ? first_includes_start : TRUE,
2141 TRUE);
2142 offset += s_lengths[n];
2144 /* Last one */
2145 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2146 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2147 last_includes_end);
2149 else {
2150 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2154 /* Show number of extensions in header root */
2155 if (s_number_of_extensions > 0) {
2156 proto_item_append_text(um_header_ti, " (%u extensions)", s_number_of_extensions);
2159 /* Call sequence analysis function now */
2160 if (((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2161 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) != NULL)) ||
2162 ((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2163 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) == NULL))) {
2165 guint16 lastSegmentOffset = offset;
2166 if (s_number_of_extensions >= 1) {
2167 int n;
2168 lastSegmentOffset = offset;
2169 for (n=0; n < s_number_of_extensions; n++) {
2170 lastSegmentOffset += s_lengths[n];
2174 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
2175 FALSE,
2176 s_number_of_extensions+1,
2177 offset,
2178 s_number_of_extensions ?
2179 s_lengths[0] :
2180 p_rlc_lte_info->pduLength - offset,
2181 lastSegmentOffset,
2182 (guint16)sn, first_includes_start, last_includes_end,
2183 FALSE, /* UM doesn't re-segment */
2184 tap_info, um_header_tree);
2187 if (is_truncated) {
2188 return;
2191 /*************************************/
2192 /* Data */
2194 reassembly_info = (rlc_channel_reassembly_info *)g_hash_table_lookup(reassembly_report_hash,
2195 get_report_hash_key((guint16)sn, pinfo->fd->num,
2196 p_rlc_lte_info, FALSE));
2198 if (s_number_of_extensions > 0) {
2199 /* Show each data segment separately */
2200 int n;
2201 for (n=0; n < s_number_of_extensions; n++) {
2202 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2203 (n==0) ? first_includes_start : TRUE,
2204 (n==0) ? reassembly_info : NULL,
2205 seq_anal_state);
2206 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2207 (n==0) ? first_includes_start : TRUE,
2208 TRUE);
2209 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2210 offset += s_lengths[n];
2214 /* Final data element */
2215 show_PDU_in_tree(pinfo, tree, tvb, offset, -1, p_rlc_lte_info,
2216 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2217 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2218 seq_anal_state);
2219 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
2220 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2221 last_includes_end);
2226 /* Dissect an AM STATUS PDU */
2227 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
2228 packet_info *pinfo,
2229 proto_tree *tree,
2230 proto_item *status_ti,
2231 int offset,
2232 proto_item *top_ti,
2233 rlc_lte_info *p_rlc_lte_info,
2234 rlc_lte_tap_info *tap_info)
2236 guint8 cpt;
2237 guint64 ack_sn, nack_sn;
2238 guint16 nack_count = 0;
2239 guint64 e1 = 0, e2 = 0;
2240 guint64 so_start, so_end;
2241 int bit_offset = offset * 8;
2242 proto_item *ti;
2244 /****************************************************************/
2245 /* Part of RLC control PDU header */
2247 /* Control PDU Type (CPT) */
2248 cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
2249 ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN);
2250 if (cpt != 0) {
2251 /* Protest and stop - only know about STATUS PDUs */
2252 expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_cpt,
2253 "RLC Control frame type %u not handled", cpt);
2254 return;
2257 /* The Status PDU itself starts 4 bits into the byte */
2258 bit_offset += 4;
2260 /* ACK SN */
2261 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2262 bit_offset, 10, &ack_sn, ENC_BIG_ENDIAN);
2263 bit_offset += 10;
2264 write_pdu_label_and_info(top_ti, status_ti, pinfo, " ACK_SN=%-4u", (guint16)ack_sn);
2266 tap_info->ACKNo = (guint16)ack_sn;
2268 /* E1 */
2269 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2270 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2272 /* Skip another bit to byte-align the next bit... */
2273 bit_offset++;
2275 /* Optional, extra fields */
2276 do {
2277 if (e1) {
2278 proto_item *nack_ti;
2280 /****************************/
2281 /* Read NACK_SN, E1, E2 */
2283 /* NACK_SN */
2284 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
2285 bit_offset, 10, &nack_sn, ENC_BIG_ENDIAN);
2286 bit_offset += 10;
2287 write_pdu_label_and_info(top_ti, NULL, pinfo, " NACK_SN=%-4u", (guint16)nack_sn);
2289 /* We shouldn't NACK the ACK_SN! */
2290 if (nack_sn == ack_sn) {
2291 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ack_same,
2292 "Status PDU shouldn't ACK and NACK the same sequence number (%" G_GINT64_MODIFIER "u)",
2293 ack_sn);
2296 /* NACK should always be 'behind' the ACK */
2297 if ((1024 + ack_sn - nack_sn) % 1024 > 512) {
2298 expert_add_info(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ahead_ack);
2301 /* Copy into struct, but don't exceed buffer */
2302 if (nack_count < MAX_NACKs) {
2303 tap_info->NACKs[nack_count++] = (guint16)nack_sn;
2305 else {
2306 /* Let it get bigger than the array for accurate stats... */
2307 nack_count++;
2310 /* E1 */
2311 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2312 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2313 bit_offset++;
2315 /* E2 */
2316 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
2317 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
2319 /* Report as expert info */
2320 if (e2) {
2321 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_partial,
2322 "Status PDU reports NACK (partial) on %s for UE %u",
2323 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2324 p_rlc_lte_info->ueid);
2326 else {
2327 expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn,
2328 "Status PDU reports NACK on %s for UE %u",
2329 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2330 p_rlc_lte_info->ueid);
2333 bit_offset++;
2336 if (e2) {
2337 /* Read SOstart, SOend */
2338 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
2339 bit_offset, 15, &so_start, ENC_BIG_ENDIAN);
2340 bit_offset += 15;
2342 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
2343 bit_offset, 15, &so_end, ENC_BIG_ENDIAN);
2344 bit_offset += 15;
2347 if ((guint16)so_end == 0x7fff) {
2348 write_pdu_label_and_info(top_ti, NULL, pinfo,
2349 " (SOstart=%u SOend=<END-OF_PDU>)",
2350 (guint16)so_start);
2352 else {
2353 write_pdu_label_and_info(top_ti, NULL, pinfo,
2354 " (SOstart=%u SOend=%u)",
2355 (guint16)so_start, (guint16)so_end);
2358 /* Reset this flag here */
2359 e2 = 0;
2361 } while (e1 || e2);
2363 if (nack_count > 0) {
2364 proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
2365 PROTO_ITEM_SET_GENERATED(count_ti);
2366 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
2367 tap_info->noOfNACKs = nack_count;
2370 /* Check that we've reached the end of the PDU. If not, show malformed */
2371 offset = (bit_offset+7) / 8;
2372 if (tvb_length_remaining(tvb, offset) > 0) {
2373 expert_add_info_format(pinfo, status_ti, &ei_rlc_lte_bytes_after_status_pdu_complete,
2374 "%cL %u bytes remaining after Status PDU complete",
2375 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2376 tvb_length_remaining(tvb, offset));
2379 /* Set selected length of control tree */
2380 proto_item_set_len(status_ti, offset);
2382 /* Repeated NACK analysis & check ACK-SN is in range */
2383 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2384 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) != NULL)) ||
2385 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2386 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) == NULL))) {
2388 if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2389 checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2390 checkChannelACKWindow((guint16)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2396 /***************************************************/
2397 /* Acknowledged mode PDU */
2398 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
2399 proto_tree *tree,
2400 int offset,
2401 rlc_lte_info *p_rlc_lte_info,
2402 proto_item *top_ti,
2403 rlc_lte_tap_info *tap_info)
2405 guint8 is_data;
2406 guint8 is_resegmented;
2407 guint8 polling;
2408 guint8 fixed_extension;
2409 guint8 framing_info;
2410 gboolean first_includes_start;
2411 gboolean last_includes_end;
2412 proto_item *am_ti;
2413 proto_tree *am_header_tree;
2414 proto_item *am_header_ti;
2415 gint start_offset = offset;
2416 guint16 sn;
2417 gboolean is_truncated = FALSE;
2418 proto_item *truncated_ti;
2419 rlc_channel_reassembly_info *reassembly_info = NULL;
2420 sequence_analysis_state seq_anal_state = SN_OK;
2422 /* Hidden AM root */
2423 am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2424 tvb, offset, 0, "", "AM");
2425 PROTO_ITEM_SET_HIDDEN(am_ti);
2427 /* Add AM header subtree */
2428 am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2429 tvb, offset, 0,
2430 "", "AM Header ");
2431 am_header_tree = proto_item_add_subtree(am_header_ti,
2432 ett_rlc_lte_am_header);
2434 /* First bit is Data/Control flag */
2435 is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
2436 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN);
2437 tap_info->isControlPDU = !is_data;
2439 if (!is_data) {
2440 /**********************/
2441 /* Status PDU */
2442 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
2444 /* Control PDUs are a completely separate format */
2445 dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2446 offset, top_ti,
2447 p_rlc_lte_info, tap_info);
2448 return;
2451 /******************************/
2452 /* Data PDU fixed header */
2454 /* Re-segmentation Flag (RF) field */
2455 is_resegmented = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
2456 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, ENC_BIG_ENDIAN);
2457 tap_info->isResegmented = is_resegmented;
2459 write_pdu_label_and_info_literal(top_ti, NULL, pinfo,
2460 (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2462 /* Polling bit */
2463 polling = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
2464 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, ENC_BIG_ENDIAN);
2466 write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : " ");
2467 if (polling) {
2468 proto_item_append_text(am_header_ti, " (P) ");
2471 /* Framing Info */
2472 framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3;
2473 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, ENC_BIG_ENDIAN);
2475 /* Extension bit */
2476 fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2;
2477 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, ENC_BIG_ENDIAN);
2479 /* Sequence Number */
2480 sn = tvb_get_ntohs(tvb, offset) & 0x03ff;
2481 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN);
2482 offset += 2;
2483 tap_info->sequenceNumber = sn;
2485 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2487 /***************************************/
2488 /* Dissect extra segment header fields */
2489 if (is_resegmented) {
2490 guint16 segmentOffset;
2492 /* Last Segment Field (LSF) */
2493 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2495 /* SO */
2496 segmentOffset = tvb_get_ntohs(tvb, offset) & 0x7fff;
2497 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN);
2498 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2499 offset += 2;
2502 /*************************************/
2503 /* AM header extension */
2504 if (fixed_extension) {
2505 offset = dissect_rlc_lte_extension_header(tvb, pinfo, am_header_tree, offset);
2508 /* Header is now complete */
2509 proto_item_set_len(am_header_ti, offset-start_offset);
2511 /* Show number of extensions in header root */
2512 if (s_number_of_extensions > 0) {
2513 proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2516 /* Extract these 2 flags from framing_info */
2517 first_includes_start = (framing_info & 0x02) == 0;
2518 last_includes_end = (framing_info & 0x01) == 0;
2520 /* There might not be any data, if only headers (plus control data) were logged */
2521 if (global_rlc_lte_headers_expected) {
2522 is_truncated = (tvb_length_remaining(tvb, offset) == 0);
2523 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2524 is_truncated);
2525 if (is_truncated) {
2526 int n;
2527 PROTO_ITEM_SET_GENERATED(truncated_ti);
2528 expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2529 /* Show in the info column how long the data would be */
2530 for (n=0; n < s_number_of_extensions; n++) {
2531 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2532 (n==0) ? first_includes_start : TRUE,
2533 TRUE);
2534 offset += s_lengths[n];
2536 /* Last one */
2537 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2538 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2539 last_includes_end);
2541 else {
2542 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2546 /* Call sequence analysis function now */
2547 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2548 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) != NULL)) ||
2549 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2550 (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) == NULL))) {
2552 guint16 firstSegmentLength;
2553 guint16 lastSegmentOffset = offset;
2554 if (s_number_of_extensions >= 1) {
2555 int n;
2556 for (n=0; n < s_number_of_extensions; n++) {
2557 lastSegmentOffset += s_lengths[n];
2560 firstSegmentLength = s_lengths[0];
2562 else {
2563 firstSegmentLength = tvb_length_remaining(tvb, offset);
2566 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, FALSE,
2567 s_number_of_extensions+1,
2568 offset, firstSegmentLength,
2569 lastSegmentOffset,
2570 (guint16)sn,
2571 first_includes_start, last_includes_end,
2572 is_resegmented, tap_info, tree);
2575 if (is_truncated) {
2576 return;
2579 /*************************************/
2580 /* Data */
2582 reassembly_info = (rlc_channel_reassembly_info *)g_hash_table_lookup(reassembly_report_hash,
2583 get_report_hash_key((guint16)sn, pinfo->fd->num,
2584 p_rlc_lte_info, FALSE));
2586 if (s_number_of_extensions > 0) {
2587 /* Show each data segment separately */
2588 int n;
2589 for (n=0; n < s_number_of_extensions; n++) {
2590 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2591 (n==0) ? first_includes_start : TRUE,
2592 (n==0) ? reassembly_info : NULL,
2593 seq_anal_state);
2594 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2595 (n==0) ? first_includes_start : TRUE,
2596 TRUE);
2597 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2598 offset += s_lengths[n];
2602 /* Final data element */
2603 if (tvb_length_remaining(tvb, offset) > 0) {
2604 show_PDU_in_tree(pinfo, tree, tvb, offset, -1, p_rlc_lte_info,
2605 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2606 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2607 seq_anal_state);
2608 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
2609 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2610 last_includes_end);
2612 else {
2613 /* Report that expected data was missing (unless we know it might happen) */
2614 if (!global_rlc_lte_headers_expected) {
2615 if (s_number_of_extensions > 0) {
2616 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data_beyond_extensions);
2618 else {
2619 expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data);
2626 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2627 static gboolean dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
2628 proto_tree *tree, void *data _U_)
2630 gint offset = 0;
2631 struct rlc_lte_info *p_rlc_lte_info;
2632 tvbuff_t *rlc_tvb;
2633 guint8 tag = 0;
2634 gboolean infoAlreadySet = FALSE;
2635 gboolean umSeqNumLengthTagPresent = FALSE;
2637 /* This is a heuristic dissector, which means we get all the UDP
2638 * traffic not sent to a known dissector and not claimed by
2639 * a heuristic dissector called before us!
2642 if (!global_rlc_lte_heur) {
2643 return FALSE;
2646 /* Do this again on re-dissection to re-discover offset of actual PDU */
2648 /* Needs to be at least as long as:
2649 - the signature string
2650 - fixed header bytes
2651 - tag for data
2652 - at least one byte of RLC PDU payload */
2653 if (tvb_length_remaining(tvb, offset) < (gint)(strlen(RLC_LTE_START_STRING)+1+2)) {
2654 return FALSE;
2657 /* OK, compare with signature string */
2658 if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (gint)strlen(RLC_LTE_START_STRING)) != 0) {
2659 return FALSE;
2661 offset += (gint)strlen(RLC_LTE_START_STRING);
2664 /* If redissecting, use previous info struct (if available) */
2665 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(pinfo->fd, proto_rlc_lte, 0);
2666 if (p_rlc_lte_info == NULL) {
2667 /* Allocate new info struct for this frame */
2668 p_rlc_lte_info = wmem_new0(wmem_file_scope(), struct rlc_lte_info);
2669 infoAlreadySet = FALSE;
2671 else {
2672 infoAlreadySet = TRUE;
2676 /* Read fixed fields */
2677 p_rlc_lte_info->rlcMode = tvb_get_guint8(tvb, offset++);
2679 /* Read optional fields */
2680 while (tag != RLC_LTE_PAYLOAD_TAG) {
2681 /* Process next tag */
2682 tag = tvb_get_guint8(tvb, offset++);
2683 switch (tag) {
2684 case RLC_LTE_UM_SN_LENGTH_TAG:
2685 p_rlc_lte_info->UMSequenceNumberLength = tvb_get_guint8(tvb, offset);
2686 offset++;
2687 umSeqNumLengthTagPresent = TRUE;
2688 break;
2689 case RLC_LTE_DIRECTION_TAG:
2690 p_rlc_lte_info->direction = tvb_get_guint8(tvb, offset);
2691 offset++;
2692 break;
2693 case RLC_LTE_PRIORITY_TAG:
2694 p_rlc_lte_info->priority = tvb_get_guint8(tvb, offset);
2695 offset++;
2696 break;
2697 case RLC_LTE_UEID_TAG:
2698 p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
2699 offset += 2;
2700 break;
2701 case RLC_LTE_CHANNEL_TYPE_TAG:
2702 p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
2703 offset += 2;
2704 break;
2705 case RLC_LTE_CHANNEL_ID_TAG:
2706 p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
2707 offset += 2;
2708 break;
2710 case RLC_LTE_PAYLOAD_TAG:
2711 /* Have reached data, so set payload length and get out of loop */
2712 p_rlc_lte_info->pduLength= tvb_length_remaining(tvb, offset);
2713 continue;
2715 default:
2716 /* It must be a recognised tag */
2717 return FALSE;
2721 if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (umSeqNumLengthTagPresent == FALSE)) {
2722 /* Conditional field is not present */
2723 return FALSE;
2726 if (!infoAlreadySet) {
2727 /* Store info in packet */
2728 p_add_proto_data(pinfo->fd, proto_rlc_lte, 0, p_rlc_lte_info);
2731 /**************************************/
2732 /* OK, now dissect as RLC LTE */
2734 /* Create tvb that starts at actual RLC PDU */
2735 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
2736 dissect_rlc_lte_common(rlc_tvb, pinfo, tree, TRUE);
2737 return TRUE;
2742 /*****************************/
2743 /* Main dissection function. */
2744 /*****************************/
2746 static void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2748 dissect_rlc_lte_common(tvb, pinfo, tree, FALSE);
2751 static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_udp_framing)
2753 proto_tree *rlc_lte_tree;
2754 proto_tree *context_tree;
2755 proto_item *top_ti;
2756 proto_item *context_ti;
2757 proto_item *ti;
2758 proto_item *mode_ti;
2759 gint offset = 0;
2760 struct rlc_lte_info *p_rlc_lte_info = NULL;
2762 /* Allocate and Zero tap struct */
2763 rlc_lte_tap_info *tap_info = wmem_new0(wmem_packet_scope(), rlc_lte_tap_info);
2765 /* Set protocol name */
2766 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2768 /* Create protocol tree. */
2769 top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2770 rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2773 /* Look for packet info! */
2774 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(pinfo->fd, proto_rlc_lte, 0);
2776 /* Can't dissect anything without it... */
2777 if (p_rlc_lte_info == NULL) {
2778 ti = proto_tree_add_text(rlc_lte_tree, tvb, offset, -1,
2779 "Can't dissect LTE RLC frame because no per-frame info was attached!");
2780 PROTO_ITEM_SET_GENERATED(ti);
2781 return;
2784 /* Clear info column when using UDP framing */
2785 if (is_udp_framing) {
2786 col_clear(pinfo->cinfo, COL_INFO);
2789 /*****************************************/
2790 /* Show context information */
2792 /* Create context root */
2793 context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2794 tvb, offset, 0, "", "Context");
2795 context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2796 PROTO_ITEM_SET_GENERATED(context_ti);
2798 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2799 tvb, 0, 0, p_rlc_lte_info->direction);
2800 PROTO_ITEM_SET_GENERATED(ti);
2802 mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2803 tvb, 0, 0, p_rlc_lte_info->rlcMode);
2804 PROTO_ITEM_SET_GENERATED(mode_ti);
2806 if (p_rlc_lte_info->ueid != 0) {
2807 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_ueid,
2808 tvb, 0, 0, p_rlc_lte_info->ueid);
2809 PROTO_ITEM_SET_GENERATED(ti);
2812 if ((p_rlc_lte_info->priority >= 1) && (p_rlc_lte_info->priority <=16)) {
2813 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_priority,
2814 tvb, 0, 0, p_rlc_lte_info->priority);
2815 PROTO_ITEM_SET_GENERATED(ti);
2818 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2819 tvb, 0, 0, p_rlc_lte_info->channelType);
2820 PROTO_ITEM_SET_GENERATED(ti);
2822 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2823 (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB) ||
2824 (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2825 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2826 tvb, 0, 0, p_rlc_lte_info->channelId);
2827 PROTO_ITEM_SET_GENERATED(ti);
2830 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2831 tvb, 0, 0, p_rlc_lte_info->pduLength);
2832 PROTO_ITEM_SET_GENERATED(ti);
2834 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
2835 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_um_sn_length,
2836 tvb, 0, 0, p_rlc_lte_info->UMSequenceNumberLength);
2837 PROTO_ITEM_SET_GENERATED(ti);
2840 /* Append highlights to top-level item */
2841 if (p_rlc_lte_info->ueid != 0) {
2842 proto_item_append_text(top_ti, " UEId=%u", p_rlc_lte_info->ueid);
2845 /* Append context highlights to info column */
2846 write_pdu_label_and_info(top_ti, NULL, pinfo,
2847 " [%s] [%s] ",
2848 (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
2849 val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
2850 if (p_rlc_lte_info->ueid != 0) {
2851 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%-4u ", p_rlc_lte_info->ueid);
2853 if (p_rlc_lte_info->channelId == 0) {
2854 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s ",
2855 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
2857 else {
2858 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
2859 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
2860 p_rlc_lte_info->channelId);
2863 /* Set context-info parts of tap struct */
2864 tap_info->rlcMode = p_rlc_lte_info->rlcMode;
2865 tap_info->direction = p_rlc_lte_info->direction;
2866 tap_info->priority = p_rlc_lte_info->priority;
2867 tap_info->ueid = p_rlc_lte_info->ueid;
2868 tap_info->channelType = p_rlc_lte_info->channelType;
2869 tap_info->channelId = p_rlc_lte_info->channelId;
2870 tap_info->pduLength = p_rlc_lte_info->pduLength;
2871 tap_info->UMSequenceNumberLength = p_rlc_lte_info->UMSequenceNumberLength;
2872 tap_info->loggedInMACFrame = (p_get_proto_data(pinfo->fd, proto_mac_lte, 0) != NULL);
2874 tap_info->time = pinfo->fd->abs_ts;
2876 /* Reset this count */
2877 s_number_of_extensions = 0;
2879 /* Dissect the RLC PDU itself. Format depends upon mode... */
2880 switch (p_rlc_lte_info->rlcMode) {
2882 case RLC_TM_MODE:
2883 dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
2884 break;
2886 case RLC_UM_MODE:
2887 dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
2888 tap_info);
2889 break;
2891 case RLC_AM_MODE:
2892 dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
2893 tap_info);
2894 break;
2896 case RLC_PREDEF:
2897 /* Predefined data (i.e. not containing a valid RLC header */
2898 proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, ENC_NA);
2899 write_pdu_label_and_info(top_ti, NULL, pinfo, " [%u-bytes]",
2900 tvb_length_remaining(tvb, offset));
2901 break;
2903 default:
2904 /* Error - unrecognised mode */
2905 expert_add_info_format(pinfo, mode_ti, &ei_rlc_lte_context_mode,
2906 "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
2907 break;
2910 /* Queue tap info */
2911 tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
2916 /* Initializes the hash tables each time a new
2917 * file is loaded or re-loaded in wireshark */
2918 static void
2919 rlc_lte_init_protocol(void)
2921 /* Destroy any existing hashes. */
2922 if (sequence_analysis_channel_hash) {
2923 g_hash_table_destroy(sequence_analysis_channel_hash);
2925 if (sequence_analysis_report_hash) {
2926 g_hash_table_destroy(sequence_analysis_report_hash);
2928 if (repeated_nack_channel_hash) {
2929 g_hash_table_destroy(repeated_nack_channel_hash);
2931 if (repeated_nack_report_hash) {
2932 g_hash_table_destroy(repeated_nack_report_hash);
2934 if (reassembly_report_hash) {
2935 g_hash_table_destroy(reassembly_report_hash);
2938 /* Now create them over */
2939 sequence_analysis_channel_hash = g_hash_table_new(rlc_channel_hash_func, rlc_channel_equal);
2940 sequence_analysis_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2942 repeated_nack_channel_hash = g_hash_table_new(rlc_channel_hash_func, rlc_channel_equal);
2943 repeated_nack_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2944 reassembly_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2948 /* Configure number of PDCP SN bits to use for DRB channels.
2949 TODO: currently assume all UEs/Channels will use the same length... */
2950 void set_rlc_lte_drb_pdcp_seqnum_length(guint16 ueid _U_, guint8 drbid _U_,
2951 guint8 userplane_seqnum_length)
2953 signalled_pdcp_sn_bits = userplane_seqnum_length;
2957 void proto_register_rlc_lte(void)
2959 static hf_register_info hf[] =
2961 /**********************************/
2962 /* Items for decoding context */
2963 { &hf_rlc_lte_context,
2964 { "Context",
2965 "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
2966 NULL, HFILL
2969 { &hf_rlc_lte_context_mode,
2970 { "RLC Mode",
2971 "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
2972 NULL, HFILL
2975 { &hf_rlc_lte_context_direction,
2976 { "Direction",
2977 "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2978 "Direction of message", HFILL
2981 { &hf_rlc_lte_context_priority,
2982 { "Priority",
2983 "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
2984 NULL, HFILL
2987 { &hf_rlc_lte_context_ueid,
2988 { "UEId",
2989 "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
2990 "User Equipment Identifier associated with message", HFILL
2993 { &hf_rlc_lte_context_channel_type,
2994 { "Channel Type",
2995 "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
2996 "Channel Type associated with message", HFILL
2999 { &hf_rlc_lte_context_channel_id,
3000 { "Channel ID",
3001 "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
3002 "Channel ID associated with message", HFILL
3005 { &hf_rlc_lte_context_pdu_length,
3006 { "PDU Length",
3007 "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
3008 "Length of PDU (in bytes)", HFILL
3011 { &hf_rlc_lte_context_um_sn_length,
3012 { "UM Sequence number length",
3013 "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3014 "Length of UM sequence number in bits", HFILL
3018 /* Transparent mode fields */
3019 { &hf_rlc_lte_tm,
3020 { "TM",
3021 "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
3022 "Transparent Mode", HFILL
3025 { &hf_rlc_lte_tm_data,
3026 { "TM Data",
3027 "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
3028 "Transparent Mode Data", HFILL
3032 /* Unacknowledged mode fields */
3033 { &hf_rlc_lte_um,
3034 { "UM",
3035 "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
3036 "Unacknowledged Mode", HFILL
3039 { &hf_rlc_lte_um_header,
3040 { "UM Header",
3041 "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
3042 "Unacknowledged Mode Header", HFILL
3045 { &hf_rlc_lte_um_fi,
3046 { "Framing Info",
3047 "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
3048 NULL, HFILL
3051 { &hf_rlc_lte_um_fixed_e,
3052 { "Extension",
3053 "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
3054 "Extension in fixed part of UM header", HFILL
3057 { &hf_rlc_lte_um_sn,
3058 { "Sequence number",
3059 "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
3060 "Unacknowledged Mode Sequence Number", HFILL
3063 { &hf_rlc_lte_um_fixed_reserved,
3064 { "Reserved",
3065 "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
3066 "Unacknowledged Mode Fixed header reserved bits", HFILL
3069 { &hf_rlc_lte_um_data,
3070 { "UM Data",
3071 "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
3072 "Unacknowledged Mode Data", HFILL
3075 { &hf_rlc_lte_extension_part,
3076 { "Extension Part",
3077 "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
3078 NULL, HFILL
3081 { &hf_rlc_lte_extension_e,
3082 { "Extension",
3083 "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
3084 "Extension in extended part of the header", HFILL
3087 { &hf_rlc_lte_extension_li,
3088 { "Length Indicator",
3089 "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
3090 NULL, HFILL
3093 { &hf_rlc_lte_extension_padding,
3094 { "Padding",
3095 "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
3096 "Extension header padding", HFILL
3100 { &hf_rlc_lte_am,
3101 { "AM",
3102 "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
3103 "Acknowledged Mode", HFILL
3106 { &hf_rlc_lte_am_header,
3107 { "AM Header",
3108 "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
3109 "Acknowledged Mode Header", HFILL
3112 { &hf_rlc_lte_am_data_control,
3113 { "Frame type",
3114 "rlc-lte.am.frame-type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80,
3115 "AM Frame Type (Control or Data)", HFILL
3118 { &hf_rlc_lte_am_rf,
3119 { "Re-segmentation Flag",
3120 "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
3121 "AM Re-segmentation Flag", HFILL
3124 { &hf_rlc_lte_am_p,
3125 { "Polling Bit",
3126 "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
3127 NULL, HFILL
3130 { &hf_rlc_lte_am_fi,
3131 { "Framing Info",
3132 "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
3133 "AM Framing Info", HFILL
3136 { &hf_rlc_lte_am_fixed_e,
3137 { "Extension",
3138 "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
3139 "Fixed Extension Bit", HFILL
3142 { &hf_rlc_lte_am_fixed_sn,
3143 { "Sequence Number",
3144 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
3145 "AM Fixed Sequence Number", HFILL
3148 { &hf_rlc_lte_am_segment_lsf,
3149 { "Last Segment Flag",
3150 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3151 NULL, HFILL
3154 { &hf_rlc_lte_am_segment_so,
3155 { "Segment Offset",
3156 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3157 NULL, HFILL
3160 { &hf_rlc_lte_am_data,
3161 { "AM Data",
3162 "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3163 "Acknowledged Mode Data", HFILL
3167 { &hf_rlc_lte_am_cpt,
3168 { "Control PDU Type",
3169 "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3170 "AM Control PDU Type", HFILL
3173 { &hf_rlc_lte_am_ack_sn,
3174 { "ACK Sequence Number",
3175 "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3176 "Sequence Number we expect to receive next", HFILL
3179 { &hf_rlc_lte_am_e1,
3180 { "Extension bit 1",
3181 "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3182 NULL, HFILL
3185 { &hf_rlc_lte_am_e2,
3186 { "Extension bit 2",
3187 "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3188 NULL, HFILL
3191 { &hf_rlc_lte_am_nacks,
3192 { "Number of NACKs",
3193 "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3194 "Number of NACKs in this status PDU", HFILL
3197 { &hf_rlc_lte_am_nack_sn,
3198 { "NACK Sequence Number",
3199 "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3200 "Negative Acknowledgement Sequence Number", HFILL
3203 { &hf_rlc_lte_am_so_start,
3204 { "SO Start",
3205 "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3206 "Segment Offset Start byte index", HFILL
3209 { &hf_rlc_lte_am_so_end,
3210 { "SO End",
3211 "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3212 "Segment Offset End byte index", HFILL
3216 { &hf_rlc_lte_predefined_pdu,
3217 { "Predefined data",
3218 "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3219 "Predefined test data", HFILL
3223 { &hf_rlc_lte_sequence_analysis,
3224 { "Sequence Analysis",
3225 "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3226 NULL, HFILL
3229 { &hf_rlc_lte_sequence_analysis_ok,
3230 { "OK",
3231 "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3232 NULL, HFILL
3235 { &hf_rlc_lte_sequence_analysis_previous_frame,
3236 { "Previous frame for channel",
3237 "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3238 NULL, HFILL
3241 { &hf_rlc_lte_sequence_analysis_next_frame,
3242 { "Next frame for channel",
3243 "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3244 NULL, HFILL
3247 { &hf_rlc_lte_sequence_analysis_expected_sn,
3248 { "Expected SN",
3249 "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3250 NULL, HFILL
3253 { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3254 { "Frame info continued correctly",
3255 "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3256 NULL, HFILL
3259 { &hf_rlc_lte_sequence_analysis_mac_retx,
3260 { "Frame retransmitted by MAC",
3261 "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3262 NULL, HFILL
3265 { &hf_rlc_lte_sequence_analysis_retx,
3266 { "Retransmitted frame",
3267 "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3268 NULL, HFILL
3271 { &hf_rlc_lte_sequence_analysis_skipped,
3272 { "Skipped frames",
3273 "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3274 NULL, HFILL
3277 { &hf_rlc_lte_sequence_analysis_repeated,
3278 { "Repeated frame",
3279 "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3280 NULL, HFILL
3283 { &hf_rlc_lte_sequence_analysis_repeated_nack,
3284 { "Repeated NACK",
3285 "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3286 NULL, HFILL
3289 { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3290 { "Frame with previous status PDU",
3291 "rlc-lte.sequence-analysis.repeated-nack.original-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3292 NULL, HFILL
3296 { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3297 { "Out of range ACK",
3298 "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3299 NULL, HFILL
3302 { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3303 { "Frame with most recent SN",
3304 "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3305 NULL, HFILL
3309 { &hf_rlc_lte_reassembly_source,
3310 { "Reassembly Source",
3311 "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3312 NULL, HFILL
3315 { &hf_rlc_lte_reassembly_source_number_of_segments,
3316 { "Number of segments",
3317 "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3318 NULL, HFILL
3321 { &hf_rlc_lte_reassembly_source_total_length,
3322 { "Total length",
3323 "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3324 NULL, HFILL
3327 { &hf_rlc_lte_reassembly_source_segment,
3328 { "Segment",
3329 "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3330 NULL, HFILL
3333 { &hf_rlc_lte_reassembly_source_segment_sn,
3334 { "SN",
3335 "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3336 NULL, HFILL
3339 { &hf_rlc_lte_reassembly_source_segment_framenum,
3340 { "Frame",
3341 "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3342 NULL, HFILL
3345 { &hf_rlc_lte_reassembly_source_segment_length,
3346 { "Length",
3347 "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3348 NULL, HFILL
3352 { &hf_rlc_lte_header_only,
3353 { "RLC PDU Header only",
3354 "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3355 NULL, HFILL
3360 static gint *ett[] =
3362 &ett_rlc_lte,
3363 &ett_rlc_lte_context,
3364 &ett_rlc_lte_um_header,
3365 &ett_rlc_lte_am_header,
3366 &ett_rlc_lte_extension_part,
3367 &ett_rlc_lte_sequence_analysis,
3368 &ett_rlc_lte_reassembly_source,
3369 &ett_rlc_lte_reassembly_source_segment
3372 static ei_register_info ei[] = {
3373 { &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 }},
3374 { &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 }},
3375 { &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 }},
3376 { &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 }},
3377 { &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 }},
3378 { &ei_rlc_lte_am_sn_missing, { "rlc_lte.sequence-analysis.am_sn.missing", PI_SEQUENCE, PI_WARN, "AM SNs missing", EXPFILL }},
3379 { &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 }},
3380 { &ei_rlc_lte_um_sn_missing, { "rlc_lte.sequence-analysis.um_sn.missing", PI_SEQUENCE, PI_WARN, "UM SNs missing", EXPFILL }},
3381 { &ei_rlc_lte_um_sn_repeated, { "rlc_lte.sequence-analysis.um_sn.repeated", PI_SEQUENCE, PI_WARN, "UM SN repeated", EXPFILL }},
3382 { &ei_rlc_lte_wrong_sequence_number, { "rlc_lte.wrong_sequence_number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
3383 { &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 }},
3384 { &ei_rlc_lte_reserved_bits_not_zero, { "rlc_lte.reserved_bits_not_zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
3385 { &ei_rlc_lte_um_sn, { "rlc-lte.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
3386 { &ei_rlc_lte_header_only, { "rlc-lte.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3387 { &ei_rlc_lte_am_cpt, { "rlc-lte.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
3388 { &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 }},
3389 { &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 }},
3390 { &ei_rlc_lte_am_nack_sn_partial, { "rlc-lte.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
3391 { &ei_rlc_lte_am_nack_sn, { "rlc-lte.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
3392 { &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 }},
3393 { &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 }},
3394 { &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 }},
3395 { &ei_rlc_lte_context_mode, { "rlc-lte.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
3398 static const enum_val_t sequence_analysis_vals[] = {
3399 {"no-analysis", "No-Analysis", FALSE},
3400 {"mac-only", "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3401 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3402 {NULL, NULL, -1}
3405 module_t *rlc_lte_module;
3406 expert_module_t* expert_rlc_lte;
3408 /* Register protocol. */
3409 proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3410 proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3411 proto_register_subtree_array(ett, array_length(ett));
3412 expert_rlc_lte = expert_register_protocol(proto_rlc_lte);
3413 expert_register_field_array(expert_rlc_lte, ei, array_length(ei));
3415 /* Allow other dissectors to find this one by name. */
3416 register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3418 /* Register the tap name */
3419 rlc_lte_tap = register_tap("rlc-lte");
3421 /* Preferences */
3422 rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3424 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3425 "Do sequence analysis for AM channels",
3426 "Attempt to keep track of PDUs for AM channels, and point out problems",
3427 &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, FALSE);
3429 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3430 "Do sequence analysis for UM channels",
3431 "Attempt to keep track of PDUs for UM channels, and point out problems",
3432 &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, FALSE);
3434 prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3435 "Call PDCP dissector for SRB PDUs",
3436 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
3437 "only be called for complete PDUs (i.e. not segmented over RLC)",
3438 &global_rlc_lte_call_pdcp_for_srb);
3440 prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3441 "Call PDCP dissector for DRB PDUs",
3442 "Call PDCP dissector for user-plane PDUs. Note that without reassembly, it can"
3443 "only be called for complete PDUs (i.e. not segmented over RLC)",
3444 &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, FALSE);
3447 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3448 "Call RRC dissector for CCCH PDUs",
3449 "Call RRC dissector for CCCH PDUs",
3450 &global_rlc_lte_call_rrc_for_ccch);
3452 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_mcch",
3453 "Call RRC dissector for MCCH PDUs",
3454 "Call RRC dissector for MCCH PDUs Note that without reassembly, it can"
3455 "only be called for complete PDUs (i.e. not segmented over RLC)",
3456 &global_rlc_lte_call_rrc_for_mcch);
3458 prefs_register_bool_preference(rlc_lte_module, "call_ip_for_mtch",
3459 "Call IP dissector for MTCH PDUs",
3460 "Call ip dissector for MTCH PDUs Note that without reassembly, it can"
3461 "only be called for complete PDUs (i.e. not segmented over RLC)",
3462 &global_rlc_lte_call_ip_for_mtch);
3464 prefs_register_bool_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp",
3465 "Try Heuristic LTE-RLC over UDP framing",
3466 "When enabled, use heuristic dissector to find RLC-LTE frames sent with "
3467 "UDP framing",
3468 &global_rlc_lte_heur);
3470 prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3471 "May see RLC headers only",
3472 "When enabled, if data is not present, don't report as an error, but instead "
3473 "add expert info to indicate that headers were omitted",
3474 &global_rlc_lte_headers_expected);
3476 prefs_register_bool_preference(rlc_lte_module, "reassembly",
3477 "Attempt SDU reassembly",
3478 "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3479 "more than one RLC PDU. Note: does not currently support out-of-order or "
3480 "re-segmentation. N.B. sequence analysis must also be turned on in order "
3481 "for reassembly to work",
3482 &global_rlc_lte_reassembly);
3485 register_init_routine(&rlc_lte_init_protocol);
3488 void
3489 proto_reg_handoff_rlc_lte(void)
3491 /* Add as a heuristic UDP dissector */
3492 heur_dissector_add("udp", dissect_rlc_lte_heur, proto_rlc_lte);
3494 pdcp_lte_handle = find_dissector("pdcp-lte");
3495 ip_handle = find_dissector("ip");