1 /* Routines for LTE RLC disassembly
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include <epan/expert.h>
34 #include <epan/prefs.h>
37 #include "packet-mac-lte.h"
38 #include "packet-rlc-lte.h"
39 #include "packet-pdcp-lte.h"
43 * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA)
44 * Radio Link Control (RLC) Protocol specification
48 - add intermediate results to segments leading to final reassembly
49 - use multiple active rlc_channel_reassembly_info's per channel
50 - sequence analysis gets confused when we change cells and skip back
51 to SN 0. Maybe add cell-id to context and add to channel/result key?
54 /********************************/
55 /* Preference settings */
57 #define SEQUENCE_ANALYSIS_MAC_ONLY 1
58 #define SEQUENCE_ANALYSIS_RLC_ONLY 2
60 /* By default don't try to analyse the sequence of messages for AM/UM channels */
61 static gint global_rlc_lte_am_sequence_analysis = FALSE;
62 static gint global_rlc_lte_um_sequence_analysis = FALSE;
64 /* By default don't call PDCP/RRC dissectors for SDU data */
65 static gboolean global_rlc_lte_call_pdcp_for_srb = FALSE;
67 enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12, PDCP_drb_SN_signalled};
68 static enum_val_t pdcp_drb_col_vals[] = {
69 {"pdcp-drb-off", "Off", PDCP_drb_off},
70 {"pdcp-drb-sn-7", "7-bit SN", PDCP_drb_SN_7},
71 {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
72 {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
75 static gint global_rlc_lte_call_pdcp_for_drb = (gint)PDCP_drb_off;
76 static gint signalled_pdcp_sn_bits = 12;
78 static gboolean global_rlc_lte_call_rrc = FALSE;
80 /* Preference to expect RLC headers without payloads */
81 static gboolean global_rlc_lte_headers_expected = FALSE;
83 /* Heuristic dissection */
84 static gboolean global_rlc_lte_heur = FALSE;
86 /* Re-assembly of segments */
87 static gboolean global_rlc_lte_reassembly = FALSE;
89 /**************************************************/
90 /* Initialize the protocol and registered fields. */
91 int proto_rlc_lte = -1;
93 extern int proto_mac_lte;
94 extern int proto_pdcp_lte;
96 static int rlc_lte_tap = -1;
98 /* Decoding context */
99 static int hf_rlc_lte_context = -1;
100 static int hf_rlc_lte_context_mode = -1;
101 static int hf_rlc_lte_context_direction = -1;
102 static int hf_rlc_lte_context_priority = -1;
103 static int hf_rlc_lte_context_ueid = -1;
104 static int hf_rlc_lte_context_channel_type = -1;
105 static int hf_rlc_lte_context_channel_id = -1;
106 static int hf_rlc_lte_context_pdu_length = -1;
107 static int hf_rlc_lte_context_um_sn_length = -1;
109 /* Transparent mode fields */
110 static int hf_rlc_lte_tm = -1;
111 static int hf_rlc_lte_tm_data = -1;
113 /* Unacknowledged mode fields */
114 static int hf_rlc_lte_um = -1;
115 static int hf_rlc_lte_um_header = -1;
116 static int hf_rlc_lte_um_fi = -1;
117 static int hf_rlc_lte_um_fixed_e = -1;
118 static int hf_rlc_lte_um_sn = -1;
119 static int hf_rlc_lte_um_fixed_reserved = -1;
120 static int hf_rlc_lte_um_data = -1;
121 static int hf_rlc_lte_extension_part = -1;
123 /* Extended header (common to UM and AM) */
124 static int hf_rlc_lte_extension_e = -1;
125 static int hf_rlc_lte_extension_li = -1;
126 static int hf_rlc_lte_extension_padding = -1;
129 /* Acknowledged mode fields */
130 static int hf_rlc_lte_am = -1;
131 static int hf_rlc_lte_am_header = -1;
132 static int hf_rlc_lte_am_data_control = -1;
133 static int hf_rlc_lte_am_rf = -1;
134 static int hf_rlc_lte_am_p = -1;
135 static int hf_rlc_lte_am_fi = -1;
136 static int hf_rlc_lte_am_fixed_e = -1;
137 static int hf_rlc_lte_am_fixed_sn = -1;
138 static int hf_rlc_lte_am_segment_lsf = -1;
139 static int hf_rlc_lte_am_segment_so = -1;
140 static int hf_rlc_lte_am_data = -1;
143 static int hf_rlc_lte_am_cpt = -1;
144 static int hf_rlc_lte_am_ack_sn = -1;
145 static int hf_rlc_lte_am_e1 = -1;
146 static int hf_rlc_lte_am_e2 = -1;
147 static int hf_rlc_lte_am_nack_sn = -1;
148 static int hf_rlc_lte_am_nacks = -1;
149 static int hf_rlc_lte_am_so_start = -1;
150 static int hf_rlc_lte_am_so_end = -1;
152 static int hf_rlc_lte_predefined_pdu = -1;
153 static int hf_rlc_lte_header_only = -1;
155 /* Sequence Analysis */
156 static int hf_rlc_lte_sequence_analysis = -1;
157 static int hf_rlc_lte_sequence_analysis_ok = -1;
158 static int hf_rlc_lte_sequence_analysis_previous_frame = -1;
159 static int hf_rlc_lte_sequence_analysis_next_frame = -1;
160 static int hf_rlc_lte_sequence_analysis_expected_sn = -1;
161 static int hf_rlc_lte_sequence_analysis_framing_info_correct = -1;
163 static int hf_rlc_lte_sequence_analysis_mac_retx = -1;
164 static int hf_rlc_lte_sequence_analysis_retx = -1;
165 static int hf_rlc_lte_sequence_analysis_repeated = -1;
166 static int hf_rlc_lte_sequence_analysis_skipped = -1;
168 static int hf_rlc_lte_sequence_analysis_repeated_nack = -1;
169 static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame = -1;
171 static int hf_rlc_lte_sequence_analysis_ack_out_of_range = -1;
172 static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = -1;
175 static int hf_rlc_lte_reassembly_source = -1;
176 static int hf_rlc_lte_reassembly_source_number_of_segments = -1;
177 static int hf_rlc_lte_reassembly_source_total_length = -1;
178 static int hf_rlc_lte_reassembly_source_segment = -1;
179 static int hf_rlc_lte_reassembly_source_segment_sn = -1;
180 static int hf_rlc_lte_reassembly_source_segment_framenum = -1;
181 static int hf_rlc_lte_reassembly_source_segment_length = -1;
184 static int ett_rlc_lte = -1;
185 static int ett_rlc_lte_context = -1;
186 static int ett_rlc_lte_um_header = -1;
187 static int ett_rlc_lte_am_header = -1;
188 static int ett_rlc_lte_extension_part = -1;
189 static int ett_rlc_lte_sequence_analysis = -1;
190 static int ett_rlc_lte_reassembly_source = -1;
191 static int ett_rlc_lte_reassembly_source_segment = -1;
194 static const value_string direction_vals[] =
196 { DIRECTION_UPLINK, "Uplink"},
197 { DIRECTION_DOWNLINK, "Downlink"},
201 static const value_string rlc_mode_short_vals[] =
203 { RLC_TM_MODE, "TM"},
204 { RLC_UM_MODE, "UM"},
205 { RLC_AM_MODE, "AM"},
206 { RLC_PREDEF, "PREDEFINED"}, /* For data testing */
210 static const value_string rlc_mode_vals[] =
212 { RLC_TM_MODE, "Transparent Mode"},
213 { RLC_UM_MODE, "Unacknowledged Mode"},
214 { RLC_AM_MODE, "Acknowledged Mode"},
218 static const value_string rlc_channel_type_vals[] =
220 { CHANNEL_TYPE_CCCH, "CCCH"},
221 { CHANNEL_TYPE_BCCH_BCH, "BCCH_BCH"},
222 { CHANNEL_TYPE_PCCH, "PCCH"},
223 { CHANNEL_TYPE_SRB, "SRB"},
224 { CHANNEL_TYPE_DRB, "DRB"},
225 { CHANNEL_TYPE_BCCH_DL_SCH, "BCCH_DL_SCH"},
229 static const value_string framing_info_vals[] =
231 { 0, "First byte begins a RLC SDU and last byte ends a RLC SDU"},
232 { 1, "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
233 { 2, "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
234 { 3, "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
238 static const value_string fixed_extension_vals[] =
240 { 0, "Data field follows from the octet following the fixed part of the header"},
241 { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"},
245 static const value_string extension_extension_vals[] =
247 { 0, "Data field follows from the octet following the LI field following this E field"},
248 { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"},
252 static const value_string data_or_control_vals[] =
259 static const value_string resegmentation_flag_vals[] =
262 { 1, "AMD PDU segment"},
266 static const value_string polling_bit_vals[] =
268 { 0, "Status report not requested"},
269 { 1, "Status report is requested"},
273 static const value_string lsf_vals[] =
275 { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
276 { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
280 static const value_string control_pdu_type_vals[] =
286 static const value_string am_e1_vals[] =
288 { 0, "A set of NACK_SN, E1 and E2 does not follow"},
289 { 1, "A set of NACK_SN, E1 and E2 follows"},
293 static const value_string am_e2_vals[] =
295 { 0, "A set of SOstart and SOend does not follow for this NACK_SN"},
296 { 1, "A set of SOstart and SOend follows for this NACK_SN"},
300 static const value_string header_only_vals[] =
302 { 0, "RLC PDU Headers and body present"},
303 { 1, "RLC PDU Headers only"},
309 /**********************************************************************************/
310 /* These are for keeping track of UM/AM extension headers, and the lengths found */
312 static guint8 s_number_of_extensions = 0;
313 #define MAX_RLC_SDUS 64
314 static guint16 s_lengths[MAX_RLC_SDUS];
317 /*********************************************************************/
318 /* UM/AM sequence analysis */
320 /* Types for RLC channel hash table */
321 /* This table is maintained during initial dissection of RLC */
322 /* frames, mapping from channel_hash_key -> sequence_analysis_report */
328 unsigned channelType : 3;
329 unsigned channelId : 5;
330 unsigned direction : 1;
334 /******************************************************************/
335 /* State maintained for AM/UM reassembly */
337 typedef struct rlc_segment {
344 typedef struct rlc_channel_reassembly_info
346 guint16 number_of_segments;
347 #define RLC_MAX_SEGMENTS 100
348 rlc_segment segments[RLC_MAX_SEGMENTS];
349 } rlc_channel_reassembly_info;
354 /*******************************************************************/
355 /* Conversation-type status for sequence analysis on channel */
360 /* For UM, we always expect the SN to keep advancing, and these fields
362 For AM, these correspond to new data */
363 guint16 previousSequenceNumber;
364 guint32 previousFrameNum;
365 gboolean previousSegmentIncomplete;
367 /* Accumulate info about current segmented SDU */
368 struct rlc_channel_reassembly_info *reassembly_info;
369 } channel_sequence_analysis_status;
371 /* The sequence analysis channel hash table */
372 static GHashTable *sequence_analysis_channel_hash = NULL;
375 /* Types for sequence analysis frame report hash table */
376 /* This is a table from framenum -> state_report_in_frame */
377 /* This is necessary because the per-packet info is already being used */
378 /* for context information before the dissector is called */
380 /* Info to attach to frame when first read, recording what to show about sequence */
382 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window, SN_Error
383 } sequence_analysis_state;
388 gboolean sequenceExpectedCorrect;
389 guint16 sequenceExpected;
390 guint32 previousFrameNum;
391 gboolean previousSegmentIncomplete;
392 guint32 nextFrameNum;
398 sequence_analysis_state state;
399 } sequence_analysis_report;
402 /* The sequence analysis frame report hash table instance itself */
403 static GHashTable *sequence_analysis_report_hash = NULL;
406 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
407 rlc_lte_info *p_rlc_lte_info,
408 gboolean do_persist);
413 /* The reassembly result hash table */
414 static GHashTable *reassembly_report_hash = NULL;
417 /* Create a new struct for reassembly */
418 static void reassembly_reset(channel_sequence_analysis_status *status)
420 status->reassembly_info = se_alloc0(sizeof(rlc_channel_reassembly_info));
423 /* Hide previous one */
424 static void reassembly_destroy(channel_sequence_analysis_status *status)
426 /* Just "leak" it. There seems to be no way to free this memory... */
427 status->reassembly_info = NULL;
430 /* Add a new segment to the accumulating segmented SDU */
431 static void reassembly_add_segment(channel_sequence_analysis_status *status,
432 guint16 SN, guint32 frame,
433 tvbuff_t *tvb, gint offset, gint length)
435 int segment_number = status->reassembly_info->number_of_segments;
436 guint8 *segment_data;
438 /* Give up if reach segment limit */
439 if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
440 reassembly_destroy(status);
444 segment_data = se_alloc(length);
445 /* TODO: is there a better way to do this? */
446 memcpy(segment_data, tvb_get_ptr(tvb, offset, length), length);
448 /* Add new segment */
449 status->reassembly_info->segments[segment_number].frameNum = frame;
450 status->reassembly_info->segments[segment_number].SN = SN;
451 status->reassembly_info->segments[segment_number].data = segment_data;
452 status->reassembly_info->segments[segment_number].length = length;
454 status->reassembly_info->number_of_segments++;
458 /* Record the current & complete segmented SDU by mapping from this frame number to
459 struct with segment info. */
460 static void reassembly_record(channel_sequence_analysis_status *status, packet_info *pinfo,
461 guint16 SN, rlc_lte_info *p_rlc_lte_info)
463 /* Just store existing info in hash table */
464 g_hash_table_insert(reassembly_report_hash,
465 get_report_hash_key(SN, pinfo->fd->num, p_rlc_lte_info, TRUE),
466 status->reassembly_info);
469 /* Create and return a tvb based upon contents of reassembly info */
470 static tvbuff_t* reassembly_get_reassembled_tvb(rlc_channel_reassembly_info *reassembly_info,
471 tvbuff_t *parent_tvb, packet_info *pinfo)
474 guint combined_length = 0;
475 guint8 *combined_data;
476 guint combined_offset = 0;
477 tvbuff_t *reassembled_tvb;
479 /* Allocate buffer big enough to hold re-assembled data */
480 for (n=0; n < reassembly_info->number_of_segments; n++) {
481 combined_length += reassembly_info->segments[n].length;
483 combined_data = ep_alloc(combined_length);
485 /* Copy data into contiguous buffer */
486 for (n=0; n < reassembly_info->number_of_segments; n++) {
487 guint8 *data = reassembly_info->segments[n].data;
488 int length = reassembly_info->segments[n].length;
489 memcpy(combined_data+combined_offset, data, length);
490 combined_offset += length;
493 /* Create and return tvb with this data */
494 reassembled_tvb = tvb_new_child_real_data(parent_tvb, combined_data, combined_offset, combined_offset);
495 add_new_data_source(pinfo, reassembled_tvb, "Reassembled SDU");
496 return reassembled_tvb;
499 /* Show where the segments came from for a reassembled SDU */
500 static void reassembly_show_source(rlc_channel_reassembly_info *reassembly_info,
501 proto_tree *tree, tvbuff_t *tvb, gint offset)
504 proto_item *source_ti, *ti;
505 proto_tree *source_tree;
506 proto_item *segment_ti;
507 proto_tree *segment_tree;
508 guint total_length=0;
510 /* Create root of source info */
511 source_ti = proto_tree_add_item(tree,
512 hf_rlc_lte_reassembly_source,
513 tvb, 0, 0, ENC_ASCII|ENC_NA);
514 source_tree = proto_item_add_subtree(source_ti, ett_rlc_lte_reassembly_source);
515 PROTO_ITEM_SET_GENERATED(source_ti);
517 for (n=0; n < reassembly_info->number_of_segments; n++) {
518 total_length += reassembly_info->segments[n].length;
520 proto_item_append_text(source_ti, " %u segments, %u bytes", reassembly_info->number_of_segments,
523 /* Number of segments */
524 ti = proto_tree_add_uint(source_tree,
525 hf_rlc_lte_reassembly_source_number_of_segments,
526 tvb, 0, 0, reassembly_info->number_of_segments);
527 PROTO_ITEM_SET_GENERATED(ti);
530 ti = proto_tree_add_uint(source_tree,
531 hf_rlc_lte_reassembly_source_total_length,
532 tvb, 0, 0, total_length);
533 PROTO_ITEM_SET_GENERATED(ti);
535 /* Now add info about each segment in turn */
536 for (n=0; n < reassembly_info->number_of_segments; n++) {
538 /* Add next segment as a subtree */
539 rlc_segment *segment = &(reassembly_info->segments[n]);
540 proto_item_append_text(source_ti, " (SN=%u frame=%u len=%u)",
541 segment->SN, segment->frameNum, segment->length);
543 /* N.B. assume last segment from passed-in tvb! */
544 segment_ti = proto_tree_add_item(source_tree,
545 hf_rlc_lte_reassembly_source_segment,
547 (n == reassembly_info->number_of_segments-1) ? offset : 0,
548 (n == reassembly_info->number_of_segments-1) ? segment->length : 0,
550 segment_tree = proto_item_add_subtree(segment_ti, ett_rlc_lte_reassembly_source_segment);
551 proto_item_append_text(segment_ti, " (SN=%u frame=%u length=%u)",
552 segment->SN, segment->frameNum, segment->length);
553 PROTO_ITEM_SET_GENERATED(segment_ti);
555 /* Add details to segment tree */
556 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_sn,
557 tvb, 0, 0, segment->SN);
558 PROTO_ITEM_SET_GENERATED(ti);
559 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_framenum,
560 tvb, 0, 0, segment->frameNum);
561 PROTO_ITEM_SET_GENERATED(ti);
562 ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_length,
563 tvb, 0, 0, segment->length);
564 PROTO_ITEM_SET_GENERATED(ti);
571 /******************************************************************/
572 /* Conversation-type status for repeated NACK checking on channel */
576 guint16 NACKs[MAX_NACKs];
578 } channel_repeated_nack_status;
580 static GHashTable *repeated_nack_channel_hash = NULL;
583 guint16 noOfNACKsRepeated;
584 guint16 repeatedNACKs[MAX_NACKs];
585 guint32 previousFrameNum;
586 } channel_repeated_nack_report;
588 static GHashTable *repeated_nack_report_hash = NULL;
592 /********************************************************/
593 /* Forward declarations & functions */
594 static void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
597 /* Write the given formatted text to:
599 - the top-level RLC PDU item
600 - another subtree item (if supplied) */
601 static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
602 packet_info *pinfo, const char *format, ...)
604 #define MAX_INFO_BUFFER 256
605 static char info_buffer[MAX_INFO_BUFFER];
609 va_start(ap, format);
610 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
613 /* Add to indicated places */
614 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
615 proto_item_append_text(pdu_ti, "%s", info_buffer);
616 if (sub_ti != NULL) {
617 proto_item_append_text(sub_ti, "%s", info_buffer);
623 /* Dissect extension headers (common to both UM and AM) */
624 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo _U_,
629 guint64 extension = 1;
632 /* Reset this count */
633 s_number_of_extensions = 0;
635 while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
636 proto_tree *extension_part_tree;
637 proto_item *extension_part_ti;
639 isOdd = (s_number_of_extensions % 2);
641 /* Extension part subtree */
642 extension_part_ti = proto_tree_add_string_format(tree,
643 hf_rlc_lte_extension_part,
647 extension_part_tree = proto_item_add_subtree(extension_part_ti,
648 ett_rlc_lte_extension_part);
650 /* Read next extension */
651 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
652 (offset*8) + ((isOdd) ? 4 : 0),
654 &extension, ENC_BIG_ENDIAN);
656 /* Read length field */
657 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
658 (offset*8) + ((isOdd) ? 5 : 1),
660 &length, ENC_BIG_ENDIAN);
662 proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length);
664 /* Move on to byte of next extension */
671 s_lengths[s_number_of_extensions++] = (guint16)length;
674 /* May need to skip padding after last extension part */
675 isOdd = (s_number_of_extensions % 2);
677 proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
678 tvb, offset++, 1, ENC_BIG_ENDIAN);
685 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
686 whether or not the beginning and end are included in this packet */
687 static void show_PDU_in_info(packet_info *pinfo,
690 gboolean first_includes_start,
691 gboolean last_includes_end)
693 /* Reflect this PDU in the info column */
695 write_pdu_label_and_info(top_ti, NULL, pinfo,
697 (first_includes_start) ? "[" : "..",
699 (length > 1) ? "s" : "",
700 (last_includes_end) ? "]" : "..");
703 write_pdu_label_and_info(top_ti, NULL, pinfo,
704 " %sunknown-bytes%s",
705 (first_includes_start) ? "[" : "..",
706 (last_includes_end) ? "]" : "..");
711 /* Show an SDU. If configured, pass to PDCP dissector */
712 static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, gint offset, gint length,
713 rlc_lte_info *rlc_info, gboolean whole_pdu, rlc_channel_reassembly_info *reassembly_info,
714 sequence_analysis_state state)
716 /* Add raw data (according to mode) */
717 proto_item *data_ti = proto_tree_add_item(tree,
718 (rlc_info->rlcMode == RLC_AM_MODE) ?
721 tvb, offset, length, ENC_NA);
723 /* Send whole PDU to PDCP */
724 if ((whole_pdu || (reassembly_info != NULL)) &&
725 (((global_rlc_lte_call_pdcp_for_srb) && (rlc_info->channelType == CHANNEL_TYPE_SRB)) ||
726 ((global_rlc_lte_call_pdcp_for_drb != PDCP_drb_off) && (rlc_info->channelType == CHANNEL_TYPE_DRB)))) {
728 /* TODO: made static to avoid compiler warning... */
729 static tvbuff_t *pdcp_tvb = NULL;
730 volatile dissector_handle_t protocol_handle;
731 struct pdcp_lte_info *p_pdcp_lte_info;
733 /* Get tvb for passing to LTE PDCP dissector */
734 if (reassembly_info == NULL) {
735 pdcp_tvb = tvb_new_subset(tvb, offset, length, length);
738 /* Get combined tvb. */
739 pdcp_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
740 reassembly_show_source(reassembly_info, tree, tvb, offset);
743 /* Reuse or allocate struct */
744 p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
745 if (p_pdcp_lte_info == NULL) {
746 p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
747 /* Store info in packet */
748 p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
751 p_pdcp_lte_info->ueid = rlc_info->ueid;
752 p_pdcp_lte_info->channelType = Channel_DCCH;
753 p_pdcp_lte_info->channelId = rlc_info->channelId;
754 p_pdcp_lte_info->direction = rlc_info->direction;
755 p_pdcp_lte_info->is_retx = (state != SN_OK);
757 /* Set plane and sequnce number length */
758 p_pdcp_lte_info->no_header_pdu = FALSE;
759 if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
760 p_pdcp_lte_info->plane = SIGNALING_PLANE;
761 p_pdcp_lte_info->seqnum_length = 5;
764 p_pdcp_lte_info->plane = USER_PLANE;
765 switch (global_rlc_lte_call_pdcp_for_drb) {
767 p_pdcp_lte_info->seqnum_length = 7;
770 p_pdcp_lte_info->seqnum_length = 12;
772 case PDCP_drb_SN_signalled:
773 /* Use whatever was signalled (e.g. in RRC) */
774 p_pdcp_lte_info->seqnum_length = signalled_pdcp_sn_bits;
778 DISSECTOR_ASSERT(FALSE);
783 p_pdcp_lte_info->rohc_compression = FALSE;
786 /* Get dissector handle */
787 protocol_handle = find_dissector("pdcp-lte");
790 call_dissector_only(protocol_handle, pdcp_tvb, pinfo, tree);
796 PROTO_ITEM_SET_HIDDEN(data_ti);
800 /* Hash table functions for RLC channels */
803 static gint rlc_channel_equal(gconstpointer v, gconstpointer v2)
805 const channel_hash_key* val1 = v;
806 const channel_hash_key* val2 = v2;
808 /* All fields must match */
809 /* N.B. Currently fits into one word, so could return (*v == *v2)
810 if we're sure they're initialised to 0... */
811 return ((val1->ueId == val2->ueId) &&
812 (val1->channelType == val2->channelType) &&
813 (val1->channelId == val2->channelId) &&
814 (val1->direction == val2->direction));
817 /* Compute a hash value for a given key. */
818 static guint rlc_channel_hash_func(gconstpointer v)
820 const channel_hash_key* val1 = v;
822 /* TODO: check/reduce multipliers */
823 return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
827 /*************************************************************************/
833 unsigned channelType : 2;
834 unsigned channelId: 5;
835 unsigned direction: 1;
836 } rlc_result_hash_key;
838 static gint rlc_result_hash_equal(gconstpointer v, gconstpointer v2)
840 const rlc_result_hash_key* val1 = (rlc_result_hash_key *)v;
841 const rlc_result_hash_key* val2 = (rlc_result_hash_key *)v2;
843 /* All fields must match */
844 return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
847 /* Compute a hash value for a given key. */
848 static guint rlc_result_hash_func(gconstpointer v)
850 const rlc_result_hash_key* val1 = (rlc_result_hash_key *)v;
852 /* TODO: check collision-rate / execution-time of these multipliers? */
853 return val1->frameNumber + (val1->SN<<13) +
854 (val1->channelType<<5) +
855 (val1->channelId<<18) +
856 (val1->direction<<9);
859 /* Convenience function to get a pointer for the hash_func to work with */
860 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
861 rlc_lte_info *p_rlc_lte_info,
864 static rlc_result_hash_key key;
865 rlc_result_hash_key *p_key;
867 /* Only allocate a struct when will be adding entry */
869 p_key = se_new0(rlc_result_hash_key);
872 memset(&key, 0, sizeof(rlc_result_hash_key));
876 /* Fill in details, and return pointer */
877 p_key->frameNumber = frameNumber;
879 p_key->channelType = p_rlc_lte_info->channelType;
880 p_key->channelId = p_rlc_lte_info->channelId;
881 p_key->direction = p_rlc_lte_info->direction;
889 /* Add to the tree values associated with sequence analysis for this frame */
890 static void addChannelSequenceInfo(sequence_analysis_report *p,
891 gboolean isControlFrame,
892 rlc_lte_info *p_rlc_lte_info,
893 guint16 sequenceNumber,
894 gboolean newSegmentStarted,
895 rlc_lte_tap_info *tap_info,
896 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
898 proto_tree *seqnum_tree;
899 proto_item *seqnum_ti;
903 seqnum_ti = proto_tree_add_string_format(tree,
904 hf_rlc_lte_sequence_analysis,
906 "", "Sequence Analysis");
907 seqnum_tree = proto_item_add_subtree(seqnum_ti,
908 ett_rlc_lte_sequence_analysis);
909 PROTO_ITEM_SET_GENERATED(seqnum_ti);
911 if (p->previousFrameNum != 0) {
912 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
913 tvb, 0, 0, p->previousFrameNum);
914 PROTO_ITEM_SET_GENERATED(ti);
917 switch (p_rlc_lte_info->rlcMode) {
920 /********************************************/
922 /********************************************/
926 if (isControlFrame) {
930 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
932 PROTO_ITEM_SET_GENERATED(ti);
933 proto_item_append_text(seqnum_ti, " - OK");
935 /* Link to next SN in channel (if known) */
936 if (p->nextFrameNum != 0) {
937 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
938 tvb, 0, 0, p->nextFrameNum);
943 if (isControlFrame) {
947 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
949 PROTO_ITEM_SET_GENERATED(ti);
950 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
952 PROTO_ITEM_SET_GENERATED(ti);
953 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
954 "AM Frame retransmitted for %s on UE %u - due to MAC retx!",
955 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
956 p_rlc_lte_info->ueid);
957 proto_item_append_text(seqnum_ti, " - MAC retx of SN %u", p->firstSN);
961 if (isControlFrame) {
965 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
967 PROTO_ITEM_SET_GENERATED(ti);
968 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
970 PROTO_ITEM_SET_GENERATED(ti);
971 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
972 "AM Frame retransmitted for %s on UE %u - most likely in response to NACK",
973 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
974 p_rlc_lte_info->ueid);
975 proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
979 if (isControlFrame) {
983 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
985 PROTO_ITEM_SET_GENERATED(ti);
986 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
988 PROTO_ITEM_SET_GENERATED(ti);
989 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
990 "AM SN Repeated for %s for UE %u - probably because didn't receive Status PDU?",
991 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
992 p_rlc_lte_info->ueid);
993 proto_item_append_text(seqnum_ti, "- SN %u Repeated", p->firstSN);
997 if (isControlFrame) {
1001 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1003 PROTO_ITEM_SET_GENERATED(ti);
1004 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1006 PROTO_ITEM_SET_GENERATED(ti);
1007 if (p->lastSN != p->firstSN) {
1008 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1009 "AM SNs (%u to %u) missing for %s on UE %u",
1010 p->firstSN, p->lastSN,
1011 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1012 p_rlc_lte_info->ueid);
1013 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1014 p->firstSN, p->lastSN);
1015 tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1018 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1019 "AM SN (%u) missing for %s on UE %u",
1021 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1022 p_rlc_lte_info->ueid);
1023 proto_item_append_text(seqnum_ti, " - SN missing (%u)", p->firstSN);
1024 tap_info->missingSNs = 1;
1028 case ACK_Out_of_Window:
1029 if (!isControlFrame) {
1035 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1038 PROTO_ITEM_SET_GENERATED(ti);
1039 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1041 PROTO_ITEM_SET_GENERATED(ti);
1043 /* Link back to last seen SN in other direction */
1044 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1045 tvb, 0, 0, p->previousFrameNum);
1046 PROTO_ITEM_SET_GENERATED(ti);
1049 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_ERROR,
1050 "AM ACK for SN %u - but last received SN in other direction is %u for UE %u",
1051 p->firstSN, p->sequenceExpected,
1052 p_rlc_lte_info->ueid);
1053 proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1054 p->firstSN, p->sequenceExpected);
1065 /********************************************/
1067 /********************************************/
1069 /* Previous channel frame */
1070 if (p->previousFrameNum != 0) {
1071 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1072 tvb, 0, 0, p->previousFrameNum);
1073 PROTO_ITEM_SET_GENERATED(ti);
1076 /* Expected sequence number */
1077 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
1078 tvb, 0, 0, p->sequenceExpected);
1079 PROTO_ITEM_SET_GENERATED(ti);
1081 if (!p->sequenceExpectedCorrect) {
1082 /* Work out SN wrap (in case needed below) */
1084 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1093 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1095 PROTO_ITEM_SET_GENERATED(ti);
1096 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1098 PROTO_ITEM_SET_GENERATED(ti);
1099 if (p->lastSN != p->firstSN) {
1100 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1101 "UM SNs (%u to %u) missing for %s on UE %u",
1102 p->firstSN, p->lastSN,
1103 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1104 p_rlc_lte_info->ueid);
1105 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1106 p->firstSN, p->lastSN);
1107 tap_info->missingSNs = ((snLimit + p->lastSN - p->firstSN) % snLimit) + 1;
1110 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1111 "UM SN (%u) missing for %s on UE %u",
1113 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1114 p_rlc_lte_info->ueid);
1115 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
1117 tap_info->missingSNs = 1;
1122 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1124 PROTO_ITEM_SET_GENERATED(ti);
1125 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1127 PROTO_ITEM_SET_GENERATED(ti);
1128 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1129 "UM SN (%u) repeated for %s for UE %u",
1131 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1132 p_rlc_lte_info->ueid);
1133 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
1138 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1140 PROTO_ITEM_SET_GENERATED(ti);
1141 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1143 PROTO_ITEM_SET_GENERATED(ti);
1144 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1145 "UM Frame retransmitted for %s on UE %u - due to MAC retx!",
1146 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1147 p_rlc_lte_info->ueid);
1151 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1153 PROTO_ITEM_SET_GENERATED(ti);
1154 proto_item_append_text(seqnum_ti, " - OK");
1156 /* Link to next SN in channel (if known) */
1157 if (p->nextFrameNum != 0) {
1158 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1159 tvb, 0, 0, p->nextFrameNum);
1164 /* Incorrect sequence number */
1165 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1166 "Wrong Sequence Number for %s on UE %u - got %u, expected %u",
1167 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1168 p_rlc_lte_info->ueid, sequenceNumber, p->sequenceExpected);
1174 /* Correct sequence number, so check frame indication bits consistent */
1175 if (p->previousSegmentIncomplete) {
1176 /* Previous segment was incomplete, so this PDU should continue it */
1177 if (newSegmentStarted) {
1178 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1180 if (!p->sequenceExpectedCorrect) {
1181 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1182 "Last segment of previous PDU was not continued for UE %u",
1183 p_rlc_lte_info->ueid);
1187 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1192 /* Previous segment was complete, so this PDU should start a new one */
1193 if (!newSegmentStarted) {
1194 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1196 if (!p->sequenceExpectedCorrect) {
1197 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
1198 "Last segment of previous PDU was complete, but new segment was not started");
1202 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1207 PROTO_ITEM_SET_GENERATED(ti);
1212 /* Update the channel status and set report for this frame */
1213 static sequence_analysis_state checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
1214 rlc_lte_info *p_rlc_lte_info,
1215 gboolean isControlFrame,
1216 guint8 number_of_segments,
1217 guint16 firstSegmentOffset,
1218 guint16 firstSegmentLength,
1219 guint16 lastSegmentOffset,
1220 guint16 sequenceNumber,
1221 gboolean first_includes_start, gboolean last_includes_end,
1222 gboolean is_resegmented _U_,
1223 rlc_lte_tap_info *tap_info,
1226 channel_hash_key channel_key;
1227 channel_hash_key *p_channel_key;
1228 channel_sequence_analysis_status *p_channel_status;
1229 sequence_analysis_report *p_report_in_frame = NULL;
1230 gboolean createdChannel = FALSE;
1231 guint16 expectedSequenceNumber = 0;
1232 guint16 snLimit = 0;
1234 /* If find stat_report_in_frame already, use that and get out */
1235 if (pinfo->fd->flags.visited) {
1236 p_report_in_frame = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1237 get_report_hash_key(sequenceNumber,
1241 if (p_report_in_frame != NULL) {
1242 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
1243 sequenceNumber, first_includes_start,
1244 tap_info, pinfo, tree, tvb);
1245 return p_report_in_frame->state;
1248 /* Don't just give up here... */
1252 /**************************************************/
1253 /* Create or find an entry for this channel state */
1254 channel_key.ueId = p_rlc_lte_info->ueid;
1255 channel_key.channelType = p_rlc_lte_info->channelType;
1256 channel_key.channelId = p_rlc_lte_info->channelId;
1257 channel_key.direction = p_rlc_lte_info->direction;
1259 /* Do the table lookup */
1260 p_channel_status = (channel_sequence_analysis_status*)g_hash_table_lookup(sequence_analysis_channel_hash, &channel_key);
1262 /* Create table entry if necessary */
1263 if (p_channel_status == NULL) {
1264 createdChannel = TRUE;
1266 /* Allocate a new value and duplicate key contents */
1267 p_channel_status = se_alloc0(sizeof(channel_sequence_analysis_status));
1268 p_channel_key = se_memdup(&channel_key, sizeof(channel_hash_key));
1271 p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1274 g_hash_table_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1277 /* Create space for frame state_report */
1278 p_report_in_frame = se_alloc(sizeof(sequence_analysis_report));
1281 /* Deal with according to channel mode */
1282 switch (p_channel_status->rlcMode) {
1285 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1292 /* Work out expected sequence number */
1293 if (!createdChannel) {
1294 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1297 /* Whatever we got is fine.. */
1298 expectedSequenceNumber = sequenceNumber;
1301 /* Set report for this frame */
1302 /* For UM, sequence number is always expectedSequence number */
1303 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
1305 /* For wrong sequence number... */
1306 if (!p_report_in_frame->sequenceExpectedCorrect) {
1308 reassembly_destroy(p_channel_status);
1310 /* Don't get confused by MAC (HARQ) retx */
1311 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1312 p_report_in_frame->state = SN_MAC_Retx;
1313 p_report_in_frame->firstSN = sequenceNumber;
1316 /* Frames are not missing if we get an earlier sequence number again */
1317 /* TODO: taking time into account would give better idea of whether missing or repeated... */
1318 else if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10) {
1319 p_report_in_frame->state = SN_Missing;
1320 tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
1321 p_report_in_frame->firstSN = expectedSequenceNumber;
1322 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
1324 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1325 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1326 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1328 /* Update channel status to remember *this* frame */
1329 p_channel_status->previousFrameNum = pinfo->fd->num;
1330 p_channel_status->previousSequenceNumber = sequenceNumber;
1331 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1334 /* An SN has been repeated */
1335 p_report_in_frame->state = SN_Repeated;
1336 p_report_in_frame->firstSN = sequenceNumber;
1338 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1339 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1344 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1345 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1346 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1348 /* Update channel status to remember *this* frame */
1349 p_channel_status->previousFrameNum = pinfo->fd->num;
1350 p_channel_status->previousSequenceNumber = sequenceNumber;
1351 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1353 if (p_channel_status->reassembly_info) {
1355 /* Add next segment to reassembly info */
1356 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->fd->num,
1357 tvb, firstSegmentOffset, firstSegmentLength);
1359 /* The end of existing reassembly? */
1360 if (!first_includes_start &&
1361 ((number_of_segments > 1) || last_includes_end)) {
1363 reassembly_record(p_channel_status, pinfo, sequenceNumber, p_rlc_lte_info);
1364 reassembly_destroy(p_channel_status);
1368 /* The start of a new reassembly? */
1369 if (!last_includes_end &&
1370 ((number_of_segments > 1) || first_includes_start)) {
1372 guint16 lastSegmentLength = tvb_length(tvb)-lastSegmentOffset;
1374 if (global_rlc_lte_reassembly) {
1375 reassembly_reset(p_channel_status);
1376 reassembly_add_segment(p_channel_status, sequenceNumber,
1378 tvb, lastSegmentOffset, lastSegmentLength);
1382 if (p_report_in_frame->previousFrameNum != 0) {
1383 /* Get report for previous frame */
1384 sequence_analysis_report *p_previous_report;
1386 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
1393 p_previous_report = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1394 get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1395 p_report_in_frame->previousFrameNum,
1398 /* It really shouldn't be NULL... */
1399 if (p_previous_report != NULL) {
1400 /* Point it forward to this one */
1401 p_previous_report->nextFrameNum = pinfo->fd->num;
1410 /* Work out expected sequence number */
1411 if (!createdChannel) {
1412 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % 1024;
1415 /* Whatever we got is fine.. */
1416 expectedSequenceNumber = sequenceNumber;
1420 - expected Sequence number OR
1421 - previous frame repeated
1422 - old SN being sent (in response to NACK)
1423 - new SN, but with frames missed out
1424 Assume window whose front is at expectedSequenceNumber */
1426 /* First of all, check to see whether frame is judged to be MAC Retx */
1427 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1428 /* Just report that this is a MAC Retx */
1429 p_report_in_frame->state = SN_MAC_Retx;
1430 p_report_in_frame->firstSN = sequenceNumber;
1432 /* No channel state to update */
1436 if (sequenceNumber != expectedSequenceNumber) {
1437 /* Don't trash reassembly info if this looks like a close retx... */
1438 if (((1024 + sequenceNumber - expectedSequenceNumber) % 1024) < 50) {
1439 reassembly_destroy(p_channel_status);
1444 if (sequenceNumber == expectedSequenceNumber) {
1445 /* Set report for this frame */
1446 p_report_in_frame->sequenceExpectedCorrect = TRUE;
1447 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1448 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1449 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1450 p_report_in_frame->state = SN_OK;
1452 /* Update channel status */
1453 p_channel_status->previousSequenceNumber = sequenceNumber;
1454 p_channel_status->previousFrameNum = pinfo->fd->num;
1455 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1458 if (p_channel_status->reassembly_info) {
1460 /* Add next segment to reassembly info */
1461 reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->fd->num,
1462 tvb, firstSegmentOffset, firstSegmentLength);
1464 /* The end of existing reassembly? */
1465 if (!first_includes_start &&
1466 ((number_of_segments > 1) || last_includes_end)) {
1468 reassembly_record(p_channel_status, pinfo,
1469 sequenceNumber, p_rlc_lte_info);
1470 reassembly_destroy(p_channel_status);
1474 /* The start of a new reassembly? */
1475 if (!last_includes_end &&
1476 ((number_of_segments > 1) || first_includes_start)) {
1478 guint16 lastSegmentLength = tvb_length(tvb)-lastSegmentOffset;
1479 if (global_rlc_lte_reassembly) {
1480 reassembly_reset(p_channel_status);
1481 reassembly_add_segment(p_channel_status, sequenceNumber,
1483 tvb, lastSegmentOffset, lastSegmentLength);
1487 if (p_report_in_frame->previousFrameNum != 0) {
1488 /* Get report for previous frame */
1489 sequence_analysis_report *p_previous_report;
1490 p_previous_report = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1491 get_report_hash_key((sequenceNumber+1023) % 1024,
1492 p_report_in_frame->previousFrameNum,
1495 /* It really shouldn't be NULL... */
1496 if (p_previous_report != NULL) {
1497 /* Point it forward to this one */
1498 p_previous_report->nextFrameNum = pinfo->fd->num;
1504 /* Previous subframe repeated? */
1505 else if (((sequenceNumber+1) % 1024) == expectedSequenceNumber) {
1506 p_report_in_frame->state = SN_Repeated;
1508 /* Set report for this frame */
1509 p_report_in_frame->sequenceExpectedCorrect = FALSE;
1510 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1511 p_report_in_frame->firstSN = sequenceNumber;
1512 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1513 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1516 /* Really should be nothing to update... */
1517 p_channel_status->previousSequenceNumber = sequenceNumber;
1518 p_channel_status->previousFrameNum = pinfo->fd->num;
1519 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1523 /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1524 int delta = (1024 + expectedSequenceNumber - sequenceNumber) % 1024;
1526 /* Rx window is 512, so check to see if this is a retx */
1528 /* Probably a retx due to receiving NACK */
1529 p_report_in_frame->state = SN_Retx;
1531 p_report_in_frame->firstSN = sequenceNumber;
1532 /* Don't update anything in channel state */
1536 /* Ahead of expected SN. Assume frames have been missed */
1537 p_report_in_frame->state = SN_Missing;
1539 p_report_in_frame->firstSN = expectedSequenceNumber;
1540 p_report_in_frame->lastSN = (1024 + sequenceNumber-1) % 1024;
1542 /* Update channel state - forget about missed SNs */
1543 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1544 p_channel_status->previousSequenceNumber = sequenceNumber;
1545 p_channel_status->previousFrameNum = pinfo->fd->num;
1546 p_channel_status->previousSegmentIncomplete = !last_includes_end;
1552 /* Shouldn't get here! */
1556 /* Associate with this frame number */
1557 g_hash_table_insert(sequence_analysis_report_hash,
1558 get_report_hash_key(sequenceNumber, pinfo->fd->num, p_rlc_lte_info, TRUE),
1561 /* Add state report for this frame into tree */
1562 addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1563 first_includes_start, tap_info, pinfo, tree, tvb);
1565 return p_report_in_frame->state;
1569 /* Add to the tree values associated with sequence analysis for this frame */
1570 static void addChannelRepeatedNACKInfo(channel_repeated_nack_report *p,
1571 rlc_lte_info *p_rlc_lte_info,
1572 packet_info *pinfo, proto_tree *tree,
1575 proto_tree *seqnum_tree;
1576 proto_item *seqnum_ti;
1580 /* Create subtree */
1581 seqnum_ti = proto_tree_add_string_format(tree,
1582 hf_rlc_lte_sequence_analysis,
1584 "", "Sequence Analysis");
1585 seqnum_tree = proto_item_add_subtree(seqnum_ti,
1586 ett_rlc_lte_sequence_analysis);
1587 PROTO_ITEM_SET_GENERATED(seqnum_ti);
1590 ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1592 PROTO_ITEM_SET_GENERATED(ti);
1594 /* Add each repeated NACK as item & expert info */
1595 for (n=0; n < p->noOfNACKsRepeated; n++) {
1597 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
1598 tvb, 0, 0, p->repeatedNACKs[n]);
1599 PROTO_ITEM_SET_GENERATED(ti);
1601 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_ERROR,
1602 "Same SN (%u) NACKd for %s on UE %u in successive Status PDUs",
1603 p->repeatedNACKs[n],
1604 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1605 p_rlc_lte_info->ueid);
1608 /* Link back to previous status report */
1609 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
1610 tvb, 0, 0, p->previousFrameNum);
1611 PROTO_ITEM_SET_GENERATED(ti);
1613 /* Append count to sequence analysis root */
1614 proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
1615 p->noOfNACKsRepeated);
1619 /* Update the channel repeated NACK status and set report for this frame */
1620 static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
1621 rlc_lte_info *p_rlc_lte_info,
1622 rlc_lte_tap_info *tap_info,
1626 channel_hash_key channel_key;
1627 channel_hash_key *p_channel_key;
1628 channel_repeated_nack_status *p_channel_status;
1629 channel_repeated_nack_report *p_report_in_frame = NULL;
1631 guint16 noOfNACKsRepeated = 0;
1632 guint16 repeatedNACKs[MAX_NACKs];
1635 /* If find state_report_in_frame already, use that and get out */
1636 if (pinfo->fd->flags.visited) {
1637 p_report_in_frame = (channel_repeated_nack_report*)g_hash_table_lookup(repeated_nack_report_hash,
1638 get_report_hash_key(0, pinfo->fd->num,
1639 p_rlc_lte_info, FALSE));
1640 if (p_report_in_frame != NULL) {
1641 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1646 /* Give up - we must have tried already... */
1652 /**************************************************/
1653 /* Create or find an entry for this channel state */
1654 channel_key.ueId = p_rlc_lte_info->ueid;
1655 channel_key.channelType = p_rlc_lte_info->channelType;
1656 channel_key.channelId = p_rlc_lte_info->channelId;
1657 channel_key.direction = p_rlc_lte_info->direction;
1658 memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1660 /* Do the table lookup */
1661 p_channel_status = (channel_repeated_nack_status*)g_hash_table_lookup(repeated_nack_channel_hash, &channel_key);
1663 /* Create table entry if necessary */
1664 if (p_channel_status == NULL) {
1666 /* Allocate a new key and value */
1667 p_channel_key = se_alloc(sizeof(channel_hash_key));
1668 p_channel_status = se_alloc0(sizeof(channel_repeated_nack_status));
1670 /* Copy key contents */
1671 memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1673 /* Add entry to table */
1674 g_hash_table_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1677 /* Compare NACKs in channel status with NACKs in tap_info.
1678 Note any that are repeated */
1679 for (i=0; i < p_channel_status->noOfNACKs; i++) {
1680 for (j=0; j < MIN(tap_info->noOfNACKs, MAX_NACKs); j++) {
1681 if (tap_info->NACKs[j] == p_channel_status->NACKs[i]) {
1682 /* Don't add the same repeated NACK twice! */
1683 if ((noOfNACKsRepeated == 0) ||
1684 (repeatedNACKs[noOfNACKsRepeated-1] != p_channel_status->NACKs[i])) {
1686 repeatedNACKs[noOfNACKsRepeated++] = p_channel_status->NACKs[i];
1692 /* Copy NACKs from tap_info into channel status for next time! */
1693 p_channel_status->noOfNACKs = 0;
1694 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1695 p_channel_status->NACKs[p_channel_status->noOfNACKs++] = tap_info->NACKs[n];
1698 if (noOfNACKsRepeated >= 1) {
1699 /* Create space for frame state_report */
1700 p_report_in_frame = se_alloc(sizeof(channel_repeated_nack_report));
1702 /* Copy in found duplicates */
1703 for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1704 p_report_in_frame->repeatedNACKs[n] = repeatedNACKs[n];
1706 p_report_in_frame->noOfNACKsRepeated = noOfNACKsRepeated;
1708 p_report_in_frame->previousFrameNum = p_channel_status->frameNum;
1710 /* Associate with this frame number */
1711 g_hash_table_insert(repeated_nack_report_hash,
1712 get_report_hash_key(0, pinfo->fd->num,
1713 p_rlc_lte_info, TRUE),
1716 /* Add state report for this frame into tree */
1717 addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1721 /* Save frame number for next comparison */
1722 p_channel_status->frameNum = pinfo->fd->num;
1725 /* Check that the ACK is consistent with data the expected sequence number
1726 in the other direction */
1727 static void checkChannelACKWindow(guint16 ack_sn,
1729 rlc_lte_info *p_rlc_lte_info,
1730 rlc_lte_tap_info *tap_info,
1734 channel_hash_key channel_key;
1735 channel_sequence_analysis_status *p_channel_status;
1736 sequence_analysis_report *p_report_in_frame = NULL;
1738 /* If find stat_report_in_frame already, use that and get out */
1739 if (pinfo->fd->flags.visited) {
1740 p_report_in_frame = (sequence_analysis_report*)g_hash_table_lookup(sequence_analysis_report_hash,
1741 get_report_hash_key(0, pinfo->fd->num,
1744 if (p_report_in_frame != NULL) {
1745 /* Add any info to tree */
1746 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info,
1748 tap_info, pinfo, tree, tvb);
1752 /* Give up - we must have tried already... */
1757 /*******************************************************************/
1758 /* Find an entry for this channel state (in the opposite direction */
1759 channel_key.ueId = p_rlc_lte_info->ueid;
1760 channel_key.channelType = p_rlc_lte_info->channelType;
1761 channel_key.channelId = p_rlc_lte_info->channelId;
1762 channel_key.direction =
1763 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1765 /* Do the table lookup */
1766 p_channel_status = (channel_sequence_analysis_status*)g_hash_table_lookup(sequence_analysis_channel_hash, &channel_key);
1768 /* Create table entry if necessary */
1769 if (p_channel_status == NULL) {
1773 /* Is it in the rx window? This test will catch if its ahead, but we don't
1774 really know what the back of the tx window is... */
1775 if (((1024 + p_channel_status->previousSequenceNumber+1 - ack_sn) % 1024) > 512) {
1778 p_report_in_frame = se_alloc(sizeof(sequence_analysis_report));
1779 p_report_in_frame->state = ACK_Out_of_Window;
1780 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1781 p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1782 p_report_in_frame->firstSN = ack_sn;
1784 /* Associate with this frame number */
1785 g_hash_table_insert(sequence_analysis_report_hash,
1786 get_report_hash_key(0, pinfo->fd->num,
1787 p_rlc_lte_info, TRUE),
1790 /* Add state report for this frame into tree */
1791 addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info, 0,
1792 FALSE, tap_info, pinfo, tree, tvb);
1799 /***************************************************/
1800 /* Transparent mode PDU. Call RRC if configured to */
1801 static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
1804 rlc_lte_info *p_rlc_lte_info,
1807 proto_item *raw_tm_ti;
1810 /* Create hidden TM root */
1811 tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
1812 tvb, offset, 0, "", "TM");
1813 PROTO_ITEM_SET_HIDDEN(tm_ti);
1815 /* Remaining bytes are all data */
1816 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, ENC_NA);
1817 if (!global_rlc_lte_call_rrc) {
1818 write_pdu_label_and_info(top_ti, NULL, pinfo,
1819 " [%u-bytes]", tvb_length_remaining(tvb, offset));
1822 if (global_rlc_lte_call_rrc) {
1823 tvbuff_t *rrc_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
1824 volatile dissector_handle_t protocol_handle = 0;
1826 switch (p_rlc_lte_info->channelType) {
1827 case CHANNEL_TYPE_CCCH:
1828 if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
1829 protocol_handle = find_dissector("lte_rrc.ul_ccch");
1832 protocol_handle = find_dissector("lte_rrc.dl_ccch");
1836 case CHANNEL_TYPE_BCCH_BCH:
1837 protocol_handle = find_dissector("lte_rrc.bcch_bch");
1839 case CHANNEL_TYPE_BCCH_DL_SCH:
1840 protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
1842 case CHANNEL_TYPE_PCCH:
1843 protocol_handle = find_dissector("lte-rrc.pcch");
1846 case CHANNEL_TYPE_SRB:
1847 case CHANNEL_TYPE_DRB:
1850 /* Shouldn't happen, just return... */
1854 /* Hide raw view of bytes */
1855 PROTO_ITEM_SET_HIDDEN(raw_tm_ti);
1857 /* Call it (catch exceptions) */
1859 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree);
1869 /***************************************************/
1870 /* Unacknowledged mode PDU */
1871 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
1874 rlc_lte_info *p_rlc_lte_info,
1876 rlc_lte_tap_info *tap_info)
1878 guint64 framing_info;
1879 gboolean first_includes_start;
1880 gboolean last_includes_end;
1881 guint64 fixed_extension;
1883 gint start_offset = offset;
1885 proto_tree *um_header_tree;
1886 proto_item *um_header_ti;
1887 gboolean is_truncated;
1888 proto_item *truncated_ti;
1889 rlc_channel_reassembly_info *reassembly_info = NULL;
1890 sequence_analysis_state seq_anal_state = SN_OK;
1892 /* Hidden UM root */
1893 um_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um,
1894 tvb, offset, 0, "", "UM");
1895 PROTO_ITEM_SET_HIDDEN(um_ti);
1897 /* Add UM header subtree */
1898 um_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um_header,
1901 um_header_tree = proto_item_add_subtree(um_header_ti,
1902 ett_rlc_lte_um_header);
1905 /*******************************/
1906 /* Fixed UM header */
1907 if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1908 /* Framing info (2 bits) */
1909 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
1911 &framing_info, ENC_BIG_ENDIAN);
1913 /* Extension (1 bit) */
1914 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
1916 &fixed_extension, ENC_BIG_ENDIAN);
1918 /* Sequence Number (5 bit) */
1919 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
1921 &sn, ENC_BIG_ENDIAN);
1924 else if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_10_BITS) {
1928 /* Check 3 Reserved bits */
1929 reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5;
1930 ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
1931 if (reserved != 0) {
1932 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
1933 "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
1936 /* Framing info (2 bits) */
1937 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
1938 tvb, (offset*8)+3, 2,
1939 &framing_info, ENC_BIG_ENDIAN);
1941 /* Extension (1 bit) */
1942 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
1944 &fixed_extension, ENC_BIG_ENDIAN);
1946 /* Sequence Number (10 bits) */
1947 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
1949 &sn, ENC_BIG_ENDIAN);
1953 /* Invalid length of sequence number */
1955 ti = proto_tree_add_text(um_header_tree, tvb, 0, 0, "Invalid sequence number length (%u bits)",
1956 p_rlc_lte_info->UMSequenceNumberLength);
1957 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
1958 "Invalid sequence number length (%u bits)",
1959 p_rlc_lte_info->UMSequenceNumberLength);
1963 tap_info->sequenceNumber = (guint16)sn;
1965 /* Show SN in info column */
1966 write_pdu_label_and_info(top_ti, um_header_ti, pinfo, " SN=%-4u", (guint16)sn);
1968 proto_item_set_len(um_header_ti, offset-start_offset);
1971 /*************************************/
1972 /* UM header extension */
1973 if (fixed_extension) {
1974 offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
1977 /* Extract these 2 flags from framing_info */
1978 first_includes_start = ((guint8)framing_info & 0x02) == 0;
1979 last_includes_end = ((guint8)framing_info & 0x01) == 0;
1981 if (global_rlc_lte_headers_expected) {
1982 /* There might not be any data, if only headers (plus control data) were logged */
1983 is_truncated = (tvb_length_remaining(tvb, offset) == 0);
1984 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
1988 PROTO_ITEM_SET_GENERATED(truncated_ti);
1989 expert_add_info_format(pinfo, truncated_ti, PI_SEQUENCE, PI_NOTE,
1990 "RLC PDU SDUs have been omitted");
1992 /* Show in the info column how long the data would be */
1993 for (n=0; n < s_number_of_extensions; n++) {
1994 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
1995 (n==0) ? first_includes_start : TRUE,
1997 offset += s_lengths[n];
2000 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2001 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2006 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2010 /* Show number of extensions in header root */
2011 if (s_number_of_extensions > 0) {
2012 proto_item_append_text(um_header_ti, " (%u extensions)", s_number_of_extensions);
2015 /* Call sequence analysis function now */
2016 if (((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2017 (p_get_proto_data(pinfo->fd, proto_mac_lte) != NULL)) ||
2018 ((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2019 (p_get_proto_data(pinfo->fd, proto_mac_lte) == NULL))) {
2021 guint16 lastSegmentOffset = offset;
2022 if (s_number_of_extensions >= 1) {
2024 lastSegmentOffset = offset;
2025 for (n=0; n < s_number_of_extensions; n++) {
2026 lastSegmentOffset += s_lengths[n];
2030 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
2032 s_number_of_extensions+1,
2033 offset, s_lengths[0],
2035 (guint16)sn, first_includes_start, last_includes_end,
2036 FALSE, /* UM doesn't re-segment */
2037 tap_info, um_header_tree);
2041 /*************************************/
2044 reassembly_info = (rlc_channel_reassembly_info *)g_hash_table_lookup(reassembly_report_hash,
2045 get_report_hash_key((guint16)sn, pinfo->fd->num,
2046 p_rlc_lte_info, FALSE));
2048 if (s_number_of_extensions > 0) {
2049 /* Show each data segment separately */
2051 for (n=0; n < s_number_of_extensions; n++) {
2052 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2053 (n==0) ? first_includes_start : TRUE,
2054 (n==0) ? reassembly_info : NULL,
2056 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2057 (n==0) ? first_includes_start : TRUE,
2059 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2060 offset += s_lengths[n];
2064 /* Final data element */
2065 show_PDU_in_tree(pinfo, tree, tvb, offset, -1, p_rlc_lte_info,
2066 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2067 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2069 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
2070 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2076 /* Dissect an AM STATUS PDU */
2077 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
2080 proto_item *status_ti,
2083 rlc_lte_info *p_rlc_lte_info,
2084 rlc_lte_tap_info *tap_info)
2087 guint64 ack_sn, nack_sn;
2088 guint16 nack_count = 0;
2089 guint64 e1 = 0, e2 = 0;
2090 guint64 so_start, so_end;
2091 int bit_offset = offset * 8;
2094 /****************************************************************/
2095 /* Part of RLC control PDU header */
2097 /* Control PDU Type (CPT) */
2098 cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
2099 ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN);
2101 /* Protest and stop - only know about STATUS PDUs */
2102 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
2103 "RLC Control frame type %u not handled", cpt);
2107 /* The Status PDU itself starts 4 bits into the byte */
2111 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2112 bit_offset, 10, &ack_sn, ENC_BIG_ENDIAN);
2114 write_pdu_label_and_info(top_ti, status_ti, pinfo, " ACK_SN=%-4u", (guint16)ack_sn);
2116 tap_info->ACKNo = (guint16)ack_sn;
2119 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2120 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2122 /* Skip another bit to byte-align the next bit... */
2125 /* Optional, extra fields */
2128 proto_item *nack_ti;
2130 /****************************/
2131 /* Read NACK_SN, E1, E2 */
2134 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
2135 bit_offset, 10, &nack_sn, ENC_BIG_ENDIAN);
2137 write_pdu_label_and_info(top_ti, NULL, pinfo, " NACK_SN=%-4u", (guint16)nack_sn);
2139 /* We shouldn't NACK the ACK_SN! */
2140 if (nack_sn == ack_sn) {
2141 expert_add_info_format(pinfo, nack_ti, PI_MALFORMED, PI_ERROR,
2142 "Status PDU shouldn't ACK and NACK the same sequence number (%" G_GINT64_MODIFIER "u)",
2146 /* Copy into struct, but don't exceed buffer */
2147 if (nack_count < MAX_NACKs) {
2148 tap_info->NACKs[nack_count++] = (guint16)nack_sn;
2151 /* Let it get bigger than the array for accurate stats... */
2156 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2157 bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2161 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
2162 bit_offset, 1, &e2, ENC_BIG_ENDIAN);
2164 /* Report as expert info */
2166 expert_add_info_format(pinfo, nack_ti, PI_SEQUENCE, PI_WARN,
2167 "Status PDU reports NACK (partial) on %s for UE %u",
2168 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2169 p_rlc_lte_info->ueid);
2172 expert_add_info_format(pinfo, nack_ti, PI_SEQUENCE, PI_WARN,
2173 "Status PDU reports NACK on %s for UE %u",
2174 val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2175 p_rlc_lte_info->ueid);
2182 /* Read SOstart, SOend */
2183 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
2184 bit_offset, 15, &so_start, ENC_BIG_ENDIAN);
2187 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
2188 bit_offset, 15, &so_end, ENC_BIG_ENDIAN);
2192 if ((guint16)so_end == 0x7fff) {
2193 write_pdu_label_and_info(top_ti, NULL, pinfo,
2194 " (SOstart=%u SOend=<END-OF_PDU>)",
2198 write_pdu_label_and_info(top_ti, NULL, pinfo,
2199 " (SOstart=%u SOend=%u)",
2200 (guint16)so_start, (guint16)so_end);
2203 /* Reset this flag here */
2208 if (nack_count > 0) {
2209 proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
2210 PROTO_ITEM_SET_GENERATED(count_ti);
2211 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
2212 tap_info->noOfNACKs = nack_count;
2215 /* Check that we've reached the end of the PDU. If not, show malformed */
2216 offset = (bit_offset+7) / 8;
2217 if (tvb_length_remaining(tvb, offset) > 0) {
2218 expert_add_info_format(pinfo, status_ti, PI_MALFORMED, PI_ERROR,
2219 "%cL %u bytes remaining after Status PDU complete",
2220 (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2221 tvb_length_remaining(tvb, offset));
2224 /* Set selected length of control tree */
2225 proto_item_set_len(status_ti, offset);
2227 /* Repeated NACK analysis & check ACK-SN is in range */
2228 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2229 (p_get_proto_data(pinfo->fd, proto_mac_lte) != NULL)) ||
2230 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2231 (p_get_proto_data(pinfo->fd, proto_mac_lte) == NULL))) {
2233 if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2234 checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2235 checkChannelACKWindow((guint16)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2241 /***************************************************/
2242 /* Acknowledged mode PDU */
2243 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
2246 rlc_lte_info *p_rlc_lte_info,
2248 rlc_lte_tap_info *tap_info)
2251 guint8 is_resegmented;
2253 guint8 fixed_extension;
2254 guint8 framing_info;
2255 gboolean first_includes_start;
2256 gboolean last_includes_end;
2258 proto_tree *am_header_tree;
2259 proto_item *am_header_ti;
2260 gint start_offset = offset;
2262 gboolean is_truncated;
2263 proto_item *truncated_ti;
2264 rlc_channel_reassembly_info *reassembly_info = NULL;
2265 sequence_analysis_state seq_anal_state = SN_OK;
2267 /* Hidden AM root */
2268 am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2269 tvb, offset, 0, "", "AM");
2270 PROTO_ITEM_SET_HIDDEN(am_ti);
2272 /* Add AM header subtree */
2273 am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2276 am_header_tree = proto_item_add_subtree(am_header_ti,
2277 ett_rlc_lte_am_header);
2279 /* First bit is Data/Control flag */
2280 is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
2281 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN);
2282 tap_info->isControlPDU = !is_data;
2285 /**********************/
2287 write_pdu_label_and_info(top_ti, NULL, pinfo, " [CONTROL]");
2289 /* Control PDUs are a completely separate format */
2290 dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2292 p_rlc_lte_info, tap_info);
2296 /******************************/
2297 /* Data PDU fixed header */
2299 /* Re-segmentation Flag (RF) field */
2300 is_resegmented = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
2301 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, ENC_BIG_ENDIAN);
2302 tap_info->isResegmented = is_resegmented;
2304 write_pdu_label_and_info(top_ti, NULL, pinfo,
2305 (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2308 polling = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
2309 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, ENC_BIG_ENDIAN);
2311 write_pdu_label_and_info(top_ti, NULL, pinfo, (polling) ? " (P) " : " ");
2313 proto_item_append_text(am_header_ti, " (P) ");
2317 framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3;
2318 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, ENC_BIG_ENDIAN);
2321 fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2;
2322 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, ENC_BIG_ENDIAN);
2324 /* Sequence Number */
2325 sn = tvb_get_ntohs(tvb, offset) & 0x03ff;
2326 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN);
2328 tap_info->sequenceNumber = sn;
2330 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2332 /***************************************/
2333 /* Dissect extra segment header fields */
2334 if (is_resegmented) {
2335 guint16 segmentOffset;
2337 /* Last Segment Field (LSF) */
2338 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2341 segmentOffset = tvb_get_ntohs(tvb, offset) & 0x7fff;
2342 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN);
2343 write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2347 /*************************************/
2348 /* AM header extension */
2349 if (fixed_extension) {
2350 offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
2353 /* Header is now complete */
2354 proto_item_set_len(am_header_ti, offset-start_offset);
2356 /* Show number of extensions in header root */
2357 if (s_number_of_extensions > 0) {
2358 proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2361 /* Extract these 2 flags from framing_info */
2362 first_includes_start = (framing_info & 0x02) == 0;
2363 last_includes_end = (framing_info & 0x01) == 0;
2365 /* There might not be any data, if only headers (plus control data) were logged */
2366 if (global_rlc_lte_headers_expected) {
2367 is_truncated = (tvb_length_remaining(tvb, offset) == 0);
2368 truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2372 PROTO_ITEM_SET_GENERATED(truncated_ti);
2373 expert_add_info_format(pinfo, truncated_ti, PI_SEQUENCE, PI_NOTE,
2374 "RLC PDU SDUs have been omitted");
2375 /* Show in the info column how long the data would be */
2376 for (n=0; n < s_number_of_extensions; n++) {
2377 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2378 (n==0) ? first_includes_start : TRUE,
2380 offset += s_lengths[n];
2383 show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2384 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2387 /* Just return now */
2391 PROTO_ITEM_SET_HIDDEN(truncated_ti);
2395 /* Call sequence analysis function now */
2396 if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2397 (p_get_proto_data(pinfo->fd, proto_mac_lte) != NULL)) ||
2398 ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2399 (p_get_proto_data(pinfo->fd, proto_mac_lte) == NULL))) {
2401 guint16 firstSegmentLength;
2402 guint16 lastSegmentOffset = offset;
2403 if (s_number_of_extensions >= 1) {
2405 for (n=0; n < s_number_of_extensions; n++) {
2406 lastSegmentOffset += s_lengths[n];
2409 firstSegmentLength = s_lengths[0];
2412 firstSegmentLength = tvb_length_remaining(tvb, offset);
2415 seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, FALSE,
2416 s_number_of_extensions+1,
2417 offset, firstSegmentLength,
2420 first_includes_start, last_includes_end,
2421 is_resegmented, tap_info, tree);
2425 /*************************************/
2428 reassembly_info = (rlc_channel_reassembly_info *)g_hash_table_lookup(reassembly_report_hash,
2429 get_report_hash_key((guint16)sn, pinfo->fd->num,
2430 p_rlc_lte_info, FALSE));
2432 if (s_number_of_extensions > 0) {
2433 /* Show each data segment separately */
2435 for (n=0; n < s_number_of_extensions; n++) {
2436 show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2437 (n==0) ? first_includes_start : TRUE,
2438 (n==0) ? reassembly_info : NULL,
2440 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2441 (n==0) ? first_includes_start : TRUE,
2443 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2444 offset += s_lengths[n];
2448 /* Final data element */
2449 if (tvb_length_remaining(tvb, offset) > 0) {
2450 show_PDU_in_tree(pinfo, tree, tvb, offset, -1, p_rlc_lte_info,
2451 ((s_number_of_extensions == 0) ? first_includes_start : TRUE) && last_includes_end,
2452 (s_number_of_extensions == 0) ? reassembly_info : NULL,
2454 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
2455 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
2459 /* Report that expected data was missing (unless we know it might happen) */
2460 if (!global_rlc_lte_headers_expected) {
2461 if (s_number_of_extensions > 0) {
2462 expert_add_info_format(pinfo, am_header_ti, PI_MALFORMED, PI_ERROR,
2463 "AM data PDU doesn't contain any data beyond extensions");
2466 expert_add_info_format(pinfo, am_header_ti, PI_MALFORMED, PI_ERROR,
2467 "AM data PDU doesn't contain any data");
2474 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2475 static gboolean dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
2479 struct rlc_lte_info *p_rlc_lte_info;
2482 gboolean infoAlreadySet = FALSE;
2483 gboolean umSeqNumLengthTagPresent = FALSE;
2485 /* This is a heuristic dissector, which means we get all the UDP
2486 * traffic not sent to a known dissector and not claimed by
2487 * a heuristic dissector called before us!
2490 if (!global_rlc_lte_heur) {
2494 /* Do this again on re-dissection to re-discover offset of actual PDU */
2496 /* Needs to be at least as long as:
2497 - the signature string
2498 - fixed header bytes
2500 - at least one byte of RLC PDU payload */
2501 if ((size_t)tvb_length_remaining(tvb, offset) < (strlen(RLC_LTE_START_STRING)+1+2)) {
2505 /* OK, compare with signature string */
2506 if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (gint)strlen(RLC_LTE_START_STRING)) != 0) {
2509 offset += (gint)strlen(RLC_LTE_START_STRING);
2512 /* If redissecting, use previous info struct (if available) */
2513 p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
2514 if (p_rlc_lte_info == NULL) {
2515 /* Allocate new info struct for this frame */
2516 p_rlc_lte_info = se_alloc0(sizeof(struct rlc_lte_info));
2517 infoAlreadySet = FALSE;
2520 infoAlreadySet = TRUE;
2524 /* Read fixed fields */
2525 p_rlc_lte_info->rlcMode = tvb_get_guint8(tvb, offset++);
2527 /* Read optional fields */
2528 while (tag != RLC_LTE_PAYLOAD_TAG) {
2529 /* Process next tag */
2530 tag = tvb_get_guint8(tvb, offset++);
2532 case RLC_LTE_UM_SN_LENGTH_TAG:
2533 p_rlc_lte_info->UMSequenceNumberLength = tvb_get_guint8(tvb, offset);
2535 umSeqNumLengthTagPresent = TRUE;
2537 case RLC_LTE_DIRECTION_TAG:
2538 p_rlc_lte_info->direction = tvb_get_guint8(tvb, offset);
2541 case RLC_LTE_PRIORITY_TAG:
2542 p_rlc_lte_info->priority = tvb_get_guint8(tvb, offset);
2545 case RLC_LTE_UEID_TAG:
2546 p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
2549 case RLC_LTE_CHANNEL_TYPE_TAG:
2550 p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
2553 case RLC_LTE_CHANNEL_ID_TAG:
2554 p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
2558 case RLC_LTE_PAYLOAD_TAG:
2559 /* Have reached data, so set payload length and get out of loop */
2560 p_rlc_lte_info->pduLength= tvb_length_remaining(tvb, offset);
2564 /* It must be a recognised tag */
2569 if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (umSeqNumLengthTagPresent == FALSE)) {
2570 /* Conditional field is not present */
2574 if (!infoAlreadySet) {
2575 /* Store info in packet */
2576 p_add_proto_data(pinfo->fd, proto_rlc_lte, p_rlc_lte_info);
2579 /**************************************/
2580 /* OK, now dissect as RLC LTE */
2582 /* Create tvb that starts at actual RLC PDU */
2583 rlc_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
2584 dissect_rlc_lte(rlc_tvb, pinfo, tree);
2590 /*****************************/
2591 /* Main dissection function. */
2592 /*****************************/
2594 static void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2596 proto_tree *rlc_lte_tree;
2597 proto_tree *context_tree;
2599 proto_item *context_ti;
2601 proto_item *mode_ti;
2603 struct rlc_lte_info *p_rlc_lte_info = NULL;
2605 /* Allocate and Zero tap struct */
2606 rlc_lte_tap_info *tap_info = ep_alloc0(sizeof(rlc_lte_tap_info));
2608 /* Set protocol name */
2609 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2611 /* Create protocol tree. */
2612 top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2613 rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2616 /* Look for packet info! */
2617 p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
2619 /* Can't dissect anything without it... */
2620 if (p_rlc_lte_info == NULL) {
2621 ti = proto_tree_add_text(rlc_lte_tree, tvb, offset, -1,
2622 "Can't dissect LTE RLC frame because no per-frame info was attached!");
2623 PROTO_ITEM_SET_GENERATED(ti);
2627 /*****************************************/
2628 /* Show context information */
2630 /* Create context root */
2631 context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2632 tvb, offset, 0, "", "Context");
2633 context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2634 PROTO_ITEM_SET_GENERATED(context_ti);
2636 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2637 tvb, 0, 0, p_rlc_lte_info->direction);
2638 PROTO_ITEM_SET_GENERATED(ti);
2640 mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2641 tvb, 0, 0, p_rlc_lte_info->rlcMode);
2642 PROTO_ITEM_SET_GENERATED(mode_ti);
2644 if (p_rlc_lte_info->ueid != 0) {
2645 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_ueid,
2646 tvb, 0, 0, p_rlc_lte_info->ueid);
2647 PROTO_ITEM_SET_GENERATED(ti);
2650 if ((p_rlc_lte_info->priority >= 1) && (p_rlc_lte_info->priority <=16)) {
2651 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_priority,
2652 tvb, 0, 0, p_rlc_lte_info->priority);
2653 PROTO_ITEM_SET_GENERATED(ti);
2656 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2657 tvb, 0, 0, p_rlc_lte_info->channelType);
2658 PROTO_ITEM_SET_GENERATED(ti);
2660 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2661 (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB)) {
2662 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2663 tvb, 0, 0, p_rlc_lte_info->channelId);
2664 PROTO_ITEM_SET_GENERATED(ti);
2667 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2668 tvb, 0, 0, p_rlc_lte_info->pduLength);
2669 PROTO_ITEM_SET_GENERATED(ti);
2671 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
2672 ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_um_sn_length,
2673 tvb, 0, 0, p_rlc_lte_info->UMSequenceNumberLength);
2674 PROTO_ITEM_SET_GENERATED(ti);
2677 /* Append highlights to top-level item */
2678 if (p_rlc_lte_info->ueid != 0) {
2679 proto_item_append_text(top_ti, " UEId=%u", p_rlc_lte_info->ueid);
2682 if (p_rlc_lte_info->channelId == 0) {
2683 proto_item_append_text(top_ti, " (%s) ",
2684 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
2687 proto_item_append_text(top_ti, " (%s:%u) ",
2688 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
2689 p_rlc_lte_info->channelId);
2692 /* Append context highlights to info column */
2693 write_pdu_label_and_info(top_ti, NULL, pinfo,
2695 (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
2696 val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
2697 if (p_rlc_lte_info->ueid != 0) {
2698 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%u ", p_rlc_lte_info->ueid);
2700 if (p_rlc_lte_info->channelId == 0) {
2701 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s",
2702 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
2705 write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
2706 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
2707 p_rlc_lte_info->channelId);
2710 /* Set context-info parts of tap struct */
2711 tap_info->rlcMode = p_rlc_lte_info->rlcMode;
2712 tap_info->direction = p_rlc_lte_info->direction;
2713 tap_info->priority = p_rlc_lte_info->priority;
2714 tap_info->ueid = p_rlc_lte_info->ueid;
2715 tap_info->channelType = p_rlc_lte_info->channelType;
2716 tap_info->channelId = p_rlc_lte_info->channelId;
2717 tap_info->pduLength = p_rlc_lte_info->pduLength;
2718 tap_info->UMSequenceNumberLength = p_rlc_lte_info->UMSequenceNumberLength;
2719 tap_info->loggedInMACFrame = (p_get_proto_data(pinfo->fd, proto_mac_lte) != NULL);
2721 tap_info->time = pinfo->fd->abs_ts;
2723 /* Reset this count */
2724 s_number_of_extensions = 0;
2726 /* Dissect the RLC PDU itself. Format depends upon mode... */
2727 switch (p_rlc_lte_info->rlcMode) {
2730 dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
2734 dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
2739 dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
2744 /* Predefined data (i.e. not containing a valid RLC header */
2745 proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, ENC_NA);
2746 write_pdu_label_and_info(top_ti, NULL, pinfo, " [%u-bytes]",
2747 tvb_length_remaining(tvb, offset));
2751 /* Error - unrecognised mode */
2752 expert_add_info_format(pinfo, mode_ti, PI_MALFORMED, PI_ERROR,
2753 "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
2757 /* Queue tap info */
2758 tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
2763 /* Initializes the hash tables each time a new
2764 * file is loaded or re-loaded in wireshark */
2766 rlc_lte_init_protocol(void)
2768 /* Destroy any existing hashes. */
2769 if (sequence_analysis_channel_hash) {
2770 g_hash_table_destroy(sequence_analysis_channel_hash);
2772 if (sequence_analysis_report_hash) {
2773 g_hash_table_destroy(sequence_analysis_report_hash);
2775 if (repeated_nack_channel_hash) {
2776 g_hash_table_destroy(repeated_nack_channel_hash);
2778 if (repeated_nack_report_hash) {
2779 g_hash_table_destroy(repeated_nack_report_hash);
2781 if (reassembly_report_hash) {
2782 g_hash_table_destroy(reassembly_report_hash);
2785 /* Now create them over */
2786 sequence_analysis_channel_hash = g_hash_table_new(rlc_channel_hash_func, rlc_channel_equal);
2787 sequence_analysis_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2789 repeated_nack_channel_hash = g_hash_table_new(rlc_channel_hash_func, rlc_channel_equal);
2790 repeated_nack_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2791 reassembly_report_hash = g_hash_table_new(rlc_result_hash_func, rlc_result_hash_equal);
2795 /* Configure number of PDCP SN bits to use for DRB channels.
2796 TODO: currently assume all UEs/Channels will use the same length... */
2797 void set_rlc_lte_drb_pdcp_seqnum_length(guint16 ueid _U_, guint8 drbid _U_,
2798 guint8 userplane_seqnum_length)
2800 signalled_pdcp_sn_bits = userplane_seqnum_length;
2804 void proto_register_rlc_lte(void)
2806 static hf_register_info hf[] =
2808 /**********************************/
2809 /* Items for decoding context */
2810 { &hf_rlc_lte_context,
2812 "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
2816 { &hf_rlc_lte_context_mode,
2818 "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
2822 { &hf_rlc_lte_context_direction,
2824 "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2825 "Direction of message", HFILL
2828 { &hf_rlc_lte_context_priority,
2830 "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
2834 { &hf_rlc_lte_context_ueid,
2836 "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
2837 "User Equipment Identifier associated with message", HFILL
2840 { &hf_rlc_lte_context_channel_type,
2842 "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
2843 "Channel Type associated with message", HFILL
2846 { &hf_rlc_lte_context_channel_id,
2848 "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
2849 "Channel ID associated with message", HFILL
2852 { &hf_rlc_lte_context_pdu_length,
2854 "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
2855 "Length of PDU (in bytes)", HFILL
2858 { &hf_rlc_lte_context_um_sn_length,
2859 { "UM Sequence number length",
2860 "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
2861 "Length of UM sequence number in bits", HFILL
2865 /* Transparent mode fields */
2868 "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
2869 "Transparent Mode", HFILL
2872 { &hf_rlc_lte_tm_data,
2874 "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
2875 "Transparent Mode Data", HFILL
2879 /* Unacknowledged mode fields */
2882 "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
2883 "Unackowledged Mode", HFILL
2886 { &hf_rlc_lte_um_header,
2888 "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
2889 "Unackowledged Mode Header", HFILL
2892 { &hf_rlc_lte_um_fi,
2894 "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
2898 { &hf_rlc_lte_um_fixed_e,
2900 "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
2901 "Extension in fixed part of UM header", HFILL
2904 { &hf_rlc_lte_um_sn,
2905 { "Sequence number",
2906 "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
2907 "Unacknowledged Mode Sequence Number", HFILL
2910 { &hf_rlc_lte_um_fixed_reserved,
2912 "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
2913 "Unacknowledged Mode Fixed header reserved bits", HFILL
2916 { &hf_rlc_lte_um_data,
2918 "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
2919 "Unacknowledged Mode Data", HFILL
2922 { &hf_rlc_lte_extension_part,
2924 "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
2928 { &hf_rlc_lte_extension_e,
2930 "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
2931 "Extension in extended part of the header", HFILL
2934 { &hf_rlc_lte_extension_li,
2935 { "Length Indicator",
2936 "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
2940 { &hf_rlc_lte_extension_padding,
2942 "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
2943 "Extension header padding", HFILL
2949 "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
2950 "Ackowledged Mode", HFILL
2953 { &hf_rlc_lte_am_header,
2955 "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
2956 "Ackowledged Mode Header", HFILL
2959 { &hf_rlc_lte_am_data_control,
2961 "rlc-lte.am.frame-type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80,
2962 "AM Frame Type (Control or Data)", HFILL
2965 { &hf_rlc_lte_am_rf,
2966 { "Re-segmentation Flag",
2967 "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
2968 "AM Re-segmentation Flag", HFILL
2973 "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
2977 { &hf_rlc_lte_am_fi,
2979 "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
2980 "AM Framing Info", HFILL
2983 { &hf_rlc_lte_am_fixed_e,
2985 "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
2986 "Fixed Extension Bit", HFILL
2989 { &hf_rlc_lte_am_fixed_sn,
2990 { "Sequence Number",
2991 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
2992 "AM Fixed Sequence Number", HFILL
2995 { &hf_rlc_lte_am_segment_lsf,
2996 { "Last Segment Flag",
2997 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3001 { &hf_rlc_lte_am_segment_so,
3003 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3007 { &hf_rlc_lte_am_data,
3009 "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3010 "Acknowledged Mode Data", HFILL
3014 { &hf_rlc_lte_am_cpt,
3015 { "Control PDU Type",
3016 "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3017 "AM Control PDU Type", HFILL
3020 { &hf_rlc_lte_am_ack_sn,
3021 { "ACK Sequence Number",
3022 "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3023 "Sequence Number we expect to receive next", HFILL
3026 { &hf_rlc_lte_am_e1,
3027 { "Extension bit 1",
3028 "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3032 { &hf_rlc_lte_am_e2,
3033 { "Extension bit 2",
3034 "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3038 { &hf_rlc_lte_am_nacks,
3039 { "Number of NACKs",
3040 "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3041 "Number of NACKs in this status PDU", HFILL
3044 { &hf_rlc_lte_am_nack_sn,
3045 { "NACK Sequence Number",
3046 "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3047 "Negative Acknowledgement Sequence Number", HFILL
3050 { &hf_rlc_lte_am_so_start,
3052 "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3053 "Segment Offset Start byte index", HFILL
3056 { &hf_rlc_lte_am_so_end,
3058 "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3059 "Segment Offset End byte index", HFILL
3063 { &hf_rlc_lte_predefined_pdu,
3064 { "Predefined data",
3065 "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3066 "Predefined test data", HFILL
3070 { &hf_rlc_lte_sequence_analysis,
3071 { "Sequence Analysis",
3072 "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3076 { &hf_rlc_lte_sequence_analysis_ok,
3078 "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3082 { &hf_rlc_lte_sequence_analysis_previous_frame,
3083 { "Previous frame for channel",
3084 "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3088 { &hf_rlc_lte_sequence_analysis_next_frame,
3089 { "Next frame for channel",
3090 "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3094 { &hf_rlc_lte_sequence_analysis_expected_sn,
3096 "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3100 { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3101 { "Frame info continued correctly",
3102 "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3106 { &hf_rlc_lte_sequence_analysis_mac_retx,
3107 { "Frame retransmitted by MAC",
3108 "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3112 { &hf_rlc_lte_sequence_analysis_retx,
3113 { "Retransmitted frame",
3114 "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3118 { &hf_rlc_lte_sequence_analysis_skipped,
3120 "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3124 { &hf_rlc_lte_sequence_analysis_repeated,
3126 "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3130 { &hf_rlc_lte_sequence_analysis_repeated_nack,
3132 "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3136 { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3137 { "Frame with previous status PDU",
3138 "rlc-lte.sequence-analysis.repeated-nack.original-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3143 { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3144 { "Out of range ACK",
3145 "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3149 { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3150 { "Frame with most recent SN",
3151 "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3156 { &hf_rlc_lte_reassembly_source,
3157 { "Reassembly Source",
3158 "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3162 { &hf_rlc_lte_reassembly_source_number_of_segments,
3163 { "Number of segments",
3164 "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3168 { &hf_rlc_lte_reassembly_source_total_length,
3170 "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3174 { &hf_rlc_lte_reassembly_source_segment,
3176 "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3180 { &hf_rlc_lte_reassembly_source_segment_sn,
3182 "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3186 { &hf_rlc_lte_reassembly_source_segment_framenum,
3188 "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3192 { &hf_rlc_lte_reassembly_source_segment_length,
3194 "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3199 { &hf_rlc_lte_header_only,
3200 { "RLC PDU Header only",
3201 "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3207 static gint *ett[] =
3210 &ett_rlc_lte_context,
3211 &ett_rlc_lte_um_header,
3212 &ett_rlc_lte_am_header,
3213 &ett_rlc_lte_extension_part,
3214 &ett_rlc_lte_sequence_analysis,
3215 &ett_rlc_lte_reassembly_source,
3216 &ett_rlc_lte_reassembly_source_segment
3219 static enum_val_t sequence_analysis_vals[] = {
3220 {"no-analysis", "No-Analysis", FALSE},
3221 {"mac-only", "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3222 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3226 module_t *rlc_lte_module;
3228 /* Register protocol. */
3229 proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3230 proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3231 proto_register_subtree_array(ett, array_length(ett));
3233 /* Allow other dissectors to find this one by name. */
3234 register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3236 /* Register the tap name */
3237 rlc_lte_tap = register_tap("rlc-lte");
3240 rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3242 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3243 "Do sequence analysis for AM channels",
3244 "Attempt to keep track of PDUs for AM channels, and point out problems",
3245 &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, FALSE);
3247 prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3248 "Do sequence analysis for UM channels",
3249 "Attempt to keep track of PDUs for UM channels, and point out problems",
3250 &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, FALSE);
3252 prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3253 "Call PDCP dissector for SRB PDUs",
3254 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
3255 "only be called for complete PDus (i.e. not segmented over RLC)",
3256 &global_rlc_lte_call_pdcp_for_srb);
3258 prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3259 "Call PDCP dissector for DRB PDUs",
3260 "Call PDCP dissector for user-plane PDUs. Note that without reassembly, it can"
3261 "only be called for complete PDUs (i.e. not segmented over RLC)",
3262 &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, FALSE);
3265 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3266 "Call RRC dissector for CCCH PDUs",
3267 "Call RRC dissector for CCCH PDUs",
3268 &global_rlc_lte_call_rrc);
3270 prefs_register_bool_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp",
3271 "Try Heuristic LTE-RLC over UDP framing",
3272 "When enabled, use heuristic dissector to find RLC-LTE frames sent with "
3274 &global_rlc_lte_heur);
3276 prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3277 "May see RLC headers only",
3278 "When enabled, if data is not present, don't report as an error, but instead "
3279 "add expert info to indicate that headers were omitted",
3280 &global_rlc_lte_headers_expected);
3282 prefs_register_bool_preference(rlc_lte_module, "reassembly",
3283 "Attempt SDU reassembly",
3284 "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3285 "more than one RLC PDU. Note: does not currently support out-of-order or "
3286 "re-segmentation. N.B. sequence analysis must also be turned on in order "
3287 "for reassembly to work",
3288 &global_rlc_lte_reassembly);
3291 register_init_routine(&rlc_lte_init_protocol);
3295 proto_reg_handoff_rlc_lte(void)
3297 /* Add as a heuristic UDP dissector */
3298 heur_dissector_add("udp", dissect_rlc_lte_heur, proto_rlc_lte);