1 /* Routines for UMTS RLC (Radio Link Control) v9.3.0 disassembly
2 * http://www.3gpp.org/ftp/Specs/archive/25_series/25.322/
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/wmem/wmem.h>
32 #include <epan/conversation.h>
33 #include <epan/asn1.h>
34 #include <epan/expert.h>
35 #include <epan/prefs.h>
38 * Optional include, for KASUMI support,
39 * see header file for more information.
41 #include <epan/crypt/kasumi.h>
43 #include "packet-umts_fp.h"
44 #include "packet-umts_mac.h"
45 #include "packet-rlc.h"
46 #include "packet-rrc.h"
49 * - distinguish between startpoints and endpoints?
50 * - use sub_num in fragment identification?
53 #define DEBUG_FRAME(number, msg) {if (pinfo->fd->num == number) printf("%u: %s\n", number, msg);}
55 #define ROL16(a,b) (guint16)((a<<b)|(a>>(16-b)))
61 /* Preference to perform reassembly */
62 static gboolean global_rlc_perform_reassemby
= TRUE
;
64 /* Preference to expect RLC headers without payloads */
65 static gboolean global_rlc_headers_expected
= FALSE
;
68 /* Heuristic dissection */
69 static gboolean global_rlc_heur
= FALSE
;
71 /* Preference to expect ciphered data */
72 static gboolean global_rlc_ciphered
= FALSE
;
74 /* Preference to try deciphering */
75 static gboolean global_rlc_try_decipher
= FALSE
;
77 #ifdef HAVE_UMTS_KASUMI
78 static const char *global_rlc_kasumi_key
= NULL
;
81 /* LI size preference */
82 #define RLC_LI_UPPERLAYER 255 /* LI-size comes from rlc_info struct rather than preference */
83 static gint global_rlc_li_size
= RLC_LI_UPPERLAYER
;
85 static const enum_val_t li_size_enumvals
[] = {
86 {"7 bits", "7 bits", RLC_LI_7BITS
},
87 {"15 bits", "15 bits", RLC_LI_15BITS
},
88 {"Let upper layers decide", "Let upper layers decide", RLC_LI_UPPERLAYER
},
92 static int hf_rlc_seq
= -1;
93 static int hf_rlc_ext
= -1;
94 static int hf_rlc_pad
= -1;
95 static int hf_rlc_frags
= -1;
96 static int hf_rlc_frag
= -1;
97 static int hf_rlc_duplicate_of
= -1;
98 static int hf_rlc_reassembled_in
= -1;
99 static int hf_rlc_he
= -1;
100 static int hf_rlc_dc
= -1;
101 static int hf_rlc_p
= -1;
102 static int hf_rlc_li
= -1;
103 static int hf_rlc_li_value
= -1;
104 static int hf_rlc_li_ext
= -1;
105 static int hf_rlc_li_data
= -1;
106 static int hf_rlc_data
= -1;
107 static int hf_rlc_ctrl_type
= -1;
108 static int hf_rlc_r1
= -1;
109 static int hf_rlc_rsn
= -1;
110 static int hf_rlc_hfni
= -1;
111 static int hf_rlc_sufi
= -1;
112 static int hf_rlc_sufi_type
= -1;
113 static int hf_rlc_sufi_lsn
= -1;
114 static int hf_rlc_sufi_wsn
= -1;
115 static int hf_rlc_sufi_sn
= -1;
116 static int hf_rlc_sufi_l
= -1;
117 static int hf_rlc_sufi_fsn
= -1;
118 static int hf_rlc_sufi_len
= -1;
119 static int hf_rlc_sufi_bitmap
= -1;
120 static int hf_rlc_sufi_cw
= -1;
121 static int hf_rlc_sufi_n
= -1;
122 static int hf_rlc_sufi_sn_ack
= -1;
123 static int hf_rlc_sufi_sn_mrw
= -1;
124 static int hf_rlc_sufi_poll_sn
= -1;
125 static int hf_rlc_header_only
= -1;
126 static int hf_rlc_channel
= -1;
127 static int hf_rlc_channel_rbid
= -1;
128 static int hf_rlc_channel_dir
= -1;
129 static int hf_rlc_channel_ueid
= -1;
132 static int ett_rlc
= -1;
133 static int ett_rlc_frag
= -1;
134 static int ett_rlc_fragments
= -1;
135 static int ett_rlc_sdu
= -1;
136 static int ett_rlc_sufi
= -1;
137 static int ett_rlc_bitmap
= -1;
138 static int ett_rlc_rlist
= -1;
139 static int ett_rlc_channel
= -1;
141 static expert_field ei_rlc_li_reserved
= EI_INIT
;
142 static expert_field ei_rlc_he
= EI_INIT
;
143 static expert_field ei_rlc_li_incorrect_mal
= EI_INIT
;
144 static expert_field ei_rlc_sufi_cw
= EI_INIT
;
145 static expert_field ei_rlc_kasumi_implementation_missing
= EI_INIT
;
146 static expert_field ei_rlc_reassembly_unknown_error
= EI_INIT
;
147 static expert_field ei_rlc_reassembly_lingering_endpoint
= EI_INIT
;
148 static expert_field ei_rlc_sufi_len
= EI_INIT
;
149 static expert_field ei_rlc_reassembly_fail_unfinished_sequence
= EI_INIT
;
150 static expert_field ei_rlc_reassembly_fail_flag_set
= EI_INIT
;
151 static expert_field ei_rlc_sufi_type
= EI_INIT
;
152 static expert_field ei_rlc_reserved_bits_not_zero
= EI_INIT
;
153 static expert_field ei_rlc_ctrl_type
= EI_INIT
;
154 static expert_field ei_rlc_li_incorrect_warn
= EI_INIT
;
155 static expert_field ei_rlc_li_too_many
= EI_INIT
;
156 static expert_field ei_rlc_header_only
= EI_INIT
;
158 static dissector_handle_t ip_handle
;
159 static dissector_handle_t rrc_handle
;
160 static dissector_handle_t bmc_handle
;
162 enum rlc_channel_type
{
174 static const value_string rlc_dir_vals
[] = {
175 { P2P_DIR_UL
, "Uplink" },
176 { P2P_DIR_DL
, "Downlink" },
180 static const true_false_string rlc_header_only_val
= {
181 "RLC PDU header only", "RLC PDU header and body present"
184 static const true_false_string rlc_ext_val
= {
185 "Next field is Length Indicator and E Bit", "Next field is data, piggybacked STATUS PDU or padding"
188 static const true_false_string rlc_dc_val
= {
192 static const true_false_string rlc_p_val
= {
193 "Request a status report", "Status report not requested"
196 static const value_string rlc_he_vals
[] = {
197 { 0, "The succeeding octet contains data" },
198 { 1, "The succeeding octet contains a length indicator and E bit" },
199 { 2, "The succeeding octet contains data and the last octet of the PDU is the last octet of an SDU" },
203 #define RLC_STATUS 0x0
204 #define RLC_RESET 0x1
205 #define RLC_RESET_ACK 0x2
206 static const value_string rlc_ctrl_vals
[] = {
207 { RLC_STATUS
, "Status" },
208 { RLC_RESET
, "Reset" },
209 { RLC_RESET_ACK
, "Reset Ack" },
213 #define RLC_SUFI_NOMORE 0x0
214 #define RLC_SUFI_WINDOW 0x1
215 #define RLC_SUFI_ACK 0x2
216 #define RLC_SUFI_LIST 0x3
217 #define RLC_SUFI_BITMAP 0x4
218 #define RLC_SUFI_RLIST 0x5
219 #define RLC_SUFI_MRW 0x6
220 #define RLC_SUFI_MRW_ACK 0x7
221 #define RLC_SUFI_POLL 0x8
222 static const value_string rlc_sufi_vals
[] = {
223 { RLC_SUFI_NOMORE
, "No more data" },
224 { RLC_SUFI_WINDOW
, "Window size" },
225 { RLC_SUFI_ACK
, "Acknowledgement" },
226 { RLC_SUFI_LIST
, "List" },
227 { RLC_SUFI_BITMAP
, "Bitmap" },
228 { RLC_SUFI_RLIST
, "Relative list" },
229 { RLC_SUFI_MRW
, "Move receiving window" },
230 { RLC_SUFI_MRW_ACK
, "Move receiving window acknowledgement" },
231 { RLC_SUFI_POLL
, "Poll" },
235 /* reassembly related data */
236 static GHashTable
*fragment_table
= NULL
; /* table of not yet assembled fragments */
237 static GHashTable
*endpoints
= NULL
; /* List of SDU-endpoints */
238 static GHashTable
*reassembled_table
= NULL
; /* maps fragment -> complete sdu */
239 static GHashTable
*sequence_table
= NULL
; /* channel -> seq */
240 static GHashTable
*duplicate_table
= NULL
; /* duplicates */
242 /* identify an RLC channel, using one of two options:
243 * - via Radio Bearer ID and U-RNTI
244 * - via Radio Bearer ID and (VPI/VCI/CID) + Link ID
251 guint16 link
; /* link number */
252 guint8 rbid
; /* radio bearer ID */
253 guint8 dir
; /* direction */
254 enum rlc_li_size li_size
;
258 /* used for duplicate detection */
263 guint16 oc
; /* overflow counter, this is not used? */
267 struct rlc_channel ch
;
269 /* We will store one seqlist per channel so this is a good place to indicate
270 * whether or not this channel's reassembly has failed or not. */
271 guint fail_packet
; /* Equal to packet where fail flag was set or 0 otherwise. */
274 /* fragment representation */
277 struct rlc_channel ch
;
278 guint16 seq
; /* RLC sequence number */
279 guint16 li
; /* LI within current RLC frame */
280 guint16 len
; /* length of fragment data */
281 guint8
*data
; /* store fragment data here */
283 struct rlc_frag
*next
; /* next fragment */
287 tvbuff_t
*tvb
; /* contains reassembled tvb */
288 guint16 len
; /* total length of reassembled SDU */
289 guint16 fragcnt
; /* number of fragments within this SDU */
290 guint8
*data
; /* reassembled data buffer */
292 struct rlc_frag
*reassembled_in
;
293 struct rlc_frag
*frags
; /* pointer to list of fragments */
294 struct rlc_frag
*last
; /* pointer to last fragment */
298 guint16 li
; /* original li */
299 guint16 len
; /* length of this data fragment */
300 guint8 ext
; /* extension bit value */
301 proto_tree
*tree
; /* subtree for this LI */
304 /*** KASUMI related variables and structs ***/
305 typedef struct umts_kat_key
{ /*Stores 128-bits KASUMI key*/
306 guint64 high
; /*64 MSB*/
307 guint64 low
; /*64 LSB*/
311 /*Counter used as input for confidentiality algorithm*/
312 static guint32 ps_counter
[31][2] ;
313 static gboolean counter_init
[31][2];
314 static guint32 max_counter
= 0;
315 static GTree
* counter_map
; /*Saves the countervalues at first pass through, since they will be update*/
317 /* hashtable functions for fragment table
321 rlc_channel_hash(gconstpointer key
)
323 const struct rlc_channel
*ch
= (const struct rlc_channel
*)key
;
326 return ch
->urnti
| ch
->rbid
| ch
->mode
;
328 return (ch
->vci
<< 16) | (ch
->link
<< 16) | ch
->vpi
| ch
->vci
;
332 rlc_channel_equal(gconstpointer a
, gconstpointer b
)
334 const struct rlc_channel
*x
= (const struct rlc_channel
*)a
, *y
= (const struct rlc_channel
*)b
;
336 if (x
->urnti
|| y
->urnti
)
337 return x
->urnti
== y
->urnti
&&
338 x
->rbid
== y
->rbid
&&
339 x
->mode
== y
->mode
&&
340 x
->dir
== y
->dir
? TRUE
: FALSE
;
342 return x
->vpi
== y
->vpi
&&
345 x
->rbid
== y
->rbid
&&
346 x
->mode
== y
->mode
&&
348 x
->link
== y
->link
? TRUE
: FALSE
;
352 rlc_channel_assign(struct rlc_channel
*ch
, enum rlc_mode mode
, packet_info
*pinfo
)
354 struct atm_phdr
*atm
;
358 atm
= &pinfo
->pseudo_header
->atm
;
359 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
360 rlcinf
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
361 if (!fpinf
|| !rlcinf
) return -1;
363 if (rlcinf
->urnti
[fpinf
->cur_tb
]) {
364 ch
->urnti
= rlcinf
->urnti
[fpinf
->cur_tb
];
365 ch
->vpi
= ch
->vci
= ch
->link
= ch
->cid
= 0;
371 ch
->cid
= atm
->aal2_cid
;
372 ch
->link
= pinfo
->link_number
;
374 ch
->rbid
= rlcinf
->rbid
[fpinf
->cur_tb
];
375 ch
->dir
= pinfo
->p2p_dir
;
377 ch
->li_size
= rlcinf
->li_size
[fpinf
->cur_tb
];
382 static struct rlc_channel
*
383 rlc_channel_create(enum rlc_mode mode
, packet_info
*pinfo
)
385 struct rlc_channel
*ch
;
388 ch
= (struct rlc_channel
*)g_malloc0(sizeof(struct rlc_channel
));
389 rv
= rlc_channel_assign(ch
, mode
, pinfo
);
392 /* channel assignment failed */
395 REPORT_DISSECTOR_BUG("Failed to assign channel");
401 rlc_channel_delete(gpointer data
)
406 /* hashtable functions for reassembled table
410 rlc_frag_hash(gconstpointer key
)
412 const struct rlc_frag
*frag
= (const struct rlc_frag
*)key
;
413 return (frag
->frame_num
<< 12) | frag
->seq
;
417 rlc_frag_equal(gconstpointer a
, gconstpointer b
)
419 const struct rlc_frag
*x
= (const struct rlc_frag
*)a
;
420 const struct rlc_frag
*y
= (const struct rlc_frag
*)b
;
422 return rlc_channel_equal(&x
->ch
, &y
->ch
) &&
424 x
->frame_num
== y
->frame_num
&&
425 x
->li
== y
->li
? TRUE
: FALSE
;
428 static struct rlc_sdu
*
433 sdu
= (struct rlc_sdu
*)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_sdu
));
438 rlc_frag_delete(gpointer data
)
440 struct rlc_frag
*frag
= (struct rlc_frag
*)data
;
449 rlc_sdu_frags_delete(gpointer data
)
451 struct rlc_sdu
*sdu
= (struct rlc_sdu
*)data
;
452 struct rlc_frag
*frag
;
465 rlc_frag_assign(struct rlc_frag
*frag
, enum rlc_mode mode
, packet_info
*pinfo
,
466 guint16 seq
, guint16 li
)
468 frag
->frame_num
= pinfo
->fd
->num
;
473 rlc_channel_assign(&frag
->ch
, mode
, pinfo
);
479 rlc_frag_assign_data(struct rlc_frag
*frag
, tvbuff_t
*tvb
,
480 guint16 offset
, guint16 length
)
483 frag
->data
= (guint8
*)g_malloc(length
);
484 tvb_memcpy(tvb
, frag
->data
, offset
, length
);
488 static struct rlc_frag
*
489 rlc_frag_create(tvbuff_t
*tvb
, enum rlc_mode mode
, packet_info
*pinfo
,
490 guint16 offset
, guint16 length
, guint16 seq
, guint16 li
)
492 struct rlc_frag
*frag
;
494 frag
= (struct rlc_frag
*)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_frag
));
495 rlc_frag_assign(frag
, mode
, pinfo
, seq
, li
);
496 rlc_frag_assign_data(frag
, tvb
, offset
, length
);
502 rlc_cmp_seq(gconstpointer a
, gconstpointer b
)
504 const struct rlc_seq
*_a
= (const struct rlc_seq
*)a
, *_b
= (const struct rlc_seq
*)b
;
506 return _a
->seq
< _b
->seq
? -1 :
507 _a
->seq
> _b
->seq
? 1 :
512 special_cmp(gconstpointer a
, gconstpointer b
)
514 const gint16 p
= GPOINTER_TO_INT(a
), q
= GPOINTER_TO_INT(b
);
515 if (ABS(p
-q
) < 2048) {
516 return (p
< q
)? -1 : (p
> q
)? 1 : 0;
526 /* "Value destroy" function called each time an entry is removed
527 * from the sequence_table hash.
528 * It frees the GList pointed to by the entry.
531 free_sequence_table_entry_data(gpointer data
)
533 struct rlc_seqlist
*list
= (struct rlc_seqlist
*)data
;
534 if (list
->list
!= NULL
) {
535 g_list_free(list
->list
);
536 list
->list
= NULL
; /* for good measure */
540 /** Utility functions used for various comparions/cleanups in tree **/
542 rlc_simple_key_cmp(gconstpointer b_ptr
, gconstpointer a_ptr
, gpointer ignore _U_
){
543 if( GPOINTER_TO_INT(a_ptr
) > GPOINTER_TO_INT(b_ptr
) ){
546 return GPOINTER_TO_INT(a_ptr
) < GPOINTER_TO_INT(b_ptr
);
550 fragment_table_init(void)
553 if (fragment_table
) {
554 g_hash_table_destroy(fragment_table
);
557 g_hash_table_destroy(endpoints
);
559 if (reassembled_table
) {
560 g_hash_table_destroy(reassembled_table
);
562 if (sequence_table
) {
563 g_hash_table_destroy(sequence_table
);
565 if (duplicate_table
) {
566 g_hash_table_destroy(duplicate_table
);
569 g_tree_destroy(counter_map
);
571 fragment_table
= g_hash_table_new_full(rlc_channel_hash
, rlc_channel_equal
, rlc_channel_delete
, NULL
);
572 endpoints
= g_hash_table_new_full(rlc_channel_hash
, rlc_channel_equal
, rlc_channel_delete
, NULL
);
573 reassembled_table
= g_hash_table_new_full(rlc_frag_hash
, rlc_frag_equal
,
574 rlc_frag_delete
, rlc_sdu_frags_delete
);
575 sequence_table
= g_hash_table_new_full(rlc_channel_hash
, rlc_channel_equal
,
576 NULL
, free_sequence_table_entry_data
);
577 duplicate_table
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, NULL
);
579 /*Reset and or clear deciphering variables*/
580 counter_map
= g_tree_new_full(rlc_simple_key_cmp
,NULL
,NULL
,rlc_channel_delete
);
581 for(i
= 0; i
< 31; i
++ ){
582 ps_counter
[i
][0] = 0;
583 ps_counter
[i
][1] = 0;
584 counter_init
[i
][0] = 0;
585 counter_init
[i
][1] = 0;
590 /* add the list of fragments for this sdu to 'tree' */
592 tree_add_fragment_list(struct rlc_sdu
*sdu
, tvbuff_t
*tvb
, proto_tree
*tree
)
595 proto_tree
*frag_tree
;
597 struct rlc_frag
*sdufrag
;
599 ti
= proto_tree_add_item(tree
, hf_rlc_frags
, tvb
, 0, -1, ENC_NA
);
600 frag_tree
= proto_item_add_subtree(ti
, ett_rlc_fragments
);
601 proto_item_append_text(ti
, " (%u bytes, %u fragments): ",
602 sdu
->len
, sdu
->fragcnt
);
603 sdufrag
= sdu
->frags
;
606 if (sdufrag
->len
> 0) {
607 proto_tree_add_uint_format(frag_tree
, hf_rlc_frag
, tvb
, offset
,
608 sdufrag
->len
, sdufrag
->frame_num
, "Frame: %u, payload: %u-%u (%u bytes) (Seq: %u)",
609 sdufrag
->frame_num
, offset
, offset
+ sdufrag
->len
- 1, sdufrag
->len
, sdufrag
->seq
);
611 proto_tree_add_uint_format(frag_tree
, hf_rlc_frag
, tvb
, offset
,
612 sdufrag
->len
, sdufrag
->frame_num
, "Frame: %u, payload: none (0 bytes) (Seq: %u)",
613 sdufrag
->frame_num
, sdufrag
->seq
);
615 offset
+= sdufrag
->len
;
616 sdufrag
= sdufrag
->next
;
620 /* add the list of fragments for this sdu to 'tree' */
622 tree_add_fragment_list_incomplete(struct rlc_sdu
*sdu
, tvbuff_t
*tvb
, proto_tree
*tree
)
625 proto_tree
*frag_tree
;
627 struct rlc_frag
*sdufrag
;
629 ti
= proto_tree_add_item(tree
, hf_rlc_frags
, tvb
, 0, 0, ENC_NA
);
630 frag_tree
= proto_item_add_subtree(ti
, ett_rlc_fragments
);
631 proto_item_append_text(ti
, " (%u bytes, %u fragments): ",
632 sdu
->len
, sdu
->fragcnt
);
633 sdufrag
= sdu
->frags
;
636 proto_tree_add_uint_format(frag_tree
, hf_rlc_frag
, tvb
, 0,
637 0, sdufrag
->frame_num
, "Frame: %u, payload %u-%u (%u bytes) (Seq: %u)",
638 sdufrag
->frame_num
, offset
, offset
+ sdufrag
->len
- 1, sdufrag
->len
, sdufrag
->seq
);
639 offset
+= sdufrag
->len
;
640 sdufrag
= sdufrag
->next
;
644 /* Add the same description to too the two given proto_items */
646 add_description(proto_item
*li_ti
, proto_item
*length_ti
,
647 const char *format
, ...)
649 #define MAX_INFO_BUFFER 256
650 static char info_buffer
[MAX_INFO_BUFFER
];
654 va_start(ap
, format
);
655 g_vsnprintf(info_buffer
, MAX_INFO_BUFFER
, format
, ap
);
658 proto_item_append_text(li_ti
, " (%s)", info_buffer
);
659 proto_item_append_text(length_ti
, " (%s)", info_buffer
);
662 /* add information for an LI to 'tree' */
664 tree_add_li(enum rlc_mode mode
, struct rlc_li
*li
, guint8 li_idx
, guint8 hdr_offs
,
665 gboolean li_is_on_2_bytes
, tvbuff_t
*tvb
, proto_tree
*tree
)
667 proto_item
*root_ti
, *ti
;
672 if (!tree
) return NULL
;
674 if (li_is_on_2_bytes
) {
675 li_offs
= hdr_offs
+ li_idx
*2;
676 root_ti
= proto_tree_add_item(tree
, hf_rlc_li
, tvb
, li_offs
, 2, ENC_NA
);
677 li_tree
= proto_item_add_subtree(root_ti
, ett_rlc_frag
);
678 ti
= proto_tree_add_bits_ret_val(li_tree
, hf_rlc_li_value
, tvb
, li_offs
*8, 15, &length
, ENC_BIG_ENDIAN
);
682 add_description(root_ti
, ti
, "The previous RLC PDU was exactly filled with the last segment of an RLC SDU and there is no LI that indicates the end of the RLC SDU in the previous RLC PDU");
685 if (mode
== RLC_UM
) {
686 add_description(root_ti
, ti
, "The first data octet in this RLC PDU is the first octet of an RLC SDU and the second last octet in this RLC PDU is the last octet of the same RLC SDU. The remaining octet in the RLC PDU is ignored");
688 add_description(root_ti
, ti
, "Reserved");
692 add_description(root_ti
, ti
, "The second last octet in the previous RLC PDU is the last octet of an RLC SDU and there is no LI to indicate the end of SDU. The remaining octet in the previous RLC PDU is ignored");
695 if (mode
== RLC_UM
) {
696 add_description(root_ti
, ti
, "The first data octet in this RLC PDU is the first octet of an RLC SDU");
698 add_description(root_ti
, ti
, "Reserved");
702 if (mode
== RLC_UM
) {
703 add_description(root_ti
, ti
, "The first data octet in this RLC PDU is the first octet of an RLC SDU and the last octet in this RLC PDU is the last octet of the same RLC SDU");
705 add_description(root_ti
, ti
, "Reserved");
709 if (mode
== RLC_UM
) {
710 add_description(root_ti
, ti
, "The RLC PDU contains a segment of an SDU but neither the first octet nor the last octet of this SDU");
712 add_description(root_ti
, ti
, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
716 add_description(root_ti
, ti
, "The rest of the RLC PDU is padding");
720 add_description(root_ti
, ti
, "length=%u", (guint16
)length
);
723 proto_tree_add_bits_item(li_tree
, hf_rlc_li_ext
, tvb
, li_offs
*8+15, 1, ENC_BIG_ENDIAN
);
725 li_offs
= hdr_offs
+ li_idx
;
726 root_ti
= proto_tree_add_item(tree
, hf_rlc_li
, tvb
, li_offs
, 1, ENC_NA
);
727 li_tree
= proto_item_add_subtree(root_ti
, ett_rlc_frag
);
728 ti
= proto_tree_add_bits_ret_val(li_tree
, hf_rlc_li_value
, tvb
, li_offs
*8, 7, &length
, ENC_BIG_ENDIAN
);
731 add_description(root_ti
, ti
, "The previous RLC PDU was exactly filled with the last segment of an RLC SDU and there is no LI that indicates the end of the RLC SDU in the previous RLC PDU");
734 if (mode
== RLC_UM
) {
735 add_description(root_ti
, ti
, "The first data octet in this RLC PDU is the first octet of an RLC SDU");
737 add_description(root_ti
, ti
, "Reserved");
741 if (mode
== RLC_UM
) {
742 add_description(root_ti
, ti
, "The first data octet in this RLC PDU is the first octet of an RLC SDU and the last octet in this RLC PDU is the last octet of the same RLC SDU");
744 add_description(root_ti
, ti
, "Reserved");
748 if (mode
== RLC_UM
) {
749 add_description(root_ti
, ti
, "The RLC PDU contains a segment of an SDU but neither the first octet nor the last octet of this SDU");
751 add_description(root_ti
, ti
, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
755 add_description(root_ti
, ti
, "The rest of the RLC PDU is padding");
759 add_description(root_ti
, ti
, "length=%u", (guint16
)length
);
762 proto_tree_add_bits_item(li_tree
, hf_rlc_li_ext
, tvb
, li_offs
*8+7, 1, ENC_BIG_ENDIAN
);
766 if (li
->li
> tvb_length_remaining(tvb
, hdr_offs
)) return li_tree
;
767 if (li
->len
> li
->li
) return li_tree
;
768 ti
= proto_tree_add_item(li_tree
, hf_rlc_li_data
, tvb
, hdr_offs
+ li
->li
- li
->len
, li
->len
, ENC_NA
);
769 PROTO_ITEM_SET_HIDDEN(ti
);
775 /* add a fragment to an SDU */
777 rlc_sdu_add_fragment(enum rlc_mode mode
, struct rlc_sdu
*sdu
, struct rlc_frag
*frag
)
779 struct rlc_frag
*tmp
;
782 /* insert as first element */
786 sdu
->len
+= frag
->len
;
791 /* insert as last element */
792 sdu
->last
->next
= frag
;
795 sdu
->len
+= frag
->len
;
801 /* If receiving exotic border line sequence, e.g. 4094, 4095, 0, 1 */
802 if (frag
->seq
+2048 < tmp
->seq
) {
803 while (tmp
->next
&& frag
->seq
+2048 < tmp
->seq
)
805 if (tmp
->next
== NULL
) {
809 while (tmp
->next
&& tmp
->next
->seq
< frag
->seq
)
811 frag
->next
= tmp
->next
;
813 if (frag
->next
== NULL
) sdu
->last
= frag
;
815 } else { /* Receiving ordinary sequence */
816 if (frag
->seq
< tmp
->seq
) {
817 /* insert as first element */
821 while (tmp
->next
&& tmp
->next
->seq
< frag
->seq
)
823 frag
->next
= tmp
->next
;
825 if (frag
->next
== NULL
) sdu
->last
= frag
;
828 sdu
->len
+= frag
->len
;
838 reassemble_data(struct rlc_channel
*ch
, struct rlc_sdu
*sdu
, struct rlc_frag
*frag
)
840 struct rlc_frag
*temp
;
843 if (!sdu
|| !ch
|| !sdu
->frags
) return;
845 if (sdu
->data
) return; /* already assembled */
848 sdu
->reassembled_in
= frag
;
850 sdu
->reassembled_in
= sdu
->last
;
852 sdu
->data
= (guint8
*)wmem_alloc(wmem_file_scope(), sdu
->len
);
854 while (temp
&& ((offs
+ temp
->len
) <= sdu
->len
)) {
855 memcpy(sdu
->data
+ offs
, temp
->data
, temp
->len
);
858 /* mark this fragment in reassembled table */
859 g_hash_table_insert(reassembled_table
, temp
, sdu
);
866 #define RLC_ADD_FRAGMENT_FAIL_PRINT 0
867 #define RLC_ADD_FRAGMENT_DEBUG_PRINT 0
868 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
870 printends(GList
* list
)
874 g_print("-> length: %d\n[", g_list_length(list
));
877 g_print("%d ", GPOINTER_TO_INT(list
->data
));
884 static struct rlc_frag
**
885 get_frags(packet_info
* pinfo
, struct rlc_channel
* ch_lookup
)
887 gpointer value
= NULL
;
888 struct rlc_frag
** frags
= NULL
;
889 /* Look for already created frags table */
890 if (g_hash_table_lookup_extended(fragment_table
, ch_lookup
, NULL
, &value
)) {
891 frags
= (struct rlc_frag
**)value
;
892 } else if (pinfo
!= NULL
) {
893 struct rlc_channel
*ch
;
894 ch
= rlc_channel_create(ch_lookup
->mode
, pinfo
);
895 frags
= (struct rlc_frag
**)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_frag
*) * 4096);
896 g_hash_table_insert(fragment_table
, ch
, frags
);
902 static struct rlc_seqlist
*
903 get_endlist(packet_info
* pinfo
, struct rlc_channel
* ch_lookup
)
905 gpointer value
= NULL
;
906 struct rlc_seqlist
* endlist
= NULL
;
907 /* If there already exists a frag table for this channel use that one. */
908 if (g_hash_table_lookup_extended(endpoints
, ch_lookup
, NULL
, &value
)) {
909 endlist
= (struct rlc_seqlist
*)value
;
910 } else if (pinfo
!= NULL
) { /* Else create a new one. */
911 struct rlc_channel
* ch
;
913 endlist
= wmem_new(wmem_file_scope(), struct rlc_seqlist
);
914 ch
= rlc_channel_create(ch_lookup
->mode
, pinfo
);
915 endlist
->fail_packet
= 0;
916 endlist
->list
= NULL
;
917 endlist
->list
= g_list_prepend(endlist
->list
, GINT_TO_POINTER(-1));
918 g_hash_table_insert(endpoints
, ch
, endlist
);
926 reassemble_sequence(struct rlc_frag
** frags
, struct rlc_seqlist
* endlist
,
927 struct rlc_channel
* ch_lookup
, guint16 start
, guint16 end
)
929 GList
* element
= NULL
;
930 struct rlc_sdu
* sdu
= rlc_sdu_create();
932 /* Insert fragments into SDU. */
933 for (; special_cmp(GINT_TO_POINTER((gint
)start
), GINT_TO_POINTER((gint
)end
)) <= 0; start
= (start
+1)%4096)
935 struct rlc_frag
* tempfrag
= NULL
;
936 tempfrag
= frags
[start
]->next
;
937 frags
[start
]->next
= NULL
;
938 rlc_sdu_add_fragment(ch_lookup
->mode
, sdu
, frags
[start
]);
939 frags
[start
] = tempfrag
;
942 /* Remove first endpoint. */
943 element
= g_list_first(endlist
->list
);
945 endlist
->list
= g_list_remove_link(endlist
->list
, element
);
946 if (frags
[end
] != NULL
) {
948 endlist
->list
->data
= GINT_TO_POINTER((GPOINTER_TO_INT(endlist
->list
->data
) - 1 + 4096) % 4096);
952 reassemble_data(ch_lookup
, sdu
, NULL
);
955 /* Reset the specified channel's reassembly data, useful for when a sequence
956 * resets on transport channel swap. */
958 rlc_reset_channel(enum rlc_mode mode
, guint8 rbid
, guint8 dir
, guint32 urnti
)
960 struct rlc_frag
** frags
= NULL
;
961 struct rlc_seqlist
* endlist
= NULL
;
962 struct rlc_channel ch_lookup
;
965 ch_lookup
.mode
= mode
;
966 ch_lookup
.rbid
= rbid
;
968 ch_lookup
.urnti
= urnti
;
969 frags
= get_frags(NULL
, &ch_lookup
);
970 endlist
= get_endlist(NULL
, &ch_lookup
);
971 DISSECTOR_ASSERT(frags
&& endlist
);
973 endlist
->fail_packet
= 0;
974 g_list_free(endlist
->list
);
975 endlist
->list
= NULL
;
977 for (i
= 0; i
< 4096; i
++) {
982 /* add a new fragment to an SDU
983 * if length == 0, just finalize the specified SDU
985 static struct rlc_frag
*
986 add_fragment(enum rlc_mode mode
, tvbuff_t
*tvb
, packet_info
*pinfo
,
987 proto_tree
*tree
, guint16 offset
, guint16 seq
, guint16 num_li
,
988 guint16 len
, gboolean final
)
990 struct rlc_channel ch_lookup
;
991 struct rlc_frag frag_lookup
, *frag
= NULL
;
992 gpointer orig_key
= NULL
, value
= NULL
;
993 struct rlc_sdu
*sdu
= NULL
;
994 struct rlc_frag
** frags
= NULL
;
995 struct rlc_seqlist
* endlist
= NULL
;
996 GList
* element
= NULL
;
998 if (rlc_channel_assign(&ch_lookup
, mode
, pinfo
) == -1) {
1001 rlc_frag_assign(&frag_lookup
, mode
, pinfo
, seq
, num_li
);
1002 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1003 g_print("packet: %d, channel (%d %d %d) seq: %u, num_li: %u, offset: %u, \n", pinfo
->fd
->num
, ch_lookup
.dir
, ch_lookup
.rbid
, ch_lookup
.urnti
, seq
, num_li
, offset
);
1005 /* look for an already assembled SDU */
1006 if (g_hash_table_lookup_extended(reassembled_table
, &frag_lookup
, &orig_key
, &value
)) {
1007 /* this fragment is already reassembled somewhere */
1008 frag
= (struct rlc_frag
*)orig_key
;
1009 sdu
= (struct rlc_sdu
*)value
;
1011 /* mark the fragment, if reassembly happened somewhere else */
1012 if (frag
->seq
!= sdu
->reassembled_in
->seq
||
1013 frag
->li
!= sdu
->reassembled_in
->li
)
1014 proto_tree_add_uint(tree
, hf_rlc_reassembled_in
, tvb
, 0, 0,
1015 sdu
->reassembled_in
->frame_num
);
1020 frags
= get_frags(pinfo
, &ch_lookup
);
1021 endlist
= get_endlist(pinfo
, &ch_lookup
);
1023 /* If already done reassembly */
1024 if (pinfo
->fd
->flags
.visited
) {
1025 if (tree
&& len
> 0) {
1026 if (endlist
->list
&& endlist
->list
->next
) {
1027 gint16 start
= (GPOINTER_TO_INT(endlist
->list
->data
) + 1) % 4096;
1028 gint16 end
= GPOINTER_TO_INT(endlist
->list
->next
->data
);
1029 gint16 missing
= start
;
1030 gboolean wecanreasmmore
= TRUE
;
1032 for (; special_cmp(GINT_TO_POINTER((gint
)missing
), GINT_TO_POINTER((gint
)end
)) <= 0; missing
= (missing
+1)%4096)
1034 if (frags
[missing
] == NULL
) {
1035 wecanreasmmore
= FALSE
;
1040 if (wecanreasmmore
) {
1041 reassemble_sequence(frags
, endlist
, &ch_lookup
, start
, end
);
1043 if (end
>= 0 && end
< 4096 && frags
[end
]) {
1044 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_reassembly_fail_unfinished_sequence
, tvb
, 0, 0,
1045 "Did not perform reassembly because of unfinished sequence (%d->%d [packet %u]), could not find %d.", start
, end
, frags
[end
]->frame_num
, missing
);
1047 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_reassembly_fail_unfinished_sequence
, tvb
, 0, 0,
1048 "Did not perform reassembly because of unfinished sequence (%d->%d [could not determine packet]), could not find %d.", start
, end
, missing
);
1051 } else if (endlist
->list
) {
1052 if (endlist
->fail_packet
!= 0 && endlist
->fail_packet
<= pinfo
->fd
->num
) {
1053 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_reassembly_fail_flag_set
, tvb
, 0, 0, "Did not perform reassembly because fail flag was set in packet %u.", endlist
->fail_packet
);
1055 gint16 end
= GPOINTER_TO_INT(endlist
->list
->data
);
1056 if (end
>= 0 && end
< 4096 && frags
[end
]) {
1057 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_reassembly_lingering_endpoint
, tvb
, 0, 0, "Did not perform reassembly because of unfinished sequence, found lingering endpoint (%d [packet %d]).", end
, frags
[end
]->frame_num
);
1059 proto_tree_add_expert_format(tree
, pinfo
, &ei_rlc_reassembly_lingering_endpoint
, tvb
, 0, 0, "Did not perform reassembly because of unfinished sequence, found lingering endpoint (%d [could not determine packet]).", end
);
1063 expert_add_info(pinfo
, NULL
, &ei_rlc_reassembly_unknown_error
);
1066 return NULL
; /* If already done reassembly and no SDU found, too bad */
1069 if (endlist
->fail_packet
!= 0) { /* don't continue after sh*t has hit the fan */
1073 frag
= rlc_frag_create(tvb
, mode
, pinfo
, offset
, len
, seq
, num_li
);
1075 /* If frags[seq] is not NULL then we must have data from several PDUs in the
1076 * same RLC packet (using Length Indicators) or something has gone terribly
1078 if (frags
[seq
] != NULL
) {
1080 struct rlc_frag
* tempfrag
= frags
[seq
];
1081 while (tempfrag
->next
!= NULL
)
1082 tempfrag
= tempfrag
->next
;
1083 tempfrag
->next
= frag
;
1084 } else { /* This should never happen */
1085 endlist
->fail_packet
= pinfo
->fd
->num
;
1092 /* It is also possible that frags[seq] is NULL even though we do have data
1093 * from several PDUs in the same RLC packet. This is if the reassembly is
1094 * not lagging behind at all because of perfectly ordered sequences. */
1095 if (endlist
->list
&& num_li
!= 0) {
1096 gint16 first
= GPOINTER_TO_INT(endlist
->list
->data
);
1098 endlist
->list
->data
= GINT_TO_POINTER(first
-1);
1102 /* If this is an endpoint */
1104 endlist
->list
= g_list_insert_sorted(endlist
->list
, GINT_TO_POINTER((gint
)seq
), special_cmp
);
1107 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1108 printends(endlist
->list
);
1111 /* Try to reassemble SDU. */
1112 if (endlist
->list
&& endlist
->list
->next
) {
1113 gint16 start
= (GPOINTER_TO_INT(endlist
->list
->data
) + 1) % 4096;
1114 gint16 end
= GPOINTER_TO_INT(endlist
->list
->next
->data
);
1115 if (frags
[end
] == NULL
) {
1116 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1117 g_warning("frag[end] is null, this is probably because end was a startpoint but because of some error ended up being treated as an endpoint, setting fail flag, start %d, end %d, packet %u\n", start
, end
, pinfo
->fd
->num
);
1119 endlist
->fail_packet
= pinfo
->fd
->num
;
1123 /* If our endpoint is a LI=0 with no data. */
1124 if (start
== end
&& frags
[start
]->len
== 0) {
1125 element
= g_list_first(endlist
->list
);
1127 endlist
->list
= g_list_remove_link(endlist
->list
, element
);
1129 frags
[start
] = frags
[start
]->next
;
1131 /* If frags[start] is not NULL now, then that means that there was
1132 * another fragment with the same seq number because of LI. If we
1133 * don't decrease the endpoint by 1 then that fragment will be
1134 * skipped and all hell will break lose. */
1135 if (frags
[start
] != NULL
) {
1136 endlist
->list
->data
= GINT_TO_POINTER(start
-1);
1138 /* NOTE: frags[start] is wmem_alloced and will remain until file closes, we would want to free it here maybe. */
1142 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1143 g_print("start: %d, end: %d\n",start
, end
);
1146 for (; special_cmp(GINT_TO_POINTER((gint
)start
), GINT_TO_POINTER((gint
)end
)) == -1; start
= (start
+1)%4096)
1148 if (frags
[start
] == NULL
) {
1149 if (MIN((start
-seq
+4096)%4096, (seq
-start
+4096)%4096) >= 1028) {
1150 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1152 "Packet %u. Setting fail flag because RLC fragment with sequence number %u was \
1153 too far away from an unfinished sequence (%u->%u). The missing sequence number \
1154 is %u. The most recently complete sequence ended in packet %u.", pinfo
->fd
->num
, seq
, 0, end
, start
, 0);
1156 endlist
->fail_packet
= pinfo
->fd
->num
; /* If it has gone too far, give up */
1162 start
= (GPOINTER_TO_INT(endlist
->list
->data
) + 1) % 4096;
1163 reassemble_sequence(frags
, endlist
, &ch_lookup
, start
, end
);
1164 } else if (endlist
->list
) {
1165 gint16 first
= (GPOINTER_TO_INT(endlist
->list
->data
) + 1) % 4096;
1166 /* If the distance between the oldest stored endpoint in endlist and
1167 * this endpoint is too large, set fail flag. */
1168 if (MIN((first
-seq
+4096)%4096, (seq
-first
+4096)%4096) >= 1028) {
1169 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1171 "Packet %u. Setting fail flag because RLC fragment with sequence number %u was \
1172 too far away from an unfinished sequence with start %u and without end.", pinfo
->fd
->num
, seq
, first
);
1174 endlist
->fail_packet
= pinfo
->fd
->num
; /* Give up if things have gone too far. */
1182 /* is_data is used to identify rlc data parts that are not identified by an LI, but are at the end of
1184 * these can be valid reassembly points, but only if the LI of the *next* relevant RLC frame is
1185 * set to '0' (this is indicated in the reassembled SDU
1188 get_reassembled_data(enum rlc_mode mode
, tvbuff_t
*tvb
, packet_info
*pinfo
,
1189 proto_tree
*tree
, guint16 seq
, guint16 num_li
)
1191 gpointer orig_frag
, orig_sdu
;
1192 struct rlc_sdu
*sdu
;
1193 struct rlc_frag lookup
, *frag
;
1195 rlc_frag_assign(&lookup
, mode
, pinfo
, seq
, num_li
);
1197 if (!g_hash_table_lookup_extended(reassembled_table
, &lookup
,
1198 &orig_frag
, &orig_sdu
))
1201 sdu
= (struct rlc_sdu
*)orig_sdu
;
1202 if (!sdu
|| !sdu
->data
)
1207 if (!rlc_frag_equal(&lookup
, sdu
->reassembled_in
)) return NULL
;
1212 while (frag
->next
) {
1213 if (frag
->next
->seq
- frag
->seq
> 1) {
1214 proto_item
*pi
= proto_tree_add_text(tree
, tvb
, 0, 0,
1215 "Error: Incomplete sequence");
1216 PROTO_ITEM_SET_GENERATED(pi
);
1217 tree_add_fragment_list_incomplete(sdu
, tvb
, tree
);
1223 sdu
->tvb
= tvb_new_child_real_data(tvb
, sdu
->data
, sdu
->len
, sdu
->len
);
1224 add_new_data_source(pinfo
, sdu
->tvb
, "Reassembled RLC Message");
1226 /* reassembly happened here, so create the fragment list */
1227 if (tree
&& sdu
->fragcnt
> 1)
1228 tree_add_fragment_list(sdu
, sdu
->tvb
, tree
);
1233 #define RLC_RETRANSMISSION_TIMEOUT 5 /* in seconds */
1235 rlc_is_duplicate(enum rlc_mode mode
, packet_info
*pinfo
, guint16 seq
,
1239 struct rlc_seqlist lookup
, *list
;
1240 struct rlc_seq seq_item
, *seq_new
;
1242 rlc_channel_assign(&lookup
.ch
, mode
, pinfo
);
1243 list
= (struct rlc_seqlist
*)g_hash_table_lookup(sequence_table
, &lookup
.ch
);
1245 /* we see this channel for the first time */
1246 list
= (struct rlc_seqlist
*)wmem_alloc0(wmem_file_scope(), sizeof(*list
));
1247 rlc_channel_assign(&list
->ch
, mode
, pinfo
);
1248 g_hash_table_insert(sequence_table
, &list
->ch
, list
);
1251 seq_item
.frame_num
= pinfo
->fd
->num
;
1253 /* seq is 12 bit (in RLC protocol) so it will wrap around after 4096. */
1254 /* Window size is at most 4095 so we remove packets further away than that */
1255 element
= g_list_first(list
->list
);
1257 seq_new
= (struct rlc_seq
*)element
->data
;
1258 /* Add 4096 because %-operation for negative values in C is not equal to mathematical modulus */
1259 if (MIN((seq_new
->seq
-seq
+4096)%4096, (seq
-seq_new
->seq
+4096)%4096) >= 1028) {
1260 list
->list
= g_list_remove_link(list
->list
, element
);
1264 element
= g_list_find_custom(list
->list
, &seq_item
, rlc_cmp_seq
);
1266 seq_new
= (struct rlc_seq
*)element
->data
;
1267 if (seq_new
->frame_num
!= seq_item
.frame_num
) {
1269 nstime_delta(&delta
, &pinfo
->fd
->abs_ts
, &seq_new
->arrival
);
1270 if (delta
.secs
< RLC_RETRANSMISSION_TIMEOUT
) {
1272 *original
= seq_new
->frame_num
;
1277 return FALSE
; /* we revisit the seq that was already seen */
1279 seq_new
= (struct rlc_seq
*)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_seq
));
1280 *seq_new
= seq_item
;
1281 seq_new
->arrival
= pinfo
->fd
->abs_ts
;
1282 list
->list
= g_list_append(list
->list
, seq_new
); /* insert in order of arrival */
1287 rlc_call_subdissector(enum rlc_channel_type channel
, tvbuff_t
*tvb
,
1288 packet_info
*pinfo
, proto_tree
*tree
)
1290 enum rrc_message_type msgtype
;
1293 msgtype
= RRC_MESSAGE_TYPE_UL_CCCH
;
1296 msgtype
= RRC_MESSAGE_TYPE_DL_CCCH
;
1299 msgtype
= RRC_MESSAGE_TYPE_INVALID
;
1300 call_dissector(bmc_handle
, tvb
, pinfo
, tree
);
1303 msgtype
= RRC_MESSAGE_TYPE_UL_DCCH
;
1306 msgtype
= RRC_MESSAGE_TYPE_DL_DCCH
;
1309 msgtype
= RRC_MESSAGE_TYPE_PCCH
;
1312 msgtype
= RRC_MESSAGE_TYPE_BCCH_FACH
;
1315 msgtype
= RRC_MESSAGE_TYPE_INVALID
;
1316 /* assume transparent PDCP for now */
1317 call_dissector(ip_handle
, tvb
, pinfo
, tree
);
1318 /* once the packet has been dissected, protect it from further changes */
1319 col_set_writable(pinfo
->cinfo
, FALSE
);
1322 return; /* stop dissecting */
1324 if (msgtype
!= RRC_MESSAGE_TYPE_INVALID
) {
1325 struct rrc_info
*rrcinf
;
1327 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
1328 rrcinf
= (rrc_info
*)p_get_proto_data(pinfo
->fd
, proto_rrc
, 0);
1330 rrcinf
= (rrc_info
*)wmem_alloc0(wmem_file_scope(), sizeof(struct rrc_info
));
1331 p_add_proto_data(pinfo
->fd
, proto_rrc
, 0, rrcinf
);
1333 rrcinf
->msgtype
[fpinf
->cur_tb
] = msgtype
;
1334 call_dissector(rrc_handle
, tvb
, pinfo
, tree
);
1335 /* once the packet has been dissected, protect it from further changes */
1336 col_set_writable(pinfo
->cinfo
, FALSE
);
1341 add_channel_info(packet_info
* pinfo
, proto_tree
* tree
, fp_info
* fpinf
, rlc_info
* rlcinf
)
1344 proto_tree
* channel_tree
;
1346 item
= proto_tree_add_item(tree
, hf_rlc_channel
, NULL
, 0, 0, ENC_NA
);
1347 channel_tree
= proto_item_add_subtree(item
, ett_rlc_channel
);
1348 proto_item_append_text(item
, " (rbid: %u, dir: %s, uid: %u)", rlcinf
->rbid
[fpinf
->cur_tb
],
1349 val_to_str_const(pinfo
->p2p_dir
, rlc_dir_vals
, "Unknown"), rlcinf
->urnti
[fpinf
->cur_tb
]);
1350 PROTO_ITEM_SET_GENERATED(item
);
1351 item
= proto_tree_add_uint(channel_tree
, hf_rlc_channel_rbid
, NULL
, 0, 0, rlcinf
->rbid
[fpinf
->cur_tb
]);
1352 PROTO_ITEM_SET_GENERATED(item
);
1353 item
= proto_tree_add_uint(channel_tree
, hf_rlc_channel_dir
, NULL
, 0, 0, pinfo
->p2p_dir
);
1354 PROTO_ITEM_SET_GENERATED(item
);
1355 item
= proto_tree_add_uint(channel_tree
, hf_rlc_channel_ueid
, NULL
, 0, 0, rlcinf
->urnti
[fpinf
->cur_tb
]);
1356 PROTO_ITEM_SET_GENERATED(item
);
1360 #ifdef HAVE_UMTS_KASUMI
1362 translate_hex_key(gchar
* char_key
){
1366 key_in
= g_malloc0(sizeof(guint8
)*16);
1367 j
= (int)(strlen(char_key
)/2)-1;
1368 /*Translate "hex-string" into a byte aligned block */
1369 for(i
= (int)strlen(char_key
); i
> 0; i
-=2 ){
1370 key_in
[j
] = ( (guint8
) (strtol( &char_key
[i
-2], NULL
, 16 ) ));
1371 char_key
[i
-2] = '\0';
1379 /** @brief Deciphers a given tvb
1381 * Note that the actual KASUMI implementation needs to be placed into
1382 * epan/crypt/kasumi.* by "end users" since due to patents the acutal implementation
1383 * cannot be distributed openly at the moment.
1385 * Refer to 3GPP TS 35.201 and 3GPP TS 35.202 for further information.
1387 * @param tvb The ciphered data.
1388 * @param pinfo Packet info.
1389 * @param counter the COUNTER value input
1390 * @param rbid the radiobear id
1391 * @param dir Direction of the link
1392 * @param header_size Size of the unciphered header
1393 * @return tvb Returns a deciphered tvb
1396 #ifndef HAVE_UMTS_KASUMI
1397 rlc_decipher_tvb(tvbuff_t
*tvb _U_
, packet_info
*pinfo
, guint32 counter _U_
,
1398 guint8 rbid _U_
, gboolean dir _U_
, guint8 header_size _U_
) {
1399 /*Check if we have a KASUMI implementation*/
1400 expert_add_info(pinfo
, NULL
, &ei_rlc_kasumi_implementation_missing
);
1403 rlc_decipher_tvb(tvbuff_t
*tvb
, packet_info
*pinfo
, guint32 counter
, guint8 rbid
, gboolean dir
, guint8 header_size
) {
1405 guint8
* out
=NULL
,*key_in
= NULL
;
1408 /*Fix the key into a byte block*/
1409 /*TODO: This should be done in a preferences callback function*/
1410 out
= wmem_alloc0(wmem_packet_scope(), strlen(global_rlc_kasumi_key
)+1);
1411 memcpy(out
,global_rlc_kasumi_key
,strlen(global_rlc_kasumi_key
)); /*Copy from prefrence const pointer*/
1412 key_in
= translate_hex_key(out
); /*Translation*/
1414 /*Location for decrypted data*/
1415 out
= g_malloc( tvb_length(tvb
) );
1417 /*Build data input but dont send the header*/
1418 for(i
= 0; i
< tvb_length(tvb
)-header_size
; i
++ ){
1419 out
[i
+header_size
] = tvb_get_guint8(tvb
, header_size
+i
);
1421 /*Call KASUMI confidentiality function, note that rbid is zero indxed*/
1422 f8( key_in
, counter
, rbid
-1, dir
, &out
[header_size
], (tvb_length(tvb
)-header_size
)*8 );
1424 /*Restore header in tvb*/
1425 for (i
= 0; i
< header_size
; i
++) {
1426 out
[i
] = tvb_get_guint8(tvb
, i
);
1430 t
= tvb_new_real_data(out
,tvb_length(tvb
), tvb_reported_length(tvb
));
1431 /*add_new_data_source(pinfo, tvb, "Data enciphered");*/
1432 add_new_data_source(pinfo
, t
, "Deciphered data");
1434 #endif /* HAVE_UMTS_KASUMI */
1438 * @param key is created with GINT_TO_POINTER
1439 * @param value is a pointer to a guint32
1440 * @param data is a pointer to a guint32
1443 iter_same(gpointer key
, gpointer value
, gpointer data
) {
1444 /*If true we found the correct frame*/
1445 if ((guint32
)GPOINTER_TO_INT(key
) > *(guint32
*)data
){
1446 *((guint32
*)data
) = *((guint32
*)value
);
1449 *((guint32
*)data
) = (guint32
)GPOINTER_TO_INT(key
);
1455 * Used for looking up and old ciphering counter value in the counter_map tree.
1456 * @param key is created with GINT_TO_POINTER
1457 * @param value is pointer to an array of 2 guint32s
1458 * @param data is a pointer to an array of 3 guint32s
1461 rlc_find_old_counter(gpointer key
, gpointer value
, gpointer data
) {
1463 /*If true we found the correct frame*/
1464 if( (guint32
)GPOINTER_TO_INT(key
) >= ((guint32
*)data
)[0] ){
1467 /*Overwrite the data since the previous one wasn't correct*/
1468 ((guint32
*)data
)[1] = ((guint32
*)value
)[0];
1469 ((guint32
*)data
)[2] = ((guint32
*)value
)[1];
1475 rlc_decipher(tvbuff_t
*tvb
, packet_info
* pinfo
, proto_tree
* tree
, fp_info
* fpinf
,
1476 rlc_info
* rlcinf
, guint16 seq
, enum rlc_mode mode
)
1478 rrc_ciphering_info
* c_inf
;
1479 guint8 indx
, header_size
, hfn_shift
;
1482 indx
= fpinf
->is_uplink
? 1 : 0;
1483 pos
= fpinf
->cur_tb
;
1484 if (mode
==RLC_UM
) {
1492 /*Ciphering info singled in RRC by securitymodecommands */
1493 c_inf
= (rrc_ciphering_info
*)g_tree_lookup(rrc_ciph_inf
, GINT_TO_POINTER((gint
)fpinf
->com_context_id
));
1495 /*TODO: This doesnt really work for all packets..*/
1496 /*Check if we have ciphering info and that this frame is ciphered*/
1497 if(c_inf
!=NULL
&& ( (c_inf
->setup_frame
> 0 && c_inf
->setup_frame
< pinfo
->fd
->num
&& c_inf
->seq_no
[rlcinf
->rbid
[pos
]][indx
] == -1) ||
1498 (c_inf
->setup_frame
< pinfo
->fd
->num
&& c_inf
->seq_no
[rlcinf
->rbid
[pos
]][indx
] >= 0 && c_inf
->seq_no
[rlcinf
->rbid
[pos
]][indx
] <= seq
) )){
1502 /*Check if this counter has been initialized*/
1503 if(!counter_init
[rlcinf
->rbid
[pos
]][indx
] ){
1504 guint32 frame_num
= pinfo
->fd
->num
;
1506 /*Initializes counter*/
1507 counter_init
[rlcinf
->rbid
[pos
]][0] = TRUE
;
1508 counter_init
[rlcinf
->rbid
[pos
]][1] = TRUE
;
1509 /*Find apropriate start value*/
1510 g_tree_foreach(c_inf
->start_ps
, (GTraverseFunc
)iter_same
, &frame_num
);
1512 /*Set COUNTER value accordingly as specified by 6.4.8 in 3GPP TS 33.102 */
1513 if(max_counter
+2 > frame_num
&& c_inf
->seq_no
[rlcinf
->rbid
[pos
]][indx
] == -1){
1514 ps_counter
[rlcinf
->rbid
[pos
]][0] = (max_counter
+2) << hfn_shift
;
1515 ps_counter
[rlcinf
->rbid
[pos
]][1] = (max_counter
+2) << hfn_shift
;
1517 ps_counter
[rlcinf
->rbid
[pos
]][0] = frame_num
<< hfn_shift
;
1518 ps_counter
[rlcinf
->rbid
[pos
]][1] = frame_num
<< hfn_shift
;
1522 /*Preserve counter value for next dissection round*/
1524 ciph
= (guint32
*)g_malloc(sizeof(guint32
)*2);
1525 ciph
[0] = ps_counter
[rlcinf
->rbid
[pos
]][0];
1526 ciph
[1] = ps_counter
[rlcinf
->rbid
[pos
]][1];
1527 g_tree_insert(counter_map
, GINT_TO_POINTER((gint
)pinfo
->fd
->num
), ciph
);
1531 /*Update the maximal COUNTER value seen so far*/
1532 max_counter
= MAX(max_counter
,((ps_counter
[rlcinf
->rbid
[pos
]][indx
]) | seq
) >> hfn_shift
);
1534 /*XXX:Since RBID in umts isnt configured properly..*/
1535 if(rlcinf
->rbid
[pos
] == 9 ){
1537 guint32 frame_num
[3];
1538 /*Set frame num we will be "searching" around*/
1539 frame_num
[0] = pinfo
->fd
->num
;
1540 /*Find the correct counter value*/
1541 g_tree_foreach(counter_map
, (GTraverseFunc
)rlc_find_old_counter
, &frame_num
[0]);
1542 t
= rlc_decipher_tvb(tvb
, pinfo
, (frame_num
[indx
+1] | seq
),16,!fpinf
->is_uplink
,header_size
);
1544 t
= rlc_decipher_tvb(tvb
, pinfo
, ((ps_counter
[rlcinf
->rbid
[pos
]][indx
]) | seq
),16,!fpinf
->is_uplink
,header_size
);
1548 /*We need to find the original counter value for second dissection pass*/
1549 guint32 frame_num
[3];
1550 frame_num
[0] = pinfo
->fd
->num
;
1551 g_tree_foreach(counter_map
, (GTraverseFunc
)rlc_find_old_counter
, &frame_num
[0]);
1552 t
= rlc_decipher_tvb(tvb
, pinfo
, (frame_num
[indx
+1] | seq
),rlcinf
->rbid
[pos
],!fpinf
->is_uplink
,header_size
);
1554 t
= rlc_decipher_tvb(tvb
, pinfo
, ((ps_counter
[rlcinf
->rbid
[pos
]][indx
]) | seq
),rlcinf
->rbid
[pos
],!fpinf
->is_uplink
,header_size
);
1557 /*Update the hyperframe number*/
1560 ps_counter
[rlcinf
->rbid
[pos
]][indx
] += 1 << hfn_shift
;
1562 if(!tree
){/*Preserve counter for second packet analysis run*/
1564 ciph
= (guint32
*)g_malloc(sizeof(guint32
)*2);
1565 ciph
[0] = ps_counter
[rlcinf
->rbid
[pos
]][0];
1566 ciph
[1] = ps_counter
[rlcinf
->rbid
[pos
]][1];
1567 g_tree_insert(counter_map
, GINT_TO_POINTER((gint
)pinfo
->fd
->num
+1), ciph
);
1571 /*Unable to decipher the packet*/
1573 proto_tree_add_text(tree
, tvb
, 0, -1,
1574 "Cannot dissect RLC frame because it is ciphered");
1575 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Ciphered Data]");
1579 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Deciphered Data]");
1581 /*TODO: Old tvb should be freed here?*/
1587 dissect_rlc_tm(enum rlc_channel_type channel
, tvbuff_t
*tvb
, packet_info
*pinfo
,
1588 proto_tree
*top_level
, proto_tree
*tree
)
1593 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
1594 rlcinf
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
1597 if (fpinf
&& rlcinf
) {
1598 /* Add "channel" information, very useful for debugging. */
1599 add_channel_info(pinfo
, tree
, fpinf
, rlcinf
);
1601 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, 0, -1, ENC_NA
);
1603 rlc_call_subdissector(channel
, tvb
, pinfo
, top_level
);
1608 rlc_um_reassemble(tvbuff_t
*tvb
, guint8 offs
, packet_info
*pinfo
, proto_tree
*tree
,
1609 proto_tree
*top_level
, enum rlc_channel_type channel
, guint16 seq
,
1610 struct rlc_li
*li
, guint16 num_li
, gboolean li_is_on_2_bytes
)
1613 gboolean dissected
= FALSE
;
1615 tvbuff_t
*next_tvb
= NULL
;
1617 /* perform reassembly now */
1618 for (i
= 0; i
< num_li
; i
++) {
1619 if ((!li_is_on_2_bytes
&& (li
[i
].li
== 0x7f)) || (li
[i
].li
== 0x7fff)) {
1620 /* padding, must be last LI */
1622 proto_tree_add_item(tree
, hf_rlc_pad
, tvb
, offs
, tvb_length_remaining(tvb
, offs
), ENC_NA
);
1624 offs
+= tvb_length_remaining(tvb
, offs
);
1625 } else if ((!li_is_on_2_bytes
&& (li
[i
].li
== 0x7c)) || (li
[i
].li
== 0x7ffc)) {
1626 /* a new SDU starts here, nothing to do */
1627 } else if (li
[i
].li
== 0x7ffa) {
1628 /* the first data octet in this RLC PDU is the first octet of an RLC SDU
1629 and the second last octet in this RLC PDU is the last octet of the same RLC SDU */
1630 length
= tvb_length_remaining(tvb
, offs
);
1633 if (tree
&& length
) {
1634 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, offs
, length
, ENC_NA
);
1636 if (global_rlc_perform_reassemby
) {
1637 add_fragment(RLC_UM
, tvb
, pinfo
, li
[i
].tree
, offs
, seq
, i
, length
, TRUE
);
1638 next_tvb
= get_reassembled_data(RLC_UM
, tvb
, pinfo
, tree
, seq
, i
);
1643 proto_tree_add_item(tree
, hf_rlc_pad
, tvb
, offs
, 1, ENC_NA
);
1647 if (tree
&& li
[i
].len
) {
1648 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, offs
, li
[i
].len
, ENC_NA
);
1650 if (global_rlc_perform_reassemby
) {
1651 add_fragment(RLC_UM
, tvb
, pinfo
, li
[i
].tree
, offs
, seq
, i
, li
[i
].len
, TRUE
);
1652 next_tvb
= get_reassembled_data(RLC_UM
, tvb
, pinfo
, tree
, seq
, i
);
1657 rlc_call_subdissector(channel
, next_tvb
, pinfo
, top_level
);
1663 /* is there data left? */
1664 if (tvb_length_remaining(tvb
, offs
) > 0) {
1666 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, offs
, -1, ENC_NA
);
1668 if (global_rlc_perform_reassemby
) {
1669 /* add remaining data as fragment */
1670 add_fragment(RLC_UM
, tvb
, pinfo
, tree
, offs
, seq
, i
, tvb_length_remaining(tvb
, offs
), FALSE
);
1671 if (dissected
== FALSE
)
1672 col_set_str(pinfo
->cinfo
, COL_INFO
, "[RLC UM Fragment]");
1675 if (dissected
== FALSE
)
1676 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC UM Fragment] SN=%u", seq
);
1678 if (channel
== RLC_UNKNOWN_CH
)
1679 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC UM Data] SN=%u", seq
);
1683 rlc_decode_li(enum rlc_mode mode
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1684 struct rlc_li
*li
, guint8 max_li
, gboolean li_on_2_bytes
)
1686 guint8 ext
, hdr_len
, offs
= 0, num_li
= 0, li_offs
;
1687 guint16 next_bytes
, prev_li
= 0;
1688 proto_item
*malformed
;
1700 case RLC_UNKNOWN_MODE
:
1705 /* calculate header length */
1706 ext
= tvb_get_guint8(tvb
, hdr_len
++) & 0x01;
1708 next_bytes
= li_on_2_bytes
? tvb_get_ntohs(tvb
, hdr_len
) : tvb_get_guint8(tvb
, hdr_len
);
1709 ext
= next_bytes
& 0x01;
1710 hdr_len
+= li_on_2_bytes
? 2 : 1;
1712 total_len
= tvb_length_remaining(tvb
, hdr_len
);
1714 /* do actual evaluation of LIs */
1715 ext
= tvb_get_guint8(tvb
, offs
++) & 0x01;
1718 if (li_on_2_bytes
) {
1719 next_bytes
= tvb_get_ntohs(tvb
, offs
);
1722 next_bytes
= tvb_get_guint8(tvb
, offs
++);
1724 ext
= next_bytes
& 0x01;
1725 li
[num_li
].ext
= ext
;
1726 li
[num_li
].li
= next_bytes
>> 1;
1728 if (li_on_2_bytes
) {
1729 switch (li
[num_li
].li
) {
1730 case 0x0000: /* previous segment was the last one */
1731 case 0x7ffb: /* previous PDU contains last segment of SDU (minus last byte) */
1732 case 0x7ffe: /* contains piggybacked STATUS in AM or segment in UM */
1733 case 0x7fff: /* padding */
1736 case 0x7ffa: /* contains exactly one SDU (minus last byte), UM only */
1737 case 0x7ffc: /* start of a new SDU, UM only */
1738 case 0x7ffd: /* contains exactly one SDU, UM only */
1739 if (mode
== RLC_UM
) {
1745 /* add malformed LI for investigation */
1746 malformed
= tree_add_li(mode
, &li
[num_li
], num_li
, li_offs
, li_on_2_bytes
, tvb
, tree
);
1747 expert_add_info(pinfo
, malformed
, &ei_rlc_li_reserved
);
1748 return -1; /* just give up on this */
1750 /* since the LI is an offset (from the end of the header), it
1751 * may not be larger than the total remaining length and no
1752 * LI may be smaller than its preceding one
1754 if (((li
[num_li
].li
> total_len
) && !global_rlc_headers_expected
)
1755 || (li
[num_li
].li
< prev_li
)) {
1756 /* add malformed LI for investigation */
1757 malformed
= tree_add_li(mode
, &li
[num_li
], num_li
, li_offs
, li_on_2_bytes
, tvb
, tree
);
1758 expert_add_info(pinfo
, malformed
, &ei_rlc_li_incorrect_warn
);
1759 return -1; /* just give up on this */
1761 li
[num_li
].len
= li
[num_li
].li
- prev_li
;
1762 prev_li
= li
[num_li
].li
;
1765 switch (li
[num_li
].li
) {
1766 case 0x00: /* previous segment was the last one */
1767 case 0x7e: /* contains piggybacked STATUS in AM or segment in UM */
1768 case 0x7f: /* padding */
1771 case 0x7c: /* start of a new SDU, UM only */
1772 case 0x7d: /* contains exactly one SDU, UM only */
1773 if (mode
== RLC_UM
) {
1779 /* add malformed LI for investigation */
1780 malformed
= tree_add_li(mode
, &li
[num_li
], num_li
, li_offs
, li_on_2_bytes
, tvb
, tree
);
1781 expert_add_info(pinfo
, malformed
, &ei_rlc_li_reserved
);
1782 return -1; /* just give up on this */
1784 /* since the LI is an offset (from the end of the header), it
1785 * may not be larger than the total remaining length and no
1786 * LI may be smaller than its preceding one
1788 if (((li
[num_li
].li
> total_len
) && !global_rlc_headers_expected
)
1789 || (li
[num_li
].li
< prev_li
)) {
1790 /* add malformed LI for investigation */
1791 malformed
= tree_add_li(mode
, &li
[num_li
], num_li
, li_offs
, li_on_2_bytes
, tvb
, tree
);
1792 expert_add_info_format(pinfo
, malformed
, &ei_rlc_li_incorrect_mal
, "Incorrect LI value 0x%x", li
[num_li
].li
);
1793 return -1; /* just give up on this */
1795 li
[num_li
].len
= li
[num_li
].li
- prev_li
;
1796 prev_li
= li
[num_li
].li
;
1799 li
[num_li
].tree
= tree_add_li(mode
, &li
[num_li
], num_li
, li_offs
, li_on_2_bytes
, tvb
, tree
);
1802 if (num_li
> max_li
) {
1803 /* OK, so this is not really a malformed packet, but for now,
1804 * we will treat it as such, so that it is marked in some way */
1805 expert_add_info(pinfo
, li
[num_li
-1].tree
, &ei_rlc_li_too_many
);
1813 dissect_rlc_um(enum rlc_channel_type channel
, tvbuff_t
*tvb
, packet_info
*pinfo
,
1814 proto_tree
*top_level
, proto_tree
*tree
)
1817 struct rlc_li li
[MAX_LI
];
1822 guint8 next_byte
, offs
= 0;
1823 gint16 pos
, num_li
= 0;
1824 gboolean is_truncated
, li_is_on_2_bytes
;
1825 proto_item
*truncated_ti
;
1827 next_byte
= tvb_get_guint8(tvb
, offs
++);
1828 seq
= next_byte
>> 1;
1830 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
1831 rlcinf
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
1834 if (fpinf
&& rlcinf
) {
1835 /* Add "channel" information, very useful for debugging. */
1836 add_channel_info(pinfo
, tree
, fpinf
, rlcinf
);
1838 /* show sequence number and extension bit */
1839 proto_tree_add_bits_item(tree
, hf_rlc_seq
, tvb
, 0, 7, ENC_BIG_ENDIAN
);
1840 proto_tree_add_bits_item(tree
, hf_rlc_ext
, tvb
, 7, 1, ENC_BIG_ENDIAN
);
1843 if (!fpinf
|| !rlcinf
) {
1844 proto_tree_add_text(tree
, tvb
, 0, -1,
1845 "Cannot dissect RLC frame because per-frame info is missing");
1849 pos
= fpinf
->cur_tb
;
1851 if ((rlcinf
->ciphered
[pos
] == TRUE
&& rlcinf
->deciphered
[pos
] == FALSE
) || global_rlc_ciphered
) {
1852 if(global_rlc_try_decipher
){
1853 rlc_decipher(tvb
, pinfo
, tree
, fpinf
, rlcinf
, seq
, RLC_UM
);
1855 proto_tree_add_text(tree
, tvb
, 0, -1,
1856 "Cannot dissect RLC frame because it is ciphered");
1857 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Ciphered Data]");
1862 if (global_rlc_li_size
== RLC_LI_UPPERLAYER
) {
1863 if (rlcinf
->li_size
[pos
] == RLC_LI_VARIABLE
) {
1864 li_is_on_2_bytes
= (tvb_length(tvb
) > 125) ? TRUE
: FALSE
;
1866 li_is_on_2_bytes
= (rlcinf
->li_size
[pos
] == RLC_LI_15BITS
) ? TRUE
: FALSE
;
1868 } else { /* Override rlcinf configuration with preference. */
1869 li_is_on_2_bytes
= (global_rlc_li_size
== RLC_LI_15BITS
) ? TRUE
: FALSE
;
1874 num_li
= rlc_decode_li(RLC_UM
, tvb
, pinfo
, tree
, li
, MAX_LI
, li_is_on_2_bytes
);
1875 if (num_li
== -1) return; /* something went wrong */
1876 offs
+= ((li_is_on_2_bytes
) ? 2 : 1) * num_li
;
1878 if (global_rlc_headers_expected
) {
1879 /* There might not be any data, if only header was logged */
1880 is_truncated
= (tvb_length_remaining(tvb
, offs
) == 0);
1881 truncated_ti
= proto_tree_add_boolean(tree
, hf_rlc_header_only
, tvb
, 0, 0,
1884 PROTO_ITEM_SET_GENERATED(truncated_ti
);
1885 expert_add_info(pinfo
, truncated_ti
, &ei_rlc_header_only
);
1888 PROTO_ITEM_SET_HIDDEN(truncated_ti
);
1892 /* do not detect duplicates or reassemble, if prefiltering is done */
1893 if (pinfo
->fd
->num
== 0) return;
1894 /* check for duplicates */
1895 if (rlc_is_duplicate(RLC_UM
, pinfo
, seq
, &orig_num
) == TRUE
) {
1896 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC UM Fragment] [Duplicate] SN=%u", seq
);
1897 proto_tree_add_uint(tree
, hf_rlc_duplicate_of
, tvb
, 0, 0, orig_num
);
1900 rlc_um_reassemble(tvb
, offs
, pinfo
, tree
, top_level
, channel
, seq
, li
, num_li
, li_is_on_2_bytes
);
1904 dissect_rlc_status(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, guint8 offset
)
1906 guint8 sufi_type
, bits
;
1907 guint64 len
, sn
, wsn
, lsn
, l
;
1908 guint16 value
, previous_sn
;
1909 gboolean isErrorBurstInd
;
1910 gint bit_offset
, previous_bit_offset
;
1912 proto_tree
*sufi_tree
, *bitmap_tree
, *rlist_tree
;
1913 proto_item
*sufi_item
, *ti
;
1914 #define BUFF_SIZE 41
1917 guint8 sufi_start_offset
;
1918 gboolean seen_last
= FALSE
;
1919 guint16 number_of_bitmap_entries
= 0;
1921 bit_offset
= offset
*8 + 4; /* first SUFI type is always 4 bit shifted */
1923 while (!seen_last
&& tvb_length_remaining(tvb
, bit_offset
/8) > 0) {
1925 sufi_type
= tvb_get_bits8(tvb
, bit_offset
, 4);
1926 sufi_start_offset
= bit_offset
/8;
1927 sufi_item
= proto_tree_add_item(tree
, hf_rlc_sufi
, tvb
, sufi_start_offset
, 0, ENC_NA
);
1928 sufi_tree
= proto_item_add_subtree(sufi_item
, ett_rlc_sufi
);
1929 proto_tree_add_bits_item(sufi_tree
, hf_rlc_sufi_type
, tvb
, bit_offset
, 4, ENC_BIG_ENDIAN
);
1930 proto_item_append_text(sufi_item
, " (%s)", val_to_str_const(sufi_type
, rlc_sufi_vals
, "Unknown"));
1932 switch (sufi_type
) {
1933 case RLC_SUFI_NOMORE
:
1937 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_lsn
, tvb
, bit_offset
, 12, &lsn
, ENC_BIG_ENDIAN
);
1938 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " LSN=%u", (guint16
)lsn
);
1939 proto_item_append_text(sufi_item
, " LSN=%u", (guint16
)lsn
);
1943 case RLC_SUFI_WINDOW
:
1944 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_wsn
, tvb
, bit_offset
, 12, &wsn
, ENC_BIG_ENDIAN
);
1945 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " WSN=%u", (guint16
)wsn
);
1949 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_len
, tvb
, bit_offset
, 4, &len
, ENC_BIG_ENDIAN
);
1950 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " LIST(%u) - ", (guint8
)len
);
1954 ti
= proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_sn
, tvb
, bit_offset
, 12, &sn
, ENC_BIG_ENDIAN
);
1955 proto_item_append_text(ti
, " (AMD PDU not correctly received)");
1957 ti
= proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_l
, tvb
, bit_offset
, 4, &l
, ENC_BIG_ENDIAN
);
1959 proto_item_append_text(ti
, " (all consecutive AMD PDUs up to SN %u not correctly received)",
1960 (unsigned)(sn
+l
)&0xfff);
1961 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%u-%u ", (guint16
)sn
, (unsigned)(sn
+l
)&0xfff);
1964 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%u ", (guint16
)sn
);
1970 expert_add_info(pinfo
, tree
, &ei_rlc_sufi_len
);
1973 case RLC_SUFI_BITMAP
:
1974 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_len
, tvb
, bit_offset
, 4, &len
, ENC_BIG_ENDIAN
);
1976 len
++; /* bitmap is len + 1 */
1977 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_fsn
, tvb
, bit_offset
, 12, &sn
, ENC_BIG_ENDIAN
);
1979 proto_tree_add_item(sufi_tree
, hf_rlc_sufi_bitmap
, tvb
, bit_offset
/8, (gint
)len
, ENC_NA
);
1980 ti
= proto_tree_add_text(sufi_tree
, tvb
, bit_offset
/8, (gint
)len
, "Decoded bitmap:");
1981 col_append_str(pinfo
->cinfo
, COL_INFO
, " BITMAP=(");
1983 bitmap_tree
= proto_item_add_subtree(ti
, ett_rlc_bitmap
);
1984 buff
= (gchar
*)wmem_alloc(wmem_packet_scope(), BUFF_SIZE
);
1985 for (i
=0; i
<len
; i
++) {
1986 bits
= tvb_get_bits8(tvb
, bit_offset
, 8);
1987 for (l
=0, j
=0; l
<8; l
++) {
1988 if ((bits
<< l
) & 0x80) {
1989 j
+= g_snprintf(&buff
[j
], BUFF_SIZE
-j
, "%4u,", (unsigned)(sn
+(8*i
)+l
)&0xfff);
1990 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %u", (unsigned)(sn
+(8*i
)+l
)&0xfff);
1991 number_of_bitmap_entries
++;
1993 j
+= g_snprintf(&buff
[j
], BUFF_SIZE
-j
, " ,");
1996 proto_tree_add_text(bitmap_tree
, tvb
, bit_offset
/8, 1, "%s", buff
);
1999 proto_item_append_text(ti
, " (%u SNs)", number_of_bitmap_entries
);
2000 col_append_str(pinfo
->cinfo
, COL_INFO
, " )");
2002 case RLC_SUFI_RLIST
:
2003 previous_bit_offset
= bit_offset
;
2004 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_len
, tvb
, bit_offset
, 4, &len
, ENC_BIG_ENDIAN
);
2006 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_fsn
, tvb
, bit_offset
, 12, &sn
, ENC_BIG_ENDIAN
);
2008 proto_item_append_text(sufi_item
, " (%u codewords)", (guint16
)len
);
2010 for (i
=0; i
<len
; i
++) {
2011 ti
= proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_cw
, tvb
, bit_offset
, 4, &l
, ENC_BIG_ENDIAN
);
2013 proto_item_append_text(ti
, " (Error burst indication)");
2018 if (len
&& (((cw
[len
-1] & 0x01) == 0) || (cw
[len
-1] == 0x01))) {
2019 expert_add_info(pinfo
, tree
, &ei_rlc_sufi_cw
);
2021 ti
= proto_tree_add_text(sufi_tree
, tvb
, previous_bit_offset
/8, (bit_offset
-previous_bit_offset
)/8, "Decoded list:");
2022 rlist_tree
= proto_item_add_subtree(ti
, ett_rlc_rlist
);
2023 proto_tree_add_text(rlist_tree
, tvb
, (previous_bit_offset
+4)/8, 12/8,
2024 "Sequence Number = %u (AMD PDU not correctly received)",(unsigned)sn
);
2025 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " RLIST=(%u", (unsigned)sn
);
2027 for (i
=0, isErrorBurstInd
=FALSE
, j
=0, previous_sn
=(guint16
)sn
, value
=0; i
<len
; i
++) {
2028 if (cw
[i
] == 0x01) {
2029 isErrorBurstInd
= TRUE
;
2031 value
|= (cw
[i
] >> 1) << j
;
2034 if (isErrorBurstInd
) {
2035 previous_sn
= (previous_sn
+ value
) & 0xfff;
2036 ti
= proto_tree_add_text(rlist_tree
, tvb
, (previous_bit_offset
+16+4*i
)/8, 1, "Length: %u", value
);
2038 proto_item_append_text(ti
, " (all consecutive AMD PDUs up to SN %u not correctly received)", previous_sn
);
2039 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " ->%u", previous_sn
);
2041 isErrorBurstInd
= FALSE
;
2043 value
= (value
+ previous_sn
) & 0xfff;
2044 proto_tree_add_text(rlist_tree
, tvb
, (previous_bit_offset
+16+4*i
)/8, 1, "Sequence Number = %u (AMD PDU not correctly received)",value
);
2045 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %u", value
);
2046 previous_sn
= value
;
2052 col_append_str(pinfo
->cinfo
, COL_INFO
, ")");
2055 case RLC_SUFI_MRW_ACK
:
2056 col_append_str(pinfo
->cinfo
, COL_INFO
, " MRW-ACK");
2057 proto_tree_add_bits_item(sufi_tree
, hf_rlc_sufi_n
, tvb
, bit_offset
, 4, ENC_BIG_ENDIAN
);
2059 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_sn_ack
, tvb
, bit_offset
, 12, &sn
, ENC_BIG_ENDIAN
);
2061 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " SN=%u", (guint16
)sn
);
2064 col_append_str(pinfo
->cinfo
, COL_INFO
, " MRW");
2065 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_len
, tvb
, bit_offset
, 4, &len
, ENC_BIG_ENDIAN
);
2069 proto_tree_add_bits_ret_val(sufi_tree
, hf_rlc_sufi_sn_mrw
, tvb
, bit_offset
, 12, &sn
, ENC_BIG_ENDIAN
);
2070 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " SN=%u", (guint16
)sn
);
2075 /* only one SN_MRW field is present */
2076 ti
= proto_tree_add_bits_item(sufi_tree
, hf_rlc_sufi_sn_mrw
, tvb
, bit_offset
, 12, ENC_BIG_ENDIAN
);
2077 proto_item_append_text(ti
, " (RLC SDU to be discarded in the Receiver extends above the configured transmission window in the Sender)");
2080 proto_tree_add_bits_item(sufi_tree
, hf_rlc_sufi_n
, tvb
, bit_offset
, 4, ENC_BIG_ENDIAN
);
2084 proto_tree_add_bits_item(sufi_tree
, hf_rlc_sufi_poll_sn
, tvb
, bit_offset
, 12, ENC_BIG_ENDIAN
);
2089 expert_add_info(pinfo
, tree
, &ei_rlc_sufi_type
);
2090 return; /* invalid value, ignore the rest */
2093 /* Set extent of SUFI root */
2094 proto_item_set_len(sufi_item
, ((bit_offset
+7)/8) - sufi_start_offset
);
2099 dissect_rlc_control(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2101 guint8 type
, next_byte
;
2106 next_byte
= tvb_get_guint8(tvb
, 0);
2107 type
= (next_byte
>> 4) & 0x07;
2109 ti
= proto_tree_add_bits_item(tree
, hf_rlc_ctrl_type
, tvb
, 1, 3, ENC_BIG_ENDIAN
);
2112 dissect_rlc_status(tvb
, pinfo
, tree
, 0);
2116 col_append_str(pinfo
->cinfo
, COL_INFO
, (type
== RLC_RESET
) ? " RESET" : " RESET-ACK");
2117 proto_tree_add_bits_ret_val(tree
, hf_rlc_rsn
, tvb
, 4, 1, &rsn
, ENC_BIG_ENDIAN
);
2118 proto_tree_add_bits_ret_val(tree
, hf_rlc_r1
, tvb
, 5, 3, &r1
, ENC_BIG_ENDIAN
);
2120 expert_add_info(pinfo
, ti
, &ei_rlc_reserved_bits_not_zero
);
2123 proto_tree_add_bits_ret_val(tree
, hf_rlc_hfni
, tvb
, 8, 20, &hfn
, ENC_BIG_ENDIAN
);
2124 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " RSN=%u HFN=%u", (guint16
)rsn
, (guint32
)hfn
);
2127 expert_add_info(pinfo
, ti
, &ei_rlc_ctrl_type
);
2128 return; /* invalid */
2133 rlc_am_reassemble(tvbuff_t
*tvb
, guint8 offs
, packet_info
*pinfo
,
2134 proto_tree
*tree
, proto_tree
*top_level
,
2135 enum rlc_channel_type channel
, guint16 seq
, gboolean poll_set
, struct rlc_li
*li
,
2136 guint16 num_li
, gboolean final
, gboolean li_is_on_2_bytes
)
2139 gboolean piggyback
= FALSE
, dissected
= FALSE
;
2140 tvbuff_t
*next_tvb
= NULL
;
2142 /* perform reassembly now */
2143 for (i
= 0; i
< num_li
; i
++) {
2144 if ((!li_is_on_2_bytes
&& (li
[i
].li
== 0x7e)) || (li
[i
].li
== 0x7ffe)) {
2145 /* piggybacked status */
2147 } else if ((!li_is_on_2_bytes
&& (li
[i
].li
== 0x7f)) || (li
[i
].li
== 0x7fff)) {
2148 /* padding, must be last LI */
2149 if (tvb_length_remaining(tvb
, offs
) > 0) {
2151 proto_tree_add_item(tree
, hf_rlc_pad
, tvb
, offs
, -1, ENC_NA
);
2154 /* Insert empty RLC frag so RLC doesn't miss this seq number. */
2155 add_fragment(RLC_AM
, tvb
, pinfo
, li
[i
].tree
, offs
, seq
, i
, 0, TRUE
);
2158 offs
+= tvb_length_remaining(tvb
, offs
);
2161 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, offs
, li
[i
].len
, ENC_NA
);
2163 if (global_rlc_perform_reassemby
) {
2164 add_fragment(RLC_AM
, tvb
, pinfo
, li
[i
].tree
, offs
, seq
, i
, li
[i
].len
, TRUE
);
2165 next_tvb
= get_reassembled_data(RLC_AM
, tvb
, pinfo
, tree
, seq
, i
);
2170 rlc_call_subdissector(channel
, next_tvb
, pinfo
, top_level
);
2177 dissect_rlc_status(tvb
, pinfo
, tree
, offs
);
2179 if (tvb_length_remaining(tvb
, offs
) > 0) {
2180 /* we have remaining data, which we need to mark in the tree */
2182 proto_tree_add_item(tree
, hf_rlc_data
, tvb
, offs
, -1, ENC_NA
);
2184 if (global_rlc_perform_reassemby
) {
2185 add_fragment(RLC_AM
, tvb
, pinfo
, tree
, offs
, seq
, i
,
2186 tvb_length_remaining(tvb
,offs
), final
);
2188 next_tvb
= get_reassembled_data(RLC_AM
, tvb
, pinfo
, tree
, seq
, i
);
2194 rlc_call_subdissector(channel
, next_tvb
, pinfo
, top_level
);
2198 if (dissected
== FALSE
)
2199 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC AM Fragment] SN=%u %s",
2200 seq
, poll_set
? "(P)" : "");
2202 if (channel
== RLC_UNKNOWN_CH
)
2203 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC AM Data] SN=%u %s",
2204 seq
, poll_set
? "(P)" : "");
2208 dissect_rlc_am(enum rlc_channel_type channel
, tvbuff_t
*tvb
, packet_info
*pinfo
,
2209 proto_tree
*top_level
, proto_tree
*tree
)
2212 struct rlc_li li
[MAX_LI
];
2216 guint8 next_byte
, offs
= 0;
2217 guint32 orig_num
= 0;
2218 gint16 num_li
= 0, pos
;
2220 gboolean is_truncated
, li_is_on_2_bytes
;
2221 proto_item
*truncated_ti
, *ti
;
2224 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2225 rlcinf
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2227 next_byte
= tvb_get_guint8(tvb
, offs
++);
2228 dc
= next_byte
>> 7;
2230 if (fpinf
&& rlcinf
) {
2231 /* Add "channel" information, very useful for debugging. */
2232 add_channel_info(pinfo
, tree
, fpinf
, rlcinf
);
2234 proto_tree_add_bits_item(tree
, hf_rlc_dc
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
2237 col_set_str(pinfo
->cinfo
, COL_INFO
, "[RLC Control Frame]");
2238 dissect_rlc_control(tvb
, pinfo
, tree
);
2242 seq
= next_byte
& 0x7f;
2244 next_byte
= tvb_get_guint8(tvb
, offs
++);
2245 seq
|= (next_byte
>> 3);
2247 ext
= next_byte
& 0x03;
2248 /* show header fields */
2249 proto_tree_add_bits_item(tree
, hf_rlc_seq
, tvb
, 1, 12, ENC_BIG_ENDIAN
);
2250 proto_tree_add_bits_ret_val(tree
, hf_rlc_p
, tvb
, 13, 1, &polling
, ENC_BIG_ENDIAN
);
2251 ti
= proto_tree_add_bits_item(tree
, hf_rlc_he
, tvb
, 14, 2, ENC_BIG_ENDIAN
);
2253 /* header extension may only be 00, 01 or 10 */
2255 expert_add_info(pinfo
, ti
, &ei_rlc_he
);
2259 if (!fpinf
|| !rlcinf
) {
2260 proto_tree_add_text(tree
, tvb
, 0, -1,
2261 "Cannot dissect RLC frame because per-frame info is missing");
2265 pos
= fpinf
->cur_tb
;
2268 * WARNING DECIPHERING IS HIGHLY EXPERIMENTAL!!!
2270 if (((rlcinf
->ciphered
[pos
] == TRUE
&& rlcinf
->deciphered
[pos
] == FALSE
) || global_rlc_ciphered
)) {
2271 if(global_rlc_try_decipher
){
2272 rlc_decipher(tvb
, pinfo
, tree
, fpinf
, rlcinf
, seq
, RLC_AM
);
2274 proto_tree_add_text(tree
, tvb
, 0, -1,
2275 "Cannot dissect RLC frame because it is ciphered");
2276 col_append_str(pinfo
->cinfo
, COL_INFO
, "[Ciphered Data]");
2281 if (global_rlc_li_size
== RLC_LI_UPPERLAYER
) {
2282 if (rlcinf
->li_size
[pos
] == RLC_LI_VARIABLE
) {
2283 li_is_on_2_bytes
= (tvb_length(tvb
) > 126) ? TRUE
: FALSE
;
2285 li_is_on_2_bytes
= (rlcinf
->li_size
[pos
] == RLC_LI_15BITS
) ? TRUE
: FALSE
;
2287 } else { /* Override rlcinf configuration with preference. */
2288 li_is_on_2_bytes
= (global_rlc_li_size
== RLC_LI_15BITS
) ? TRUE
: FALSE
;
2291 num_li
= rlc_decode_li(RLC_AM
, tvb
, pinfo
, tree
, li
, MAX_LI
, li_is_on_2_bytes
);
2292 if (num_li
== -1) return; /* something went wrong */
2293 offs
+= ((li_is_on_2_bytes
) ? 2 : 1) * num_li
;
2294 if (global_rlc_headers_expected
) {
2295 /* There might not be any data, if only header was logged */
2296 is_truncated
= (tvb_length_remaining(tvb
, offs
) == 0);
2297 truncated_ti
= proto_tree_add_boolean(tree
, hf_rlc_header_only
, tvb
, 0, 0,
2300 PROTO_ITEM_SET_GENERATED(truncated_ti
);
2301 expert_add_info(pinfo
, truncated_ti
, &ei_rlc_header_only
);
2304 PROTO_ITEM_SET_HIDDEN(truncated_ti
);
2308 /* do not detect duplicates or reassemble, if prefiltering is done */
2309 if (pinfo
->fd
->num
== 0) return;
2310 /* check for duplicates, but not if already visited */
2311 if (pinfo
->fd
->flags
.visited
== FALSE
&& rlc_is_duplicate(RLC_AM
, pinfo
, seq
, &orig_num
) == TRUE
) {
2312 g_hash_table_insert(duplicate_table
, GUINT_TO_POINTER(pinfo
->fd
->num
), GUINT_TO_POINTER(orig_num
));
2314 } else if (pinfo
->fd
->flags
.visited
== TRUE
&& tree
) {
2315 gpointer value
= g_hash_table_lookup(duplicate_table
, GUINT_TO_POINTER(pinfo
->fd
->num
));
2316 if (value
!= NULL
) {
2317 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "[RLC AM Fragment] [Duplicate] SN=%u %s", seq
, (polling
!= 0) ? "(P)" : "");
2318 proto_tree_add_uint(tree
, hf_rlc_duplicate_of
, tvb
, 0, 0, GPOINTER_TO_UINT(value
));
2323 rlc_am_reassemble(tvb
, offs
, pinfo
, tree
, top_level
, channel
, seq
, polling
!= 0,
2324 li
, num_li
, ext
== 2, li_is_on_2_bytes
);
2327 /* dissect entry functions */
2329 dissect_rlc_pcch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2331 proto_tree
*subtree
= NULL
;
2333 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2334 col_clear(pinfo
->cinfo
, COL_INFO
);
2336 /* PCCH is always RLC TM */
2339 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2340 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2341 proto_item_append_text(ti
, " TM (PCCH)");
2343 dissect_rlc_tm(RLC_PCCH
, tvb
, pinfo
, tree
, subtree
);
2347 dissect_rlc_bcch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2350 proto_item
*ti
= NULL
;
2351 proto_tree
*subtree
= NULL
;
2353 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2354 col_clear(pinfo
->cinfo
, COL_INFO
);
2356 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2357 if (!fpi
) return; /* dissection failure */
2360 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2361 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2363 proto_item_append_text(ti
, " TM (BCCH)");
2364 dissect_rlc_tm(RLC_BCCH
, tvb
, pinfo
, tree
, subtree
);
2368 dissect_rlc_ccch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2371 proto_item
*ti
= NULL
;
2372 proto_tree
*subtree
= NULL
;
2374 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2375 col_clear(pinfo
->cinfo
, COL_INFO
);
2377 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2378 if (!fpi
) return; /* dissection failure */
2381 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2382 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2385 if (fpi
->is_uplink
) {
2386 /* UL CCCH is always RLC TM */
2387 proto_item_append_text(ti
, " TM (CCCH)");
2388 dissect_rlc_tm(RLC_UL_CCCH
, tvb
, pinfo
, tree
, subtree
);
2390 /* DL CCCH is always UM */
2391 proto_item_append_text(ti
, " UM (CCCH)");
2392 dissect_rlc_um(RLC_DL_CCCH
, tvb
, pinfo
, tree
, subtree
);
2397 dissect_rlc_ctch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2400 proto_item
*ti
= NULL
;
2401 proto_tree
*subtree
= NULL
;
2404 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2405 col_clear(pinfo
->cinfo
, COL_INFO
);
2407 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2408 if (!fpi
) return; /* dissection failure */
2411 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2412 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2415 /* CTCH is always UM */
2416 proto_item_append_text(ti
, " UM (CTCH)");
2417 dissect_rlc_um(RLC_DL_CTCH
, tvb
, pinfo
, tree
, subtree
);
2421 dissect_rlc_dcch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2423 proto_item
*ti
= NULL
;
2424 proto_tree
*subtree
= NULL
;
2427 enum rlc_channel_type channel
;
2429 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2430 col_clear(pinfo
->cinfo
, COL_INFO
);
2432 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2433 rlci
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2436 ti
= proto_tree_add_text(tree
, tvb
, 0, -1,
2437 "Can't dissect RLC frame because no per-frame info was attached!");
2438 PROTO_ITEM_SET_GENERATED(ti
);
2443 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2444 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2447 channel
= fpi
->is_uplink
? RLC_UL_DCCH
: RLC_DL_DCCH
;
2449 switch (rlci
->mode
[fpi
->cur_tb
]) {
2451 proto_item_append_text(ti
, " UM (DCCH)");
2452 dissect_rlc_um(channel
, tvb
, pinfo
, tree
, subtree
);
2455 proto_item_append_text(ti
, " AM (DCCH)");
2456 dissect_rlc_am(channel
, tvb
, pinfo
, tree
, subtree
);
2462 dissect_rlc_ps_dtch(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2464 proto_item
*ti
= NULL
;
2465 proto_tree
*subtree
= NULL
;
2469 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2470 col_clear(pinfo
->cinfo
, COL_INFO
);
2472 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2473 rlci
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2475 if (!fpi
|| !rlci
) {
2476 ti
= proto_tree_add_text(tree
, tvb
, 0, -1,
2477 "Can't dissect RLC frame because no per-frame info was attached!");
2478 PROTO_ITEM_SET_GENERATED(ti
);
2483 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2484 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2487 switch (rlci
->mode
[fpi
->cur_tb
]) {
2489 proto_item_append_text(ti
, " UM (PS DTCH)");
2490 dissect_rlc_um(RLC_PS_DTCH
, tvb
, pinfo
, tree
, subtree
);
2493 proto_item_append_text(ti
, " AM (PS DTCH)");
2494 dissect_rlc_am(RLC_PS_DTCH
, tvb
, pinfo
, tree
, subtree
);
2497 proto_item_append_text(ti
, " TM (PS DTCH)");
2498 dissect_rlc_tm(RLC_PS_DTCH
, tvb
, pinfo
, tree
, subtree
);
2504 dissect_rlc_dch_unknown(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2506 proto_item
*ti
= NULL
;
2507 proto_tree
*subtree
= NULL
;
2511 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2512 col_clear(pinfo
->cinfo
, COL_INFO
);
2514 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2515 rlci
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2517 if (!fpi
|| !rlci
) return;
2520 ti
= proto_tree_add_item(tree
, proto_rlc
, tvb
, 0, -1, ENC_NA
);
2521 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2524 switch (rlci
->mode
[fpi
->cur_tb
]) {
2526 proto_item_append_text(ti
, " UM (Unknown)");
2527 dissect_rlc_um(RLC_UNKNOWN_CH
, tvb
, pinfo
, tree
, subtree
);
2530 proto_item_append_text(ti
, " AM (Unknown)");
2531 dissect_rlc_am(RLC_UNKNOWN_CH
, tvb
, pinfo
, tree
, subtree
);
2534 proto_item_append_text(ti
, " TM (Unknown)");
2535 dissect_rlc_tm(RLC_UNKNOWN_CH
, tvb
, pinfo
, tree
, subtree
);
2541 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2543 dissect_rlc_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2550 guint channelType
= UMTS_CHANNEL_TYPE_UNSPECIFIED
;
2551 gboolean fpInfoAlreadySet
= FALSE
;
2552 gboolean rlcInfoAlreadySet
= FALSE
;
2553 gboolean channelTypePresent
= FALSE
;
2554 gboolean rlcModePresent
= FALSE
;
2555 proto_item
*ti
= NULL
;
2556 proto_tree
*subtree
= NULL
;
2558 /* This is a heuristic dissector, which means we get all the UDP
2559 * traffic not sent to a known dissector and not claimed by
2560 * a heuristic dissector called before us!
2562 if (!global_rlc_heur
) {
2566 /* Do this again on re-dissection to re-discover offset of actual PDU */
2568 /* Needs to be at least as long as:
2569 - the signature string
2570 - conditional header bytes
2572 - at least one byte of RLC PDU payload */
2573 if (tvb_length_remaining(tvb
, offset
) < (gint
)(strlen(RLC_START_STRING
)+2+2)) {
2577 /* OK, compare with signature string */
2578 if (tvb_strneql(tvb
, offset
, RLC_START_STRING
, (gint
)strlen(RLC_START_STRING
)) != 0) {
2581 offset
+= (gint
)strlen(RLC_START_STRING
);
2583 /* If redissecting, use previous info struct (if available) */
2584 fpi
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2586 /* Allocate new info struct for this frame */
2587 fpi
= (fp_info
*)wmem_alloc0(wmem_file_scope(), sizeof(fp_info
));
2589 fpInfoAlreadySet
= TRUE
;
2591 rlci
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2593 /* Allocate new info struct for this frame */
2594 rlci
= (rlc_info
*)wmem_alloc0(wmem_file_scope(), sizeof(rlc_info
));
2596 rlcInfoAlreadySet
= TRUE
;
2599 /* Read conditional/optional fields */
2600 while (tag
!= RLC_PAYLOAD_TAG
) {
2601 /* Process next tag */
2602 tag
= tvb_get_guint8(tvb
, offset
++);
2604 case RLC_CHANNEL_TYPE_TAG
:
2605 channelType
= tvb_get_guint8(tvb
, offset
);
2607 channelTypePresent
= TRUE
;
2610 rlci
->mode
[fpi
->cur_tb
] = tvb_get_guint8(tvb
, offset
);
2612 rlcModePresent
= TRUE
;
2614 case RLC_DIRECTION_TAG
:
2615 if (tvb_get_guint8(tvb
, offset
) == DIRECTION_UPLINK
) {
2616 fpi
->is_uplink
= TRUE
;
2617 pinfo
->p2p_dir
= P2P_DIR_UL
;
2619 fpi
->is_uplink
= FALSE
;
2620 pinfo
->p2p_dir
= P2P_DIR_DL
;
2625 rlci
->urnti
[fpi
->cur_tb
] = tvb_get_ntohl(tvb
, offset
);
2628 case RLC_RADIO_BEARER_ID_TAG
:
2629 rlci
->rbid
[fpi
->cur_tb
] = tvb_get_guint8(tvb
, offset
);
2632 case RLC_LI_SIZE_TAG
:
2633 rlci
->li_size
[fpi
->cur_tb
] = (enum rlc_li_size
) tvb_get_guint8(tvb
, offset
);
2636 case RLC_PAYLOAD_TAG
:
2637 /* Have reached data, so get out of loop */
2640 /* It must be a recognised tag */
2645 if ((channelTypePresent
== FALSE
) && (rlcModePresent
== FALSE
)) {
2646 /* Conditional fields are missing */
2650 /* Store info in packet if needed */
2651 if (!fpInfoAlreadySet
) {
2652 p_add_proto_data(pinfo
->fd
, proto_fp
, 0, fpi
);
2654 if (!rlcInfoAlreadySet
) {
2655 p_add_proto_data(pinfo
->fd
, proto_rlc
, 0, rlci
);
2658 /**************************************/
2659 /* OK, now dissect as RLC */
2661 /* Create tvb that starts at actual RLC PDU */
2662 rlc_tvb
= tvb_new_subset_remaining(tvb
, offset
);
2663 switch (channelType
) {
2664 case UMTS_CHANNEL_TYPE_UNSPECIFIED
:
2665 /* Call relevant dissector according to RLC mode */
2666 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RLC");
2667 col_clear(pinfo
->cinfo
, COL_INFO
);
2670 ti
= proto_tree_add_item(tree
, proto_rlc
, rlc_tvb
, 0, -1, ENC_NA
);
2671 subtree
= proto_item_add_subtree(ti
, ett_rlc
);
2674 if (rlci
->mode
[fpi
->cur_tb
] == RLC_AM
) {
2675 proto_item_append_text(ti
, " AM");
2676 dissect_rlc_am(RLC_UNKNOWN_CH
, rlc_tvb
, pinfo
, tree
, subtree
);
2677 } else if (rlci
->mode
[fpi
->cur_tb
] == RLC_UM
) {
2678 proto_item_append_text(ti
, " UM");
2679 dissect_rlc_um(RLC_UNKNOWN_CH
, rlc_tvb
, pinfo
, tree
, subtree
);
2681 proto_item_append_text(ti
, " TM");
2682 dissect_rlc_tm(RLC_UNKNOWN_CH
, rlc_tvb
, pinfo
, tree
, subtree
);
2685 case UMTS_CHANNEL_TYPE_PCCH
:
2686 dissect_rlc_pcch(rlc_tvb
, pinfo
, tree
);
2688 case UMTS_CHANNEL_TYPE_CCCH
:
2689 dissect_rlc_ccch(rlc_tvb
, pinfo
, tree
);
2691 case UMTS_CHANNEL_TYPE_DCCH
:
2692 dissect_rlc_dcch(rlc_tvb
, pinfo
, tree
);
2694 case UMTS_CHANNEL_TYPE_PS_DTCH
:
2695 dissect_rlc_ps_dtch(rlc_tvb
, pinfo
, tree
);
2697 case UMTS_CHANNEL_TYPE_CTCH
:
2698 dissect_rlc_ctch(rlc_tvb
, pinfo
, tree
);
2700 case UMTS_CHANNEL_TYPE_BCCH
:
2701 dissect_rlc_bcch(rlc_tvb
, pinfo
, tree
);
2704 /* Unknown channel type */
2712 rlc_is_ciphered(packet_info
* pinfo
){
2717 return global_rlc_ciphered
;
2720 fpinf
= (fp_info
*)p_get_proto_data(pinfo
->fd
, proto_fp
, 0);
2721 rlcinf
= (rlc_info
*)p_get_proto_data(pinfo
->fd
, proto_rlc
, 0);
2723 return ((rlcinf
&& fpinf
&& (rlcinf
->ciphered
[fpinf
->cur_tb
] == TRUE
) && (rlcinf
->deciphered
[fpinf
->cur_tb
] == FALSE
))
2724 || global_rlc_ciphered
);
2728 proto_register_rlc(void)
2730 module_t
*rlc_module
;
2731 expert_module_t
* expert_rlc
;
2732 static hf_register_info hf
[] = {
2734 { "D/C Bit", "rlc.dc",
2735 FT_BOOLEAN
, BASE_NONE
, TFS(&rlc_dc_val
), 0, NULL
, HFILL
}
2737 { &hf_rlc_ctrl_type
,
2738 { "Control PDU Type", "rlc.ctrl_pdu_type",
2739 FT_UINT8
, BASE_DEC
, VALS(rlc_ctrl_vals
), 0, "PDU Type", HFILL
}
2742 { "Reserved 1", "rlc.r1",
2743 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2746 { "Reset Sequence Number", "rlc.rsn",
2747 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2750 { "Hyper Frame Number Indicator", "rlc.hfni",
2751 FT_UINT24
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2754 { "Sequence Number", "rlc.seq",
2755 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2758 { "Extension Bit", "rlc.ext",
2759 FT_BOOLEAN
, BASE_NONE
, TFS(&rlc_ext_val
), 0, NULL
, HFILL
}
2762 { "Header Extension Type", "rlc.he",
2763 FT_UINT8
, BASE_DEC
, VALS(rlc_he_vals
), 0, NULL
, HFILL
}
2766 { "Polling Bit", "rlc.p",
2767 FT_BOOLEAN
, BASE_NONE
, TFS(&rlc_p_val
), 0, NULL
, HFILL
}
2770 { "Padding", "rlc.padding",
2771 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2774 { "Reassembled Fragments", "rlc.fragments",
2775 FT_NONE
, BASE_NONE
, NULL
, 0, "Fragments", HFILL
}
2778 { "RLC Fragment", "rlc.fragment",
2779 FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2781 { &hf_rlc_duplicate_of
,
2782 { "Duplicate of", "rlc.duplicate_of",
2783 FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2785 { &hf_rlc_reassembled_in
,
2786 { "Reassembled Message in frame", "rlc.reassembled_in",
2787 FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2790 { "Data", "rlc.data",
2791 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2793 /* LI information */
2796 FT_NONE
, BASE_NONE
, NULL
, 0, "Length Indicator", HFILL
}
2799 { "LI value", "rlc.li.value",
2800 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2803 { "LI extension bit", "rlc.li.ext",
2804 FT_BOOLEAN
, BASE_NONE
, TFS(&rlc_ext_val
), 0, NULL
, HFILL
}
2807 { "LI Data", "rlc.li.data",
2808 FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2810 /* SUFI information */
2812 { "SUFI", "rlc.sufi",
2813 FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2815 { &hf_rlc_sufi_type
,
2816 { "SUFI Type", "rlc.sufi.type",
2817 FT_UINT8
, BASE_DEC
, VALS(rlc_sufi_vals
), 0, NULL
, HFILL
}
2820 { "Last Sequence Number", "rlc.sufi.lsn",
2821 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2824 { "Window Size Number", "rlc.sufi.wsn",
2825 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2828 { "Sequence Number", "rlc.sufi.sn",
2829 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2832 { "Length", "rlc.sufi.l",
2833 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2836 { "Length", "rlc.sufi.len",
2837 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2840 { "First Sequence Number", "rlc.sufi.fsn",
2841 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2843 { &hf_rlc_sufi_bitmap
,
2844 { "Bitmap", "rlc.sufi.bitmap",
2845 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2848 { "Codeword", "rlc.sufi.cw",
2849 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2852 { "Nlength", "rlc.sufi.n",
2853 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2855 { &hf_rlc_sufi_sn_ack
,
2856 { "SN ACK", "rlc.sufi.sn_ack",
2857 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2859 { &hf_rlc_sufi_sn_mrw
,
2860 { "SN MRW", "rlc.sufi.sn_mrw",
2861 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2863 { &hf_rlc_sufi_poll_sn
,
2864 { "Poll SN", "rlc.sufi.poll_sn",
2865 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2867 /* Other information */
2868 { &hf_rlc_header_only
,
2869 { "RLC PDU header only", "rlc.header_only",
2870 FT_BOOLEAN
, BASE_NONE
, TFS(&rlc_header_only_val
), 0 ,NULL
, HFILL
}
2873 { "Channel", "rlc.channel",
2874 FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
2876 { &hf_rlc_channel_rbid
,
2877 { "Radio Bearer ID", "rlc.channel.rbid",
2878 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2880 { &hf_rlc_channel_dir
,
2881 { "Direction", "rlc.channel.dir",
2882 FT_UINT8
, BASE_DEC
, VALS(rlc_dir_vals
), 0, NULL
, HFILL
}
2884 { &hf_rlc_channel_ueid
,
2885 { "User Equipment ID", "rlc.channel.ueid",
2886 FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
2889 static gint
*ett
[] = {
2899 static ei_register_info ei
[] = {
2900 { &ei_rlc_reassembly_fail_unfinished_sequence
, { "rlc.reassembly.fail.unfinished_sequence", PI_REASSEMBLE
, PI_ERROR
, "Did not perform reassembly because of previous unfinished sequence.", EXPFILL
}},
2901 { &ei_rlc_reassembly_fail_flag_set
, { "rlc.reassembly.fail.flag_set", PI_REASSEMBLE
, PI_ERROR
, "Did not perform reassembly because fail flag was set previously.", EXPFILL
}},
2902 { &ei_rlc_reassembly_lingering_endpoint
, { "rlc.lingering_endpoint", PI_REASSEMBLE
, PI_ERROR
, "Lingering endpoint.", EXPFILL
}},
2903 { &ei_rlc_reassembly_unknown_error
, { "rlc.reassembly.unknown_error", PI_REASSEMBLE
, PI_ERROR
, "Unknown error.", EXPFILL
}},
2904 { &ei_rlc_kasumi_implementation_missing
, { "rlc.kasumi_implementation_missing", PI_UNDECODED
, PI_WARN
, "Unable to decipher packet since KASUMI implementation is missing.", EXPFILL
}},
2905 { &ei_rlc_li_reserved
, { "rlc.li.reserved", PI_PROTOCOL
, PI_WARN
, "Uses reserved LI", EXPFILL
}},
2906 { &ei_rlc_li_incorrect_warn
, { "rlc.li.incorrect", PI_PROTOCOL
, PI_WARN
, "Incorrect LI value", EXPFILL
}},
2907 { &ei_rlc_li_incorrect_mal
, { "rlc.li.incorrect", PI_MALFORMED
, PI_ERROR
, "Incorrect LI value 0x%x", EXPFILL
}},
2908 { &ei_rlc_li_too_many
, { "rlc.li.too_many", PI_MALFORMED
, PI_ERROR
, "Too many LI entries", EXPFILL
}},
2909 { &ei_rlc_header_only
, { "rlc.header_only.expert", PI_SEQUENCE
, PI_NOTE
, "RLC PDU SDUs have been omitted", EXPFILL
}},
2910 { &ei_rlc_sufi_len
, { "rlc.sufi.len.invalid", PI_MALFORMED
, PI_ERROR
, "Invalid length", EXPFILL
}},
2911 { &ei_rlc_sufi_cw
, { "rlc.sufi.cw.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid last codeword", EXPFILL
}},
2912 { &ei_rlc_sufi_type
, { "rlc.sufi.type.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid SUFI type", EXPFILL
}},
2913 { &ei_rlc_reserved_bits_not_zero
, { "rlc.reserved_bits_not_zero", PI_PROTOCOL
, PI_WARN
, "reserved bits not zero", EXPFILL
}},
2914 { &ei_rlc_ctrl_type
, { "rlc.ctrl_pdu_type.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid RLC AM control type %u", EXPFILL
}},
2915 { &ei_rlc_he
, { "rlc.he.invalid", PI_PROTOCOL
, PI_WARN
, "Incorrect HE value", EXPFILL
}},
2918 proto_rlc
= proto_register_protocol("Radio Link Control", "RLC", "rlc");
2919 register_dissector("rlc.bcch", dissect_rlc_bcch
, proto_rlc
);
2920 register_dissector("rlc.pcch", dissect_rlc_pcch
, proto_rlc
);
2921 register_dissector("rlc.ccch", dissect_rlc_ccch
, proto_rlc
);
2922 register_dissector("rlc.ctch", dissect_rlc_ctch
, proto_rlc
);
2923 register_dissector("rlc.dcch", dissect_rlc_dcch
, proto_rlc
);
2924 register_dissector("rlc.ps_dtch", dissect_rlc_ps_dtch
, proto_rlc
);
2925 register_dissector("rlc.dch_unknown", dissect_rlc_dch_unknown
, proto_rlc
);
2927 proto_register_field_array(proto_rlc
, hf
, array_length(hf
));
2928 proto_register_subtree_array(ett
, array_length(ett
));
2929 expert_rlc
= expert_register_protocol(proto_rlc
);
2930 expert_register_field_array(expert_rlc
, ei
, array_length(ei
));
2933 rlc_module
= prefs_register_protocol(proto_rlc
, NULL
);
2935 prefs_register_bool_preference(rlc_module
, "heuristic_rlc_over_udp",
2936 "Try Heuristic RLC over UDP framing",
2937 "When enabled, use heuristic dissector to find RLC frames sent with "
2941 prefs_register_bool_preference(rlc_module
, "perform_reassembly",
2942 "Try to reassemble SDUs",
2943 "When enabled, try to reassemble SDUs from the various PDUs received",
2944 &global_rlc_perform_reassemby
);
2946 prefs_register_bool_preference(rlc_module
, "header_only_mode",
2947 "May see RLC headers only",
2948 "When enabled, if data is not present, don't report as an error, but instead "
2949 "add expert info to indicate that headers were omitted",
2950 &global_rlc_headers_expected
);
2952 prefs_register_bool_preference(rlc_module
, "ciphered_data",
2954 "When enabled, rlc will assume all data is ciphered",
2955 &global_rlc_ciphered
);
2957 prefs_register_bool_preference(rlc_module
, "try_decipher",
2958 "Try to Decipher data",
2959 "When enabled, rlc will try to decipher data. (Experimental)",
2960 &global_rlc_try_decipher
);
2962 prefs_register_enum_preference(rlc_module
, "li_size",
2964 "LI size in bits, either 7 or 15 bit",
2965 &global_rlc_li_size
, li_size_enumvals
, FALSE
);
2967 #ifdef HAVE_UMTS_KASUMI
2968 prefs_register_string_preference(rlc_module
, "kasumi_key",
2969 "KASUMI key", "Key for kasumi 32 characters long hex-string", &global_rlc_kasumi_key
);
2970 #endif /* HAVE_UMTS_KASUMI */
2972 register_init_routine(fragment_table_init
);
2976 proto_reg_handoff_rlc(void)
2978 rrc_handle
= find_dissector("rrc");
2979 ip_handle
= find_dissector("ip");
2980 bmc_handle
= find_dissector("bmc");
2981 /* Add as a heuristic UDP dissector */
2982 heur_dissector_add("udp", dissect_rlc_heur
, proto_rlc
);