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-rlc-lte.h"
38 #include "packet-pdcp-lte.h"
42 * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA)
43 * Radio Link Control (RLC) Protocol specification
47 - AM sequence analysis/re-assembly?
51 /* By default try to analyse the sequence of messages for UM channels */
52 static gboolean global_rlc_lte_sequence_analysis = TRUE;
54 /* By default don't call PDCP/RRC dissectors for SDU data */
55 static gboolean global_rlc_lte_call_pdcp = FALSE;
56 static gboolean global_rlc_lte_call_rrc = FALSE;
59 /* Initialize the protocol and registered fields. */
60 int proto_rlc_lte = -1;
62 static int rlc_lte_tap = -1;
64 /* Decoding context */
65 static int hf_rlc_lte_context_mode = -1;
66 static int hf_rlc_lte_context_direction = -1;
67 static int hf_rlc_lte_context_priority = -1;
68 static int hf_rlc_lte_context_ueid = -1;
69 static int hf_rlc_lte_context_channel_type = -1;
70 static int hf_rlc_lte_context_channel_id = -1;
71 static int hf_rlc_lte_context_pdu_length = -1;
72 static int hf_rlc_lte_context_um_sn_length = -1;
74 /* Transparent mode fields */
75 static int hf_rlc_lte_tm_data = -1;
77 /* Unacknowledged mode fields */
78 static int hf_rlc_lte_um_header = -1;
79 static int hf_rlc_lte_um_fi = -1;
80 static int hf_rlc_lte_um_fixed_e = -1;
81 static int hf_rlc_lte_um_sn = -1;
82 static int hf_rlc_lte_um_fixed_reserved = -1;
83 static int hf_rlc_lte_um_data = -1;
84 static int hf_rlc_lte_extension_part = -1;
86 /* Extended header (common to UM and AM) */
87 static int hf_rlc_lte_extension_e = -1;
88 static int hf_rlc_lte_extension_li = -1;
89 static int hf_rlc_lte_extension_padding = -1;
92 /* Acknowledged mode fields */
93 static int hf_rlc_lte_am_header = -1;
94 static int hf_rlc_lte_am_data_control = -1;
95 static int hf_rlc_lte_am_rf = -1;
96 static int hf_rlc_lte_am_p = -1;
97 static int hf_rlc_lte_am_fi = -1;
98 static int hf_rlc_lte_am_fixed_e = -1;
99 static int hf_rlc_lte_am_fixed_sn = -1;
100 static int hf_rlc_lte_am_segment_lsf = -1;
101 static int hf_rlc_lte_am_segment_so = -1;
102 static int hf_rlc_lte_am_data = -1;
105 static int hf_rlc_lte_am_cpt = -1;
106 static int hf_rlc_lte_am_ack_sn = -1;
107 static int hf_rlc_lte_am_e1 = -1;
108 static int hf_rlc_lte_am_e2 = -1;
109 static int hf_rlc_lte_am_nack_sn = -1;
110 static int hf_rlc_lte_am_so_start = -1;
111 static int hf_rlc_lte_am_so_end = -1;
113 static int hf_rlc_lte_predefined_pdu = -1;
115 /* Sequence Analysis */
116 static int hf_rlc_lte_sequence_analysis = -1;
117 static int hf_rlc_lte_sequence_analysis_previous_frame = -1;
118 static int hf_rlc_lte_sequence_analysis_expected_sn = -1;
119 static int hf_rlc_lte_sequence_analysis_framing_info_correct = -1;
123 static int ett_rlc_lte = -1;
124 static int ett_rlc_lte_um_header = -1;
125 static int ett_rlc_lte_am_header = -1;
126 static int ett_rlc_lte_extension_part = -1;
127 static int ett_rlc_lte_sequence_analysis = -1;
130 static const value_string direction_vals[] =
132 { DIRECTION_UPLINK, "Uplink"},
133 { DIRECTION_DOWNLINK, "Downlink"},
137 static const value_string rlc_mode_short_vals[] =
139 { RLC_TM_MODE, "TM"},
140 { RLC_UM_MODE, "UM"},
141 { RLC_AM_MODE, "AM"},
142 { RLC_PREDEF, "PREDEFINED"},
146 static const value_string rlc_mode_vals[] =
148 { RLC_TM_MODE, "Transparent Mode"},
149 { RLC_UM_MODE, "Unacknowledged Mode"},
150 { RLC_AM_MODE, "Acknowledged Mode"},
155 static const value_string rlc_channel_type_vals[] =
157 { CHANNEL_TYPE_CCCH, "CCCH"},
158 { CHANNEL_TYPE_BCCH, "BCCH"},
159 { CHANNEL_TYPE_PCCH, "PCCH"},
160 { CHANNEL_TYPE_SRB, "SRB"},
161 { CHANNEL_TYPE_DRB, "DRB"},
166 static const value_string framing_info_vals[] =
168 { 0, "First byte begins a RLC SDU and last byte ends a RLC SDU"},
169 { 1, "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
170 { 2, "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
171 { 3, "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
175 static const value_string fixed_extension_vals[] =
177 { 0, "Data field follows from the octet following the fixed part of the header"},
178 { 1, "A set of E field and LI field follows from the octet following the fixed part of the header"},
182 static const value_string extension_extension_vals[] =
184 { 0, "Data field follows from the octet following the LI field following this E field"},
185 { 1, "A set of E field and LI field follows from the bit following the LI field following this E field"},
189 static const value_string data_or_control_vals[] =
196 static const value_string resegmentation_flag_vals[] =
199 { 1, "AMD PDU segment"},
203 static const value_string polling_bit_vals[] =
205 { 0, "Status report not requested"},
206 { 1, "Status report is requested"},
211 static const value_string lsf_vals[] =
213 { 0, "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
214 { 1, "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
219 static const value_string control_pdu_type_vals[] =
225 static const value_string am_e1_vals[] =
227 { 0, "A set of NACK_SN, E1 and E2 does not follow"},
228 { 1, "A set of NACK_SN, E1 and E2 follows"},
232 static const value_string am_e2_vals[] =
234 { 0, "A set of SOstart and SOend does not follow for this NACK_SN"},
235 { 1, "A set of SOstart and SOend follows for this NACK_SN"},
240 extern int proto_pdcp_lte;
243 /**********************************************************************************/
244 /* These are for keeping track of UM/AM extension headers, and the lengths found */
246 guint8 s_number_of_extensions = 0;
247 #define MAX_RLC_SDUS 64
248 guint16 s_lengths[MAX_RLC_SDUS];
251 /* Dissect extension headers (common to both UM and AM) */
252 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo,
257 guint64 extension = 1;
260 /* Reset this count */
261 s_number_of_extensions = 0;
263 while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
264 proto_tree *extension_part_tree;
265 proto_item *extension_part_ti;
267 isOdd = (s_number_of_extensions % 2);
269 /* Extension part subtree */
270 extension_part_ti = proto_tree_add_string_format(tree,
271 hf_rlc_lte_extension_part,
275 extension_part_tree = proto_item_add_subtree(extension_part_ti,
276 ett_rlc_lte_extension_part);
278 /* Read next extension */
279 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
280 (offset*8) + ((isOdd) ? 4 : 0),
284 /* Read length field */
285 proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
286 (offset*8) + ((isOdd) ? 5 : 1),
290 proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length);
292 /* Move on to byte of next extension */
299 s_lengths[s_number_of_extensions++] = (guint16)length;
302 /* May need to skip padding after last extension part */
303 isOdd = (s_number_of_extensions % 2);
308 padding = tvb_get_guint8(tvb, offset) & 0x0f;
309 ti = proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
310 tvb, offset, 1, FALSE);
312 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
313 "Extension Header padding not zero (found 0x%x)", padding);
322 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
323 whether or not the beginning and end are included in this packet */
324 static void show_PDU_in_info(packet_info *pinfo,
327 gboolean first_includes_start,
328 gboolean last_includes_end)
330 /* Reflect this PDU in the info column */
331 col_append_fstr(pinfo->cinfo, COL_INFO, " %s%u-byte%s%s",
332 (first_includes_start) ? "[" : "..",
334 (length > 1) ? "s" : "",
335 (last_includes_end) ? "]" : "..");
337 proto_item_append_text(top_ti, " %s%u-byte%s%s",
338 (first_includes_start) ? "[" : "..",
340 (length > 1) ? "s" : "",
341 (last_includes_end) ? "]" : "..");
345 static void show_AM_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, gint offset, gint length,
346 rlc_lte_info *rlc_info, gboolean whole_pdu)
348 proto_item *data_ti = proto_tree_add_item(tree, hf_rlc_lte_am_data, tvb, offset, length, FALSE);
350 /* Decode signalling PDUs as PDCP */
351 if (global_rlc_lte_call_pdcp && whole_pdu) {
352 if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
353 /* Attempt to decode payload using LTE PDCP dissector */
354 tvbuff_t *pdcp_tvb = tvb_new_subset(tvb, offset, length, length);
355 volatile dissector_handle_t protocol_handle;
357 struct pdcp_lte_info *p_pdcp_lte_info;
359 /* Reuse or allocate struct */
360 p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
361 if (p_pdcp_lte_info == NULL) {
362 p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
364 if (p_pdcp_lte_info == NULL) {
368 p_pdcp_lte_info->channelType = Channel_DCCH;
369 p_pdcp_lte_info->direction = rlc_info->direction;
370 p_pdcp_lte_info->no_header_pdu = FALSE;
371 p_pdcp_lte_info->plane = SIGNALING_PLANE;
373 p_pdcp_lte_info->rohc_compression = FALSE;
375 /* Store info in packet */
376 p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
378 /* Get dissector handle */
379 protocol_handle = find_dissector("pdcp-lte");
382 call_dissector_only(protocol_handle, pdcp_tvb, pinfo, tree);
388 PROTO_ITEM_SET_HIDDEN(data_ti);
394 /*********************************************************************/
395 /* UM/AM sequence analysis */
397 /* Types for RLC channel hash table */
398 /* This table is maintained during initial dissection of RLC */
399 /* frames, mapping from rlc_channel_hash_key -> rlc_channel_status */
408 } rlc_channel_hash_key;
410 /* Conversation-type status for channel */
413 guint16 previousSequenceNumber;
414 guint32 previousFrameNum;
415 gboolean previousSegmentIncomplete;
416 } rlc_channel_status;
419 /* Hash table functions for RLC channels */
422 static gint rlc_channel_equal(gconstpointer v, gconstpointer v2)
424 const rlc_channel_hash_key* val1 = v;
425 const rlc_channel_hash_key* val2 = v2;
427 /* All fields must match */
428 return ((val1->ueId == val2->ueId) &&
429 (val1->channelType == val2->channelType) &&
430 (val1->channelId == val2->channelId) &&
431 (val1->direction == val2->direction));
434 /* Compute a hash value for a given key. */
435 static guint rlc_channel_hash_func(gconstpointer v)
437 const rlc_channel_hash_key* val1 = v;
439 /* TODO: check/reduce multipliers */
440 return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
443 /* The channel hash table instance itself */
444 static GHashTable *rlc_lte_channel_hash = NULL;
449 /* Types for frame report hash table */
450 /* This is a table from framenum -> state_report_in_frame */
451 /* This is necessary because the per-packet info is already being used */
452 /* for conext information before the dissector is called */
454 /* Info to attach to frame when first read, recording what to show about sequence */
457 guint8 sequenceExpectedCorrect;
458 guint16 sequenceExpected;
459 guint32 previousFrameNum;
460 guint8 previousSegmentIncomplete;
461 } state_report_in_frame;
464 /* Hash table functions for frame reports */
467 static gint rlc_frame_equal(gconstpointer v, gconstpointer v2)
472 /* Compute a hash value for a given key. */
473 static guint rlc_frame_hash_func(gconstpointer v)
475 return GPOINTER_TO_UINT(v);
478 /* The frame report hash table instance itself */
479 static GHashTable *rlc_lte_frame_report_hash = NULL;
483 /* Add to the tree values associated with sequence analysis for this frame */
484 static void addChannelSequenceInfo(state_report_in_frame *p,
485 guint16 sequenceNumber,
486 gboolean newSegmentStarted,
487 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
489 proto_tree *seqnum_tree;
490 proto_item *seqnum_ti;
494 seqnum_ti = proto_tree_add_string_format(tree,
495 hf_rlc_lte_sequence_analysis,
498 "Sequence Analysis");
499 seqnum_tree = proto_item_add_subtree(seqnum_ti,
500 ett_rlc_lte_sequence_analysis);
501 PROTO_ITEM_SET_GENERATED(seqnum_ti);
503 /* Previous channel frame */
504 if (p->previousFrameNum != 0) {
505 proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
506 tvb, 0, 0, p->previousFrameNum);
509 /* Expected sequence number */
510 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
511 tvb, 0, 0, p->sequenceExpected);
512 PROTO_ITEM_SET_GENERATED(ti);
513 if (!p->sequenceExpectedCorrect) {
514 /* Incorrect sequence number */
515 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
516 "Wrong Sequence Number - got %u, expected %u",
517 sequenceNumber, p->sequenceExpected);
520 /* Correct sequence number, so check frame indication bits consistent */
521 if (p->previousSegmentIncomplete) {
522 /* Previous segment was incomplete, so this PDU should continue it */
523 if (newSegmentStarted) {
524 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
526 if (!p->sequenceExpectedCorrect) {
527 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
528 "Last segment of previous PDU was not continued");
532 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
537 /* Previous segment was complete, so this PDU should start a new one */
538 if (!newSegmentStarted) {
539 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
541 if (!p->sequenceExpectedCorrect) {
542 expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
543 "Last segment of previous PDU was complete, but new segment was not started");
547 ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
552 PROTO_ITEM_SET_GENERATED(ti);
556 /* Update the channel status and set report for this frame */
557 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
558 rlc_lte_info *p_rlc_lte_info,
559 guint16 sequenceNumber,
560 gboolean first_includes_start, gboolean last_includes_end,
563 rlc_channel_hash_key channel_key;
564 rlc_channel_hash_key *p_channel_key;
565 rlc_channel_status *p_channel_status;
566 state_report_in_frame *p_report_in_frame = NULL;
567 guint8 createdChannel = FALSE;
568 guint16 expectedSequenceNumber;
570 /* If find stat_report_in_frame already, use that and get out */
571 if (pinfo->fd->flags.visited) {
572 p_report_in_frame = (state_report_in_frame*)g_hash_table_lookup(rlc_lte_frame_report_hash,
574 if (p_report_in_frame != NULL) {
575 addChannelSequenceInfo(p_report_in_frame, sequenceNumber, first_includes_start,
580 /* Give up - we must have tried already... */
586 /**************************************************/
587 /* Create or find an entry for this channel state */
588 channel_key.ueId = p_rlc_lte_info->ueid;
589 channel_key.channelType = p_rlc_lte_info->channelType;
590 channel_key.channelId = p_rlc_lte_info->channelId;
591 channel_key.direction = p_rlc_lte_info->direction;
593 /* Do the table lookup */
594 p_channel_status = (rlc_channel_status*)g_hash_table_lookup(rlc_lte_channel_hash, &channel_key);
596 /* Create table entry if necessary */
597 if (p_channel_status == NULL) {
598 createdChannel = TRUE;
600 /* Allocate a new key and value */
601 p_channel_key = se_alloc(sizeof(rlc_channel_hash_key));
602 p_channel_status = se_alloc0(sizeof(rlc_channel_status));
604 /* Just give up if allocations failed */
605 if (!p_channel_key || !p_channel_status) {
609 /* Copy key contents */
610 memcpy(p_channel_key, &channel_key, sizeof(rlc_channel_hash_key));
613 g_hash_table_insert(rlc_lte_channel_hash, p_channel_key, p_channel_status);
616 /* Create space for frame state_report */
617 p_report_in_frame = se_alloc(sizeof(state_report_in_frame));
619 /* Set expected sequence number.
620 Wrap according to number of bits in SN */
621 if (!createdChannel) {
622 guint16 snLimit = 4096; /* AM default */
623 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
624 if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
631 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
634 expectedSequenceNumber = 0;
637 /* Set report info regarding sequence number */
638 if (sequenceNumber == expectedSequenceNumber) {
639 p_report_in_frame->sequenceExpectedCorrect = TRUE;
642 p_report_in_frame->sequenceExpectedCorrect = FALSE;
644 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
645 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
646 p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
648 /* Associate with this frame number */
649 g_hash_table_insert(rlc_lte_frame_report_hash, &pinfo->fd->num, p_report_in_frame);
651 /* Update channel status to remember *this* frame */
652 p_channel_status->previousFrameNum = pinfo->fd->num;
653 p_channel_status->previousSequenceNumber = sequenceNumber;
654 p_channel_status->previousSegmentIncomplete = !last_includes_end;
656 /* Add state report for this frame into tree */
657 addChannelSequenceInfo(p_report_in_frame, sequenceNumber, first_includes_start,
663 /***************************************************/
664 /* Unacknowledged mode PDU */
665 static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
668 rlc_lte_info *p_rlc_lte_info,
669 proto_item *top_ti _U_)
671 proto_item *raw_tm_ti;
673 /* Remaining bytes are all data */
674 raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, FALSE);
675 if (!global_rlc_lte_call_rrc) {
676 col_append_fstr(pinfo->cinfo, COL_INFO, " [%u-bytes]",
677 tvb_length_remaining(tvb, offset));
680 if (global_rlc_lte_call_rrc) {
681 tvbuff_t *rrc_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
682 volatile dissector_handle_t protocol_handle = 0;
684 switch (p_rlc_lte_info->channelType) {
685 case CHANNEL_TYPE_CCCH:
686 if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
687 protocol_handle = find_dissector("lte-rrc.ul.ccch");
690 protocol_handle = find_dissector("lte-rrc.dl.ccch");
694 case CHANNEL_TYPE_BCCH:
695 /* TODO: Problem is don't know which transport channel... */
698 case CHANNEL_TYPE_PCCH:
699 protocol_handle = find_dissector("lte-rrc.pcch");
702 case CHANNEL_TYPE_SRB:
703 case CHANNEL_TYPE_DRB:
705 /* Shouldn't happen, just return...
706 TODO: should flag an error? */
710 /* Hide raw view of bytes */
711 PROTO_ITEM_SET_HIDDEN(raw_tm_ti);
713 /* Call it (catch exceptions) */
715 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree);
725 /***************************************************/
726 /* Unacknowledged mode PDU */
727 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
730 rlc_lte_info *p_rlc_lte_info,
732 rlc_lte_tap_info *tap_info)
734 guint64 framing_info;
735 gboolean first_includes_start;
736 gboolean last_includes_end;
737 guint64 fixed_extension;
739 gint start_offset = offset;
740 proto_tree *um_header_tree;
741 proto_item *um_header_ti;
743 /* Add UM header subtree */
744 um_header_ti = proto_tree_add_string_format(tree,
745 hf_rlc_lte_um_header,
749 um_header_tree = proto_item_add_subtree(um_header_ti,
750 ett_rlc_lte_um_header);
753 /*******************************/
754 /* Fixed UM header */
755 if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_5_BITS) {
756 /* Framing info (2 bits) */
757 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
759 &framing_info, FALSE);
761 /* Extension (1 bit) */
762 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
764 &fixed_extension, FALSE);
766 /* Sequence Number (5 bit) */
767 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
772 else if (p_rlc_lte_info->UMSequenceNumberLength == UM_SN_LENGTH_10_BITS) {
776 /* Check 3 Reserved bits */
777 reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5;
778 ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, FALSE);
780 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
781 "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
784 /* Framing info (2 bits) */
785 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
786 tvb, (offset*8)+3, 2,
787 &framing_info, FALSE);
789 /* Extension (1 bit) */
790 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
792 &fixed_extension, FALSE);
794 /* Sequence Number (10 bits) */
795 proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
801 /* Invalid length of sequence number */
803 ti = proto_tree_add_text(um_header_tree, tvb, 0, 0, "Invalid sequence number length (%u bits)",
804 p_rlc_lte_info->UMSequenceNumberLength);
805 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
806 "Invalid sequence number length (%u bits)",
807 p_rlc_lte_info->UMSequenceNumberLength);
811 tap_info->sequenceNumber = (guint16)sn;
813 /* Show SN in info column */
814 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%04u", (guint16)sn);
816 /* Show SN in UM header root */
817 proto_item_append_text(um_header_ti, " (SN=%u)", (guint16)sn);
818 proto_item_set_len(um_header_ti, offset-start_offset);
821 /*************************************/
822 /* UM header extension */
823 if (fixed_extension) {
824 offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
828 /* Extract these 2 flags from framing_info */
829 first_includes_start = ((guint8)framing_info & 0x02) == 0;
830 last_includes_end = ((guint8)framing_info & 0x01) == 0;
833 /* Call sequence analysis function now */
834 if (global_rlc_lte_sequence_analysis) {
835 checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
836 (guint16)sn, first_includes_start, last_includes_end,
841 /*************************************/
843 if (s_number_of_extensions > 0) {
844 /* Show each data segment separately */
846 for (n=0; n < s_number_of_extensions; n++) {
847 proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, s_lengths[n], FALSE);
848 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
849 (n==0) ? first_includes_start : TRUE,
851 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
852 offset += s_lengths[n];
856 /* Final data element */
857 proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, -1, FALSE);
858 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
859 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
866 /* Dissect an AM STATUS PDU */
867 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
870 proto_item *status_ti,
873 rlc_lte_tap_info *tap_info)
876 guint64 ack_sn, nack_sn;
877 guint nack_count = 0;
878 guint64 e1 = 0, e2 = 0;
879 guint64 so_start, so_end;
880 int bit_offset = offset * 8;
883 /****************************************************************/
884 /* Part of RLC control PDU header */
886 /* Control PDU Type (CPT) */
887 cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
888 ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, FALSE);
890 /* Protest and stop - only know about STATUS PDUs */
891 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
892 "RLC Control frame type %u not handled", cpt);
897 /*****************************************************************/
900 /* The PDU itself starts 4 bits into the byte */
904 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
905 bit_offset, 10, &ack_sn, FALSE);
907 col_append_fstr(pinfo->cinfo, COL_INFO, " ACK_SN=%u", (guint16)ack_sn);
908 proto_item_append_text(top_ti, " ACK_SN=%u", (guint16)ack_sn);
909 proto_item_append_text(status_ti, " ACK_SN=%u", (guint16)ack_sn);
910 tap_info->ACKNo = (guint16)ack_sn;
913 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
914 bit_offset, 1, &e1, FALSE);
916 /* Skip another bit to byte-align the next bit... */
919 /* Optional, extra fields */
924 /****************************/
925 /* Read NACK_SN, E1, E2 */
928 nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
929 bit_offset, 10, &nack_sn, FALSE);
932 col_append_fstr(pinfo->cinfo, COL_INFO, " NACK_SN=%u", (guint16)nack_sn);
933 proto_item_append_text(top_ti, " NACK_SN=%u", (guint16)nack_sn);
934 tap_info->NACKs[nack_count] = (guint16)nack_sn;
937 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
938 bit_offset, 1, &e1, FALSE);
942 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
943 bit_offset, 1, &e2, FALSE);
945 /* Report as expert info */
947 expert_add_info_format(pinfo, nack_ti, PI_SEQUENCE, PI_WARN,
948 "Status PDU reports NACK for SN=%u (partial)", (guint16)nack_sn);
951 expert_add_info_format(pinfo, nack_ti, PI_SEQUENCE, PI_WARN,
952 "Status PDU reports NACK for SN=%u", (guint16)nack_sn);
959 /* Read SOstart, SOend */
960 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
961 bit_offset, 15, &so_start, FALSE);
964 proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
965 bit_offset, 15, &so_end, FALSE);
969 if ((guint16)so_end == 0x7fff) {
970 col_append_fstr(pinfo->cinfo, COL_INFO, " (SOstart=%u SOend=<END-OF_PDU>)",
974 col_append_fstr(pinfo->cinfo, COL_INFO, " (SOstart=%u SOend=%u)",
975 (guint16)so_start, (guint16)so_end);
978 /* Reset this flag here */
983 if (nack_count > 0) {
984 proto_item_append_text(status_ti, " (%u NACKs)", nack_count);
985 tap_info->noOfNACKs = nack_count;
988 /* Check that we've reached the end of the PDU. If not, show malformed */
989 offset = (bit_offset+7) / 8;
990 if (tvb_length_remaining(tvb, offset) > 0) {
991 expert_add_info_format(pinfo, status_ti, PI_MALFORMED, PI_ERROR,
992 "%u bytes remaining after Status PDU complete",
993 tvb_length_remaining(tvb, offset));
996 /* Set selected length of control tree */
997 proto_item_set_len(status_ti, offset);
1001 /***************************************************/
1002 /* Acknowledged mode PDU */
1003 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
1006 rlc_lte_info *p_rlc_lte_info,
1008 rlc_lte_tap_info *tap_info)
1013 guint8 fixed_extension;
1014 guint8 framing_info;
1015 gboolean first_includes_start;
1016 gboolean last_includes_end;
1017 proto_tree *am_header_tree;
1018 proto_item *am_header_ti;
1019 gint start_offset = offset;
1022 /* Add AM header subtree */
1023 am_header_ti = proto_tree_add_string_format(tree,
1024 hf_rlc_lte_am_header,
1028 am_header_tree = proto_item_add_subtree(am_header_ti,
1029 ett_rlc_lte_am_header);
1032 /*******************************************/
1033 /* First bit is Data/Control flag */
1034 is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
1035 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, FALSE);
1036 tap_info->isControlPDU = !is_data;
1038 /**************************************************/
1040 col_append_str(pinfo->cinfo, COL_INFO, " [CONTROL]");
1041 proto_item_append_text(top_ti, " [CONTROL]");
1043 /* Control PDUs are a completely separate format */
1044 dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
1045 offset, top_ti, tap_info);
1049 /******************************/
1050 /* Data PDU fixed header */
1052 /* Re-segmentation Flag (RF) field */
1053 is_segment = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
1054 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, FALSE);
1055 tap_info->isResegmented = is_segment;
1057 col_append_str(pinfo->cinfo, COL_INFO, (is_segment) ? " [DATA-SEGMENT]" : " [DATA]");
1058 proto_item_append_text(top_ti, (is_segment) ? " [DATA-SEGMENT]" : " [DATA]");
1062 polling = (tvb_get_guint8(tvb, offset) & 0x20) >> 5;
1063 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, FALSE);
1064 col_append_str(pinfo->cinfo, COL_INFO, (polling) ? " (P) " : " ");
1065 proto_item_append_text(top_ti, (polling) ? " (P) " : " ");
1067 proto_item_append_text(am_header_ti, " (P)");
1071 framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3;
1072 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, FALSE);
1075 fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2;
1076 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, FALSE);
1078 /* Sequence Number */
1079 sn = tvb_get_ntohs(tvb, offset) & 0x03ff;
1080 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, FALSE);
1082 tap_info->sequenceNumber = sn;
1084 col_append_fstr(pinfo->cinfo, COL_INFO, "sn=%u", sn);
1085 proto_item_append_text(top_ti, " (SN=%u)", sn);
1087 /* Show SN in AM header root */
1088 proto_item_append_text(am_header_ti, " (SN=%u)", sn);
1090 /***************************************/
1091 /* Dissect extra segment header fields */
1093 guint16 segmentOffset;
1095 /* Last Segment Field (LSF) */
1096 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, FALSE);
1099 segmentOffset = tvb_get_ntohs(tvb, offset) & 0x7fff;
1100 proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, FALSE);
1101 col_append_fstr(pinfo->cinfo, COL_INFO, " SO=%u ", segmentOffset);
1102 proto_item_append_text(top_ti, " SO=%u ", segmentOffset);
1107 /*************************************/
1108 /* AM header extension */
1109 if (fixed_extension) {
1110 offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
1113 /* Head is now complete */
1114 proto_item_set_len(am_header_ti, offset-start_offset);
1116 /* Extract these 2 flags from framing_info */
1117 first_includes_start = (framing_info & 0x02) == 0;
1118 last_includes_end = (framing_info & 0x01) == 0;
1121 /* Call sequence analysis function now (pretty limited for AM) */
1123 if (global_rlc_lte_sequence_analysis) {
1124 checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, (guint16)sn,
1125 first_includes_start, last_includes_end,
1131 /*************************************/
1133 if (s_number_of_extensions > 0) {
1134 /* Show each data segment separately */
1136 for (n=0; n < s_number_of_extensions; n++) {
1137 show_AM_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
1138 first_includes_start && last_includes_end);
1139 show_PDU_in_info(pinfo, top_ti, s_lengths[n],
1140 (n==0) ? first_includes_start : TRUE,
1142 tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
1143 offset += s_lengths[n];
1147 /* Final data element */
1148 if (tvb_length_remaining(tvb, offset) > 0) {
1149 show_AM_PDU_in_tree(pinfo, tree, tvb, offset, -1, p_rlc_lte_info,
1150 first_includes_start && last_includes_end);
1151 show_PDU_in_info(pinfo, top_ti, (guint16)tvb_length_remaining(tvb, offset),
1152 (s_number_of_extensions == 0) ? first_includes_start : TRUE,
1156 if (s_number_of_extensions > 0) {
1157 expert_add_info_format(pinfo, am_header_ti, PI_MALFORMED, PI_ERROR,
1158 "AM data PDU doesn't contain any data beyond extensions");
1161 expert_add_info_format(pinfo, am_header_ti, PI_MALFORMED, PI_ERROR,
1162 "AM data PDU doesn't contain any data");
1169 /* Forwad declarations */
1170 void proto_reg_handoff_rlc_lte(void);
1171 void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
1173 /* Heuristic dissection */
1174 static gboolean global_rlc_lte_heur = FALSE;
1176 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
1177 static gboolean dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
1181 struct rlc_lte_info *p_rlc_lte_info;
1184 gboolean infoAlreadySet = FALSE;
1185 gboolean umSeqNumLengthTagPresent = FALSE;
1187 /* This is a heuristic dissector, which means we get all the UDP
1188 * traffic not sent to a known dissector and not claimed by
1189 * a heuristic dissector called before us!
1192 if (!global_rlc_lte_heur) {
1196 /* If redissecting, use previous info struct (if available) */
1197 p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
1198 if (p_rlc_lte_info == NULL) {
1199 /* Allocate new info struct for this frame */
1200 p_rlc_lte_info = se_alloc0(sizeof(struct rlc_lte_info));
1201 if (p_rlc_lte_info == NULL) {
1204 infoAlreadySet = FALSE;
1207 infoAlreadySet = TRUE;
1210 /* Do this again on re-dissection to re-discover offset of actual PDU */
1212 /* Needs to be at least as long as:
1213 - the signature string
1214 - fixed header bytes
1216 - at least one byte of RLC PDU payload */
1217 if ((size_t)tvb_length_remaining(tvb, offset) < (strlen(RLC_LTE_START_STRING)+1+2)) {
1221 /* OK, compare with signature string */
1222 if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (gint)strlen(RLC_LTE_START_STRING)) != 0) {
1225 offset += (gint)strlen(RLC_LTE_START_STRING);
1227 /* Read fixed fields */
1228 p_rlc_lte_info->rlcMode = tvb_get_guint8(tvb, offset++);
1230 /* Read optional fields */
1231 while (tag != RLC_LTE_PAYLOAD_TAG) {
1232 /* Process next tag */
1233 tag = tvb_get_guint8(tvb, offset++);
1235 case RLC_LTE_UM_SN_LENGTH_TAG:
1236 p_rlc_lte_info->UMSequenceNumberLength = tvb_get_guint8(tvb, offset);
1238 umSeqNumLengthTagPresent = TRUE;
1240 case RLC_LTE_DIRECTION_TAG:
1241 p_rlc_lte_info->direction = tvb_get_guint8(tvb, offset);
1244 case RLC_LTE_PRIORITY_TAG:
1245 p_rlc_lte_info->priority = tvb_get_guint8(tvb, offset);
1248 case RLC_LTE_UEID_TAG:
1249 p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
1252 case RLC_LTE_CHANNEL_TYPE_TAG:
1253 p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
1256 case RLC_LTE_CHANNEL_ID_TAG:
1257 p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
1261 case RLC_LTE_PAYLOAD_TAG:
1262 /* Have reached data, so set payload length and get out of loop */
1263 p_rlc_lte_info->pduLength= tvb_length_remaining(tvb, offset);
1267 /* It must be a recognised tag */
1272 if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (umSeqNumLengthTagPresent == FALSE)) {
1273 /* Conditional field is not present */
1277 if (!infoAlreadySet) {
1278 /* Store info in packet */
1279 p_add_proto_data(pinfo->fd, proto_rlc_lte, p_rlc_lte_info);
1282 /**************************************/
1283 /* OK, now dissect as RLC LTE */
1285 /* Create tvb that starts at actual RLC PDU */
1286 rlc_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
1287 dissect_rlc_lte(rlc_tvb, pinfo, tree);
1292 /*****************************/
1293 /* Main dissection function. */
1294 /*****************************/
1296 void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1298 proto_tree *rlc_lte_tree;
1301 proto_item *mode_ti;
1303 struct rlc_lte_info *p_rlc_lte_info = NULL;
1306 static rlc_lte_tap_info tap_info;
1307 memset(&tap_info, 0, sizeof(rlc_lte_tap_info));
1309 /* Set protocol name */
1310 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
1312 /* Create protocol tree. */
1313 top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, FALSE);
1314 rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
1317 /* Look for packet info! */
1318 p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
1320 /* Can't dissect anything without it... */
1321 if (p_rlc_lte_info == NULL) {
1323 proto_tree_add_text(rlc_lte_tree, tvb, offset, -1,
1324 "Can't dissect LTE RLC frame because no per-frame info was attached!");
1325 PROTO_ITEM_SET_GENERATED(ti);
1329 /*****************************************/
1330 /* Show context information */
1332 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_direction,
1333 tvb, 0, 0, p_rlc_lte_info->direction);
1334 PROTO_ITEM_SET_GENERATED(ti);
1336 mode_ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_mode,
1337 tvb, 0, 0, p_rlc_lte_info->rlcMode);
1338 PROTO_ITEM_SET_GENERATED(mode_ti);
1340 if (p_rlc_lte_info->ueid != 0) {
1341 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_ueid,
1342 tvb, 0, 0, p_rlc_lte_info->ueid);
1343 PROTO_ITEM_SET_GENERATED(ti);
1346 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_priority,
1347 tvb, 0, 0, p_rlc_lte_info->priority);
1348 PROTO_ITEM_SET_GENERATED(ti);
1350 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_type,
1351 tvb, 0, 0, p_rlc_lte_info->channelType);
1352 PROTO_ITEM_SET_GENERATED(ti);
1354 if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
1355 (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB)) {
1356 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_id,
1357 tvb, 0, 0, p_rlc_lte_info->channelId);
1358 PROTO_ITEM_SET_GENERATED(ti);
1361 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_pdu_length,
1362 tvb, 0, 0, p_rlc_lte_info->pduLength);
1363 PROTO_ITEM_SET_GENERATED(ti);
1365 if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
1366 ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_um_sn_length,
1367 tvb, 0, 0, p_rlc_lte_info->UMSequenceNumberLength);
1368 PROTO_ITEM_SET_GENERATED(ti);
1371 /* Append highlights to top-level item */
1372 if (p_rlc_lte_info->ueid != 0) {
1373 proto_item_append_text(top_ti, " UEId=%u", p_rlc_lte_info->ueid);
1376 if (p_rlc_lte_info->channelId == 0) {
1377 proto_item_append_text(top_ti, " (%s) ",
1378 val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
1381 proto_item_append_text(top_ti, " (%s:%u) ",
1382 val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1383 p_rlc_lte_info->channelId);
1385 proto_item_append_text(top_ti, "[%s] ",
1386 val_to_str(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
1389 /* Append context highlights to info column */
1390 col_add_fstr(pinfo->cinfo, COL_INFO,
1392 (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
1393 val_to_str(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
1394 if (p_rlc_lte_info->ueid != 0) {
1395 col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%u ", p_rlc_lte_info->ueid);
1397 if (p_rlc_lte_info->channelId == 0) {
1398 col_append_fstr(pinfo->cinfo, COL_INFO, "%s",
1399 val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
1402 col_append_fstr(pinfo->cinfo, COL_INFO, "%s:%u",
1403 val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1404 p_rlc_lte_info->channelId);
1407 /* Set context-info parts of tap struct */
1408 tap_info.rlcMode = p_rlc_lte_info->rlcMode;
1409 tap_info.direction = p_rlc_lte_info->direction;
1410 tap_info.priority = p_rlc_lte_info->priority;
1411 tap_info.ueid = p_rlc_lte_info->ueid;
1412 tap_info.channelType = p_rlc_lte_info->channelType;
1413 tap_info.channelId = p_rlc_lte_info->channelId;
1414 tap_info.pduLength = p_rlc_lte_info->pduLength;
1415 tap_info.UMSequenceNumberLength = p_rlc_lte_info->UMSequenceNumberLength;
1417 /* Reset this count */
1418 s_number_of_extensions = 0;
1420 /* Dissect the RLC PDU itself. Format depends upon mode... */
1421 switch (p_rlc_lte_info->rlcMode) {
1424 dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
1428 dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
1433 dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
1438 /* Predefined data (i.e. not containing a valid RLC header */
1439 proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, FALSE);
1440 col_append_fstr(pinfo->cinfo, COL_INFO, " [%u-bytes]",
1441 tvb_length_remaining(tvb, offset));
1445 /* Error - unrecognised mode */
1446 expert_add_info_format(pinfo, mode_ti, PI_MALFORMED, PI_ERROR,
1447 "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
1451 /* Queue tap info */
1452 if (!pinfo->in_error_pkt) {
1453 tap_queue_packet(rlc_lte_tap, pinfo, &tap_info);
1459 /* Initializes the hash table and the mem_chunk area each time a new
1460 * file is loaded or re-loaded in wireshark */
1462 rlc_lte_init_protocol(void)
1464 /* Destroy any existing hashes. */
1465 if (rlc_lte_channel_hash) {
1466 g_hash_table_destroy(rlc_lte_channel_hash);
1469 if (rlc_lte_frame_report_hash) {
1470 g_hash_table_destroy(rlc_lte_frame_report_hash);
1473 /* Now create them over */
1474 rlc_lte_channel_hash = g_hash_table_new(rlc_channel_hash_func, rlc_channel_equal);
1475 rlc_lte_frame_report_hash = g_hash_table_new(rlc_frame_hash_func, rlc_frame_equal);
1481 void proto_register_rlc_lte(void)
1483 static hf_register_info hf[] =
1485 /**********************************/
1486 /* Items for decoding context */
1487 { &hf_rlc_lte_context_mode,
1489 "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
1493 { &hf_rlc_lte_context_direction,
1495 "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1496 "Direction of message", HFILL
1499 { &hf_rlc_lte_context_priority,
1501 "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
1505 { &hf_rlc_lte_context_ueid,
1507 "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
1508 "User Equipment Identifier associated with message", HFILL
1511 { &hf_rlc_lte_context_channel_type,
1513 "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
1514 "Channel Type associated with message", HFILL
1517 { &hf_rlc_lte_context_channel_id,
1519 "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
1520 "Channel ID associated with message", HFILL
1523 { &hf_rlc_lte_context_pdu_length,
1525 "rlc-lte.pdu_length", FT_UINT16, BASE_DEC, 0, 0x0,
1526 "Length of PDU (in bytes)", HFILL
1529 { &hf_rlc_lte_context_um_sn_length,
1530 { "UM Sequence number length",
1531 "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
1532 "Length of UM sequence number in bits", HFILL
1537 /* Transparent mode fields */
1538 { &hf_rlc_lte_tm_data,
1540 "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
1541 "Transparent Mode Data", HFILL
1545 /* Unacknowledged mode fields */
1546 { &hf_rlc_lte_um_header,
1548 "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
1549 "Unackowledged Mode Header", HFILL
1552 { &hf_rlc_lte_um_fi,
1554 "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
1558 { &hf_rlc_lte_um_fixed_e,
1560 "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
1561 "Extension in fixed part of UM header", HFILL
1564 { &hf_rlc_lte_um_sn,
1565 { "Sequence number",
1566 "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
1567 "Unacknowledged Mode Sequence Number", HFILL
1570 { &hf_rlc_lte_um_fixed_reserved,
1572 "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
1573 "Unacknowledged Mode Fixed header reserved bits", HFILL
1576 { &hf_rlc_lte_um_data,
1578 "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
1579 "Unacknowledged Mode Data", HFILL
1582 { &hf_rlc_lte_extension_part,
1584 "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
1590 { &hf_rlc_lte_extension_e,
1592 "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
1593 "Extension in extended part of the header", HFILL
1596 { &hf_rlc_lte_extension_li,
1597 { "Length Indicator",
1598 "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
1602 { &hf_rlc_lte_extension_padding,
1604 "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
1605 "Extension header padding", HFILL
1610 { &hf_rlc_lte_am_header,
1612 "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
1613 "Ackowledged Mode Header", HFILL
1616 { &hf_rlc_lte_am_data_control,
1618 "rlc-lte.am.frame_type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80,
1619 "AM Frame Type (Control or Data)", HFILL
1622 { &hf_rlc_lte_am_rf,
1623 { "Re-segmentation Flag",
1624 "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
1625 "AM Re-segmentation Flag", HFILL
1630 "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
1634 { &hf_rlc_lte_am_fi,
1636 "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
1637 "AM Framing Info", HFILL
1640 { &hf_rlc_lte_am_fixed_e,
1642 "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
1643 "Fixed Extension Bit", HFILL
1646 { &hf_rlc_lte_am_fixed_sn,
1647 { "Sequence Number",
1648 "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
1649 "AM Fixed Sequence Number", HFILL
1652 { &hf_rlc_lte_am_segment_lsf,
1653 { "Last Segment Flag",
1654 "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
1658 { &hf_rlc_lte_am_segment_so,
1660 "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
1664 { &hf_rlc_lte_am_data,
1666 "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
1667 "Acknowledged Mode Data", HFILL
1672 { &hf_rlc_lte_am_cpt,
1673 { "Control PDU Type",
1674 "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
1675 "AM Control PDU Type", HFILL
1678 { &hf_rlc_lte_am_ack_sn,
1679 { "ACK Sequence Number",
1680 "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
1681 "Sequence Number we're next expecting to receive", HFILL
1684 { &hf_rlc_lte_am_e1,
1685 { "Extension bit 1",
1686 "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
1690 { &hf_rlc_lte_am_e2,
1691 { "Extension bit 2",
1692 "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
1696 { &hf_rlc_lte_am_nack_sn,
1697 { "NACK Sequence Number",
1698 "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
1699 "Negative Acknowledgement Sequence Number", HFILL
1702 { &hf_rlc_lte_am_so_start,
1704 "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
1708 { &hf_rlc_lte_am_so_end,
1710 "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
1715 { &hf_rlc_lte_predefined_pdu,
1716 { "Predefined data",
1717 "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
1718 "Predefined test data", HFILL
1722 { &hf_rlc_lte_sequence_analysis,
1723 { "Sequence Analysis",
1724 "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
1728 { &hf_rlc_lte_sequence_analysis_previous_frame,
1729 { "Previous frame for channel",
1730 "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1734 { &hf_rlc_lte_sequence_analysis_expected_sn,
1736 "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
1740 { &hf_rlc_lte_sequence_analysis_framing_info_correct,
1741 { "Frame info continued correctly",
1742 "rlc-lte.sequence-analysis.framing-info-correct", FT_UINT8, BASE_DEC, 0, 0x0,
1748 static gint *ett[] =
1751 &ett_rlc_lte_um_header,
1752 &ett_rlc_lte_am_header,
1753 &ett_rlc_lte_extension_part,
1754 &ett_rlc_lte_sequence_analysis
1757 module_t *rlc_lte_module;
1759 /* Register protocol. */
1760 proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
1761 proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
1762 proto_register_subtree_array(ett, array_length(ett));
1764 /* Allow other dissectors to find this one by name. */
1765 register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
1767 /* Register the tap name */
1768 rlc_lte_tap = register_tap("rlc-lte");
1771 rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
1773 prefs_register_bool_preference(rlc_lte_module, "do_sequence_analysis",
1774 "Do sequence analysis for UM channels",
1775 "Attempt to keep track of PDUs for UM channels, and point out problems",
1776 &global_rlc_lte_sequence_analysis);
1778 prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
1779 "Call PDCP dissector for SRB PDUs",
1780 "Call PDCP dissector for signalling PDUs. Note that without reassembly, it can"
1781 "only be called for complete PDus (i.e. not segmented over RLC)",
1782 &global_rlc_lte_call_pdcp);
1784 prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
1785 "Call RRC dissector for CCCH PDUs",
1786 "Call RRC dissector for CCCH PDUs",
1787 &global_rlc_lte_call_rrc);
1789 prefs_register_bool_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp",
1790 "Try Heuristic LTE-RLC over UDP framing",
1791 "When enabled, use heuristic dissector to find RLC-LTE frames sent with "
1793 &global_rlc_lte_heur);
1795 register_init_routine(&rlc_lte_init_protocol);
1799 proto_reg_handoff_rlc_lte(void)
1801 static dissector_handle_t rlc_lte_handle;
1802 if (!rlc_lte_handle) {
1803 rlc_lte_handle = find_dissector("rlc-lte");
1805 /* Add as a heuristic UDP dissector */
1806 heur_dissector_add("udp", dissect_rlc_lte_heur, proto_rlc_lte);