HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-rlc.c
blob122e1744a6d84924690100c2e818871b910e203d
1 /* Routines for UMTS RLC (Radio Link Control) v9.3.0 disassembly
2 * http://www.3gpp.org/ftp/Specs/archive/25_series/25.322/
4 * $Id$
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.
25 #include "config.h"
27 #include <string.h>
28 #include <glib.h>
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.
40 * */
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"
48 /* TODO:
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)))
57 int proto_rlc = -1;
59 extern int proto_fp;
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;
79 #endif
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},
89 {NULL, NULL, -1}};
91 /* fields */
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;
131 /* subtrees */
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 {
163 RLC_PCCH,
164 RLC_BCCH,
165 RLC_UL_CCCH,
166 RLC_DL_CCCH,
167 RLC_UL_DCCH,
168 RLC_DL_DCCH,
169 RLC_PS_DTCH,
170 RLC_DL_CTCH,
171 RLC_UNKNOWN_CH
174 static const value_string rlc_dir_vals[] = {
175 { P2P_DIR_UL, "Uplink" },
176 { P2P_DIR_DL, "Downlink" },
177 { 0, NULL }
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 = {
189 "Data", "Control"
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" },
200 { 0, NULL }
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" },
210 { 0, NULL }
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" },
232 { 0, NULL }
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
246 struct rlc_channel {
247 guint32 urnti;
248 guint16 vpi;
249 guint16 vci;
250 guint8 cid;
251 guint16 link; /* link number */
252 guint8 rbid; /* radio bearer ID */
253 guint8 dir; /* direction */
254 enum rlc_li_size li_size;
255 enum rlc_mode mode;
258 /* used for duplicate detection */
259 struct rlc_seq {
260 guint32 frame_num;
261 nstime_t arrival;
262 guint16 seq;
263 guint16 oc; /* overflow counter, this is not used? */
266 struct rlc_seqlist {
267 struct rlc_channel ch;
268 GList *list;
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 */
275 struct rlc_frag {
276 guint32 frame_num;
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 */
286 struct rlc_sdu {
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 */
297 struct rlc_li {
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*/
308 }kasumi_key;
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
318 * rlc_channel -> SDU
320 static guint
321 rlc_channel_hash(gconstpointer key)
323 const struct rlc_channel *ch = (const struct rlc_channel *)key;
325 if (ch->urnti)
326 return ch->urnti | ch->rbid | ch->mode;
328 return (ch->vci << 16) | (ch->link << 16) | ch->vpi | ch->vci;
331 static gboolean
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 &&
343 x->vci == y->vci &&
344 x->cid == y->cid &&
345 x->rbid == y->rbid &&
346 x->mode == y->mode &&
347 x->dir == y->dir &&
348 x->link == y->link ? TRUE : FALSE;
351 static int
352 rlc_channel_assign(struct rlc_channel *ch, enum rlc_mode mode, packet_info *pinfo)
354 struct atm_phdr *atm;
355 rlc_info *rlcinf;
356 fp_info *fpinf;
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;
366 } else {
367 if (!atm) return -1;
368 ch->urnti = 1;
369 ch->vpi = atm->vpi;
370 ch->vci = atm->vci;
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;
376 ch->mode = mode;
377 ch->li_size = rlcinf->li_size[fpinf->cur_tb];
379 return 0;
382 static struct rlc_channel *
383 rlc_channel_create(enum rlc_mode mode, packet_info *pinfo)
385 struct rlc_channel *ch;
386 int rv;
388 ch = (struct rlc_channel *)g_malloc0(sizeof(struct rlc_channel));
389 rv = rlc_channel_assign(ch, mode, pinfo);
391 if (rv != 0) {
392 /* channel assignment failed */
393 g_free(ch);
394 ch = NULL;
395 REPORT_DISSECTOR_BUG("Failed to assign channel");
397 return ch;
400 static void
401 rlc_channel_delete(gpointer data)
403 g_free(data);
406 /* hashtable functions for reassembled table
407 * fragment -> SDU
409 static guint
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;
416 static gboolean
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) &&
423 x->seq == y->seq &&
424 x->frame_num == y->frame_num &&
425 x->li == y->li ? TRUE : FALSE;
428 static struct rlc_sdu *
429 rlc_sdu_create(void)
431 struct rlc_sdu *sdu;
433 sdu = (struct rlc_sdu *)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_sdu));
434 return sdu;
437 static void
438 rlc_frag_delete(gpointer data)
440 struct rlc_frag *frag = (struct rlc_frag *)data;
442 if (frag->data) {
443 g_free(frag->data);
444 frag->data = NULL;
448 static void
449 rlc_sdu_frags_delete(gpointer data)
451 struct rlc_sdu *sdu = (struct rlc_sdu *)data;
452 struct rlc_frag *frag;
454 frag = sdu->frags;
455 while (frag) {
456 if (frag->data) {
457 g_free(frag->data);
459 frag->data = NULL;
460 frag = frag->next;
464 static int
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;
469 frag->seq = seq;
470 frag->li = li;
471 frag->len = 0;
472 frag->data = NULL;
473 rlc_channel_assign(&frag->ch, mode, pinfo);
475 return 0;
478 static int
479 rlc_frag_assign_data(struct rlc_frag *frag, tvbuff_t *tvb,
480 guint16 offset, guint16 length)
482 frag->len = length;
483 frag->data = (guint8 *)g_malloc(length);
484 tvb_memcpy(tvb, frag->data, offset, length);
485 return 0;
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);
498 return frag;
501 static int
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 :
511 static int
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;
517 } else {
518 if (p+2048 < q) {
519 return 1;
520 } else {
521 return -1;
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.
530 static void
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 **/
541 static gint
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) ){
544 return -1;
546 return GPOINTER_TO_INT(a_ptr) < GPOINTER_TO_INT(b_ptr);
549 static void
550 fragment_table_init(void)
552 int i;
553 if (fragment_table) {
554 g_hash_table_destroy(fragment_table);
556 if (endpoints) {
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);
568 if(counter_map){
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;
587 max_counter = 0;
590 /* add the list of fragments for this sdu to 'tree' */
591 static void
592 tree_add_fragment_list(struct rlc_sdu *sdu, tvbuff_t *tvb, proto_tree *tree)
594 proto_item *ti;
595 proto_tree *frag_tree;
596 guint16 offset;
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;
604 offset = 0;
605 while (sdufrag) {
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);
610 } else {
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' */
621 static void
622 tree_add_fragment_list_incomplete(struct rlc_sdu *sdu, tvbuff_t *tvb, proto_tree *tree)
624 proto_item *ti;
625 proto_tree *frag_tree;
626 guint16 offset;
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;
634 offset = 0;
635 while (sdufrag) {
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 */
645 static void
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];
652 va_list ap;
654 va_start(ap, format);
655 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
656 va_end(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' */
663 static proto_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;
668 proto_tree *li_tree;
669 guint8 li_offs;
670 guint64 length;
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);
680 switch (li->li) {
681 case 0x0000:
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");
683 break;
684 case 0x7ffa:
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");
687 } else {
688 add_description(root_ti, ti, "Reserved");
690 break;
691 case 0x7ffb:
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");
693 break;
694 case 0x7ffc:
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");
697 } else {
698 add_description(root_ti, ti, "Reserved");
700 break;
701 case 0x7ffd:
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");
704 } else {
705 add_description(root_ti, ti, "Reserved");
707 break;
708 case 0x7ffe:
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");
711 } else {
712 add_description(root_ti, ti, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
714 break;
715 case 0x7fff:
716 add_description(root_ti, ti, "The rest of the RLC PDU is padding");
717 break;
719 default:
720 add_description(root_ti, ti, "length=%u", (guint16)length);
721 break;
723 proto_tree_add_bits_item(li_tree, hf_rlc_li_ext, tvb, li_offs*8+15, 1, ENC_BIG_ENDIAN);
724 } else {
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);
729 switch (li->li) {
730 case 0x00:
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");
732 break;
733 case 0x7c:
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");
736 } else {
737 add_description(root_ti, ti, "Reserved");
739 break;
740 case 0x7d:
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");
743 } else {
744 add_description(root_ti, ti, "Reserved");
746 break;
747 case 0x7e:
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");
750 } else {
751 add_description(root_ti, ti, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
753 break;
754 case 0x7f:
755 add_description(root_ti, ti, "The rest of the RLC PDU is padding");
756 break;
758 default:
759 add_description(root_ti, ti, "length=%u", (guint16)length);
760 break;
762 proto_tree_add_bits_item(li_tree, hf_rlc_li_ext, tvb, li_offs*8+7, 1, ENC_BIG_ENDIAN);
765 if (li->len > 0) {
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);
772 return li_tree;
775 /* add a fragment to an SDU */
776 static int
777 rlc_sdu_add_fragment(enum rlc_mode mode, struct rlc_sdu *sdu, struct rlc_frag *frag)
779 struct rlc_frag *tmp;
781 if (!sdu->frags) {
782 /* insert as first element */
783 sdu->frags = frag;
784 sdu->last = frag;
785 sdu->fragcnt++;
786 sdu->len += frag->len;
787 return 0;
789 switch (mode) {
790 case RLC_UM:
791 /* insert as last element */
792 sdu->last->next = frag;
793 frag->next = NULL;
794 sdu->last = frag;
795 sdu->len += frag->len;
796 break;
797 case RLC_AM:
798 /* insert ordered */
799 tmp = sdu->frags;
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)
804 tmp = tmp->next;
805 if (tmp->next == NULL) {
806 tmp->next = frag;
807 sdu->last = frag;
808 } else {
809 while (tmp->next && tmp->next->seq < frag->seq)
810 tmp = tmp->next;
811 frag->next = tmp->next;
812 tmp->next = frag;
813 if (frag->next == NULL) sdu->last = frag;
815 } else { /* Receiving ordinary sequence */
816 if (frag->seq < tmp->seq) {
817 /* insert as first element */
818 frag->next = tmp;
819 sdu->frags = frag;
820 } else {
821 while (tmp->next && tmp->next->seq < frag->seq)
822 tmp = tmp->next;
823 frag->next = tmp->next;
824 tmp->next = frag;
825 if (frag->next == NULL) sdu->last = frag;
828 sdu->len += frag->len;
829 break;
830 default:
831 return -2;
833 sdu->fragcnt++;
834 return 0;
837 static void
838 reassemble_data(struct rlc_channel *ch, struct rlc_sdu *sdu, struct rlc_frag *frag)
840 struct rlc_frag *temp;
841 guint16 offs = 0;
843 if (!sdu || !ch || !sdu->frags) return;
845 if (sdu->data) return; /* already assembled */
847 if (frag)
848 sdu->reassembled_in = frag;
849 else
850 sdu->reassembled_in = sdu->last;
852 sdu->data = (guint8 *)wmem_alloc(wmem_file_scope(), sdu->len);
853 temp = sdu->frags;
854 while (temp && ((offs + temp->len) <= sdu->len)) {
855 memcpy(sdu->data + offs, temp->data, temp->len);
856 g_free(temp->data);
857 temp->data = NULL;
858 /* mark this fragment in reassembled table */
859 g_hash_table_insert(reassembled_table, temp, sdu);
861 offs += temp->len;
862 temp = temp->next;
866 #define RLC_ADD_FRAGMENT_FAIL_PRINT 0
867 #define RLC_ADD_FRAGMENT_DEBUG_PRINT 0
868 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
869 static void
870 printends(GList * list)
872 if (list == NULL)
873 return;
874 g_print("-> length: %d\n[", g_list_length(list));
875 while (list)
877 g_print("%d ", GPOINTER_TO_INT(list->data));
878 list = list->next;
880 g_print("]\n");
882 #endif
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);
897 } else {
898 return NULL;
900 return 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);
919 } else {
920 return NULL;
922 return endlist;
925 static void
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);
944 if (element) {
945 endlist->list = g_list_remove_link(endlist->list, element);
946 if (frags[end] != NULL) {
947 if (endlist->list) {
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. */
957 void
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;
963 guint i;
965 ch_lookup.mode = mode;
966 ch_lookup.rbid = rbid;
967 ch_lookup.dir = dir;
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++) {
978 frags[i] = NULL;
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) {
999 return NULL;
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);
1004 #endif
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;
1010 if (tree) {
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);
1017 return frag;
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;
1036 break;
1040 if (wecanreasmmore) {
1041 reassemble_sequence(frags, endlist, &ch_lookup, start, end);
1042 } else {
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);
1046 } else {
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);
1054 } else {
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);
1058 } else {
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);
1062 } else {
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 */
1070 return NULL;
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
1077 * wrong. */
1078 if (frags[seq] != NULL) {
1079 if (num_li > 0) {
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;
1086 return NULL;
1088 } else {
1089 frags[seq] = frag;
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);
1097 if (seq == first) {
1098 endlist->list->data = GINT_TO_POINTER(first-1);
1102 /* If this is an endpoint */
1103 if (final) {
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);
1109 #endif
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);
1118 #endif
1119 endlist->fail_packet = pinfo->fd->num;
1120 return NULL;
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);
1126 if (element) {
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. */
1139 return NULL;
1142 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1143 g_print("start: %d, end: %d\n",start, end);
1144 #endif
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
1151 g_warning(
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);
1155 #endif
1156 endlist->fail_packet = pinfo->fd->num; /* If it has gone too far, give up */
1157 return NULL;
1159 return frag;
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
1170 g_warning(
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);
1173 #endif
1174 endlist->fail_packet = pinfo->fd->num; /* Give up if things have gone too far. */
1175 return NULL;
1179 return frag;
1182 /* is_data is used to identify rlc data parts that are not identified by an LI, but are at the end of
1183 * the RLC frame
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
1187 static tvbuff_t *
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))
1199 return NULL;
1201 sdu = (struct rlc_sdu *)orig_sdu;
1202 if (!sdu || !sdu->data)
1203 return NULL;
1205 /* TODO */
1206 #if 0
1207 if (!rlc_frag_equal(&lookup, sdu->reassembled_in)) return NULL;
1208 #endif
1210 if (tree) {
1211 frag = sdu->frags;
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);
1218 return NULL;
1220 frag = frag->next;
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);
1230 return sdu->tvb;
1233 #define RLC_RETRANSMISSION_TIMEOUT 5 /* in seconds */
1234 static gboolean
1235 rlc_is_duplicate(enum rlc_mode mode, packet_info *pinfo, guint16 seq,
1236 guint32 *original)
1238 GList *element;
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);
1244 if (!list) {
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);
1250 seq_item.seq = seq;
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);
1256 if (element) {
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);
1265 if (element) {
1266 seq_new = (struct rlc_seq *)element->data;
1267 if (seq_new->frame_num != seq_item.frame_num) {
1268 nstime_t delta;
1269 nstime_delta(&delta, &pinfo->fd->abs_ts, &seq_new->arrival);
1270 if (delta.secs < RLC_RETRANSMISSION_TIMEOUT) {
1271 if (original)
1272 *original = seq_new->frame_num;
1273 return TRUE;
1275 return FALSE;
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 */
1283 return FALSE;
1286 static void
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;
1291 switch (channel) {
1292 case RLC_UL_CCCH:
1293 msgtype = RRC_MESSAGE_TYPE_UL_CCCH;
1294 break;
1295 case RLC_DL_CCCH:
1296 msgtype = RRC_MESSAGE_TYPE_DL_CCCH;
1297 break;
1298 case RLC_DL_CTCH:
1299 msgtype = RRC_MESSAGE_TYPE_INVALID;
1300 call_dissector(bmc_handle, tvb, pinfo, tree);
1301 break;
1302 case RLC_UL_DCCH:
1303 msgtype = RRC_MESSAGE_TYPE_UL_DCCH;
1304 break;
1305 case RLC_DL_DCCH:
1306 msgtype = RRC_MESSAGE_TYPE_DL_DCCH;
1307 break;
1308 case RLC_PCCH:
1309 msgtype = RRC_MESSAGE_TYPE_PCCH;
1310 break;
1311 case RLC_BCCH:
1312 msgtype = RRC_MESSAGE_TYPE_BCCH_FACH;
1313 break;
1314 case RLC_PS_DTCH:
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);
1320 break;
1321 default:
1322 return; /* stop dissecting */
1324 if (msgtype != RRC_MESSAGE_TYPE_INVALID) {
1325 struct rrc_info *rrcinf;
1326 fp_info *fpinf;
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);
1329 if (!rrcinf) {
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);
1340 static void
1341 add_channel_info(packet_info * pinfo, proto_tree * tree, fp_info * fpinf, rlc_info * rlcinf)
1343 proto_item * item;
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
1361 static guint8 *
1362 translate_hex_key(gchar * char_key){
1363 int i,j;
1364 guint8 * key_in;
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';
1372 j--;
1374 return key_in;
1377 #endif
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
1395 static tvbuff_t *
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);
1401 return NULL;
1402 #else
1403 rlc_decipher_tvb(tvbuff_t *tvb, packet_info *pinfo, guint32 counter, guint8 rbid, gboolean dir, guint8 header_size) {
1404 guint i;
1405 guint8* out=NULL,*key_in = NULL;
1406 tvbuff_t *t;
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);
1429 /*Create new tvb.*/
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");
1433 return t;
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
1442 static gboolean
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);
1447 return TRUE;
1449 *((guint32*)data) = (guint32)GPOINTER_TO_INT(key);
1451 return TRUE;
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
1460 static gboolean
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] ){
1465 return TRUE;
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];
1471 return FALSE;
1474 static void
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;
1480 gint16 pos;
1482 indx = fpinf->is_uplink ? 1 : 0;
1483 pos = fpinf->cur_tb;
1484 if (mode ==RLC_UM) {
1485 header_size = 1;
1486 hfn_shift = 7;
1487 } else {
1488 header_size = 2;
1489 hfn_shift = 12;
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) )){
1500 tvbuff_t *t;
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;
1516 }else{
1517 ps_counter[rlcinf->rbid[pos]][0] = frame_num << hfn_shift;
1518 ps_counter[rlcinf->rbid[pos]][1] = frame_num << hfn_shift;
1521 if(!tree){
1522 /*Preserve counter value for next dissection round*/
1523 guint32 * ciph;
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 ){
1536 if(tree){
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);
1543 }else{
1544 t = rlc_decipher_tvb(tvb, pinfo, ((ps_counter[rlcinf->rbid[pos]][indx]) | seq),16,!fpinf->is_uplink,header_size);
1546 }else{
1547 if(tree){
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);
1553 }else
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*/
1558 if(seq == 4095){
1560 ps_counter[rlcinf->rbid[pos]][indx] += 1 << hfn_shift;
1562 if(!tree){/*Preserve counter for second packet analysis run*/
1563 guint32 * ciph;
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*/
1572 if(t == NULL){
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]");
1576 return;
1578 }else{
1579 col_append_str(pinfo->cinfo, COL_INFO, "[Deciphered Data]");
1581 /*TODO: Old tvb should be freed here?*/
1586 static void
1587 dissect_rlc_tm(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
1588 proto_tree *top_level, proto_tree *tree)
1590 fp_info *fpinf;
1591 rlc_info *rlcinf;
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);
1596 if (tree) {
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);
1607 static void
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)
1612 guint8 i;
1613 gboolean dissected = FALSE;
1614 gint length;
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 */
1621 if (tree) {
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);
1631 if (length > 1) {
1632 length--;
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);
1640 offs += length;
1642 if (tree) {
1643 proto_tree_add_item(tree, hf_rlc_pad, tvb, offs, 1, ENC_NA);
1645 offs += 1;
1646 } else {
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);
1655 if (next_tvb) {
1656 dissected = TRUE;
1657 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
1658 next_tvb = NULL;
1660 offs += li[i].len;
1663 /* is there data left? */
1664 if (tvb_length_remaining(tvb, offs) > 0) {
1665 if (tree) {
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);
1677 else
1678 if (channel == RLC_UNKNOWN_CH)
1679 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Data] SN=%u", seq);
1682 static gint16
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;
1689 guint16 total_len;
1691 switch (mode) {
1692 case RLC_AM:
1693 offs = 1;
1694 break;
1695 case RLC_UM:
1696 offs = 0;
1697 break;
1698 case RLC_TM:
1699 /* fall trough */
1700 case RLC_UNKNOWN_MODE:
1701 default:
1702 return -1;
1704 hdr_len = offs;
1705 /* calculate header length */
1706 ext = tvb_get_guint8(tvb, hdr_len++) & 0x01;
1707 while (ext) {
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;
1716 li_offs = offs;
1717 while (ext) {
1718 if (li_on_2_bytes) {
1719 next_bytes = tvb_get_ntohs(tvb, offs);
1720 offs += 2;
1721 } else {
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 */
1734 li[num_li].len = 0;
1735 break;
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) {
1740 /* valid for UM */
1741 li[num_li].len = 0;
1742 break;
1744 /*invalid for AM */
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 */
1749 default:
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;
1764 } else {
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 */
1769 li[num_li].len = 0;
1770 break;
1771 case 0x7c: /* start of a new SDU, UM only */
1772 case 0x7d: /* contains exactly one SDU, UM only */
1773 if (mode == RLC_UM) {
1774 /* valid for UM */
1775 li[num_li].len = 0;
1776 break;
1778 /*invalid for AM */
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 */
1783 default:
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);
1800 num_li++;
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);
1806 return -1;
1809 return num_li;
1812 static void
1813 dissect_rlc_um(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
1814 proto_tree *top_level, proto_tree *tree)
1816 #define MAX_LI 16
1817 struct rlc_li li[MAX_LI];
1818 fp_info *fpinf;
1819 rlc_info *rlcinf;
1820 guint32 orig_num;
1821 guint8 seq;
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);
1833 if (tree) {
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");
1846 return;
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);
1854 }else{
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]");
1858 return;
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;
1865 } else {
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,
1882 is_truncated);
1883 if (is_truncated) {
1884 PROTO_ITEM_SET_GENERATED(truncated_ti);
1885 expert_add_info(pinfo, truncated_ti, &ei_rlc_header_only);
1886 return;
1887 } else {
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);
1898 return;
1900 rlc_um_reassemble(tvb, offs, pinfo, tree, top_level, channel, seq, li, num_li, li_is_on_2_bytes);
1903 static void
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;
1911 guint i, j;
1912 proto_tree *sufi_tree, *bitmap_tree, *rlist_tree;
1913 proto_item *sufi_item, *ti;
1914 #define BUFF_SIZE 41
1915 gchar *buff = NULL;
1916 guint8 cw[15];
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) {
1924 /* SUFI */
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"));
1931 bit_offset += 4;
1932 switch (sufi_type) {
1933 case RLC_SUFI_NOMORE:
1934 seen_last = TRUE;
1935 break;
1936 case RLC_SUFI_ACK:
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);
1940 bit_offset += 12;
1941 seen_last = TRUE;
1942 break;
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);
1946 bit_offset += 12;
1947 break;
1948 case RLC_SUFI_LIST:
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);
1951 bit_offset += 4;
1952 if (len) {
1953 while (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)");
1956 bit_offset += 12;
1957 ti = proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_l, tvb, bit_offset, 4, &l, ENC_BIG_ENDIAN);
1958 if (l) {
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);
1963 else {
1964 col_append_fstr(pinfo->cinfo, COL_INFO, "%u ", (guint16)sn);
1966 bit_offset += 4;
1967 len--;
1969 } else {
1970 expert_add_info(pinfo, tree, &ei_rlc_sufi_len);
1972 break;
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);
1975 bit_offset += 4;
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);
1978 bit_offset += 12;
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++;
1992 } else {
1993 j += g_snprintf(&buff[j], BUFF_SIZE-j, " ,");
1996 proto_tree_add_text(bitmap_tree, tvb, bit_offset/8, 1, "%s", buff);
1997 bit_offset += 8;
1999 proto_item_append_text(ti, " (%u SNs)", number_of_bitmap_entries);
2000 col_append_str(pinfo->cinfo, COL_INFO, " )");
2001 break;
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);
2005 bit_offset += 4;
2006 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_fsn, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2007 bit_offset += 12;
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);
2012 if (l == 0x01) {
2013 proto_item_append_text(ti, " (Error burst indication)");
2015 bit_offset += 4;
2016 cw[i] = (guint8)l;
2018 if (len && (((cw[len-1] & 0x01) == 0) || (cw[len-1] == 0x01))) {
2019 expert_add_info(pinfo, tree, &ei_rlc_sufi_cw);
2020 } else {
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;
2030 } else {
2031 value |= (cw[i] >> 1) << j;
2032 j += 3;
2033 if (cw[i] & 0x01) {
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);
2037 if (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;
2042 } else {
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;
2048 value = j = 0;
2052 col_append_str(pinfo->cinfo, COL_INFO, ")");
2054 break;
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);
2058 bit_offset += 4;
2059 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_sn_ack, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2060 bit_offset += 12;
2061 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u", (guint16)sn);
2062 break;
2063 case RLC_SUFI_MRW:
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);
2066 bit_offset += 4;
2067 if (len) {
2068 while (len) {
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);
2071 bit_offset += 12;
2072 len--;
2074 } else {
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)");
2078 bit_offset += 12;
2080 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_n, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
2081 bit_offset += 4;
2082 break;
2083 case RLC_SUFI_POLL:
2084 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_poll_sn, tvb, bit_offset, 12, ENC_BIG_ENDIAN);
2085 bit_offset += 12;
2086 break;
2088 default:
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);
2098 static void
2099 dissect_rlc_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2101 guint8 type, next_byte;
2102 proto_item *ti;
2103 guint64 r1;
2104 guint64 rsn, hfn;
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);
2110 switch (type) {
2111 case RLC_STATUS:
2112 dissect_rlc_status(tvb, pinfo, tree, 0);
2113 break;
2114 case RLC_RESET:
2115 case RLC_RESET_ACK:
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);
2119 if (r1) {
2120 expert_add_info(pinfo, ti, &ei_rlc_reserved_bits_not_zero);
2121 return;
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);
2125 break;
2126 default:
2127 expert_add_info(pinfo, ti, &ei_rlc_ctrl_type);
2128 return; /* invalid */
2132 static void
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)
2138 guint8 i;
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 */
2146 piggyback = TRUE;
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) {
2150 if (tree) {
2151 proto_tree_add_item(tree, hf_rlc_pad, tvb, offs, -1, ENC_NA);
2153 if (i == 0) {
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);
2159 } else {
2160 if (tree) {
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);
2168 if (next_tvb) {
2169 dissected = TRUE;
2170 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
2171 next_tvb = NULL;
2173 offs += li[i].len;
2176 if (piggyback) {
2177 dissect_rlc_status(tvb, pinfo, tree, offs);
2178 } else {
2179 if (tvb_length_remaining(tvb, offs) > 0) {
2180 /* we have remaining data, which we need to mark in the tree */
2181 if (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);
2187 if (final) {
2188 next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, tree, seq, i);
2192 if (next_tvb) {
2193 dissected = TRUE;
2194 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
2195 next_tvb = NULL;
2198 if (dissected == FALSE)
2199 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] SN=%u %s",
2200 seq, poll_set ? "(P)" : "");
2201 else
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)" : "");
2207 static void
2208 dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
2209 proto_tree *top_level, proto_tree *tree)
2211 #define MAX_LI 16
2212 struct rlc_li li[MAX_LI];
2213 fp_info *fpinf;
2214 rlc_info *rlcinf;
2215 guint8 ext, dc;
2216 guint8 next_byte, offs = 0;
2217 guint32 orig_num = 0;
2218 gint16 num_li = 0, pos;
2219 guint16 seq;
2220 gboolean is_truncated, li_is_on_2_bytes;
2221 proto_item *truncated_ti, *ti;
2222 guint64 polling;
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;
2229 if (tree) {
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);
2236 if (dc == 0) {
2237 col_set_str(pinfo->cinfo, COL_INFO, "[RLC Control Frame]");
2238 dissect_rlc_control(tvb, pinfo, tree);
2239 return;
2242 seq = next_byte & 0x7f;
2243 seq <<= 5;
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 */
2254 if (ext > 2) {
2255 expert_add_info(pinfo, ti, &ei_rlc_he);
2256 return;
2259 if (!fpinf || !rlcinf) {
2260 proto_tree_add_text(tree, tvb, 0, -1,
2261 "Cannot dissect RLC frame because per-frame info is missing");
2262 return;
2265 pos = fpinf->cur_tb;
2268 * WARNING DECIPHERING IS HIGHLY EXPERIMENTAL!!!
2269 * */
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);
2273 }else{
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]");
2277 return;
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;
2284 } else {
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,
2298 is_truncated);
2299 if (is_truncated) {
2300 PROTO_ITEM_SET_GENERATED(truncated_ti);
2301 expert_add_info(pinfo, truncated_ti, &ei_rlc_header_only);
2302 return;
2303 } else {
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));
2313 return;
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));
2319 return;
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 */
2328 static void
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 */
2337 if (tree) {
2338 proto_item *ti;
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);
2346 static void
2347 dissect_rlc_bcch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2349 fp_info *fpi;
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 */
2359 if (tree) {
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);
2367 static void
2368 dissect_rlc_ccch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2370 fp_info *fpi;
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 */
2380 if (tree) {
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);
2389 } else {
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);
2396 static void
2397 dissect_rlc_ctch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2399 fp_info *fpi;
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 */
2410 if (tree) {
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);
2420 static void
2421 dissect_rlc_dcch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2423 proto_item *ti = NULL;
2424 proto_tree *subtree = NULL;
2425 fp_info *fpi;
2426 rlc_info *rlci;
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);
2435 if (!fpi || !rlci){
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);
2439 return;
2442 if (tree) {
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]) {
2450 case RLC_UM:
2451 proto_item_append_text(ti, " UM (DCCH)");
2452 dissect_rlc_um(channel, tvb, pinfo, tree, subtree);
2453 break;
2454 case RLC_AM:
2455 proto_item_append_text(ti, " AM (DCCH)");
2456 dissect_rlc_am(channel, tvb, pinfo, tree, subtree);
2457 break;
2461 static void
2462 dissect_rlc_ps_dtch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2464 proto_item *ti = NULL;
2465 proto_tree *subtree = NULL;
2466 fp_info *fpi;
2467 rlc_info *rlci;
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);
2479 return;
2482 if (tree) {
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]) {
2488 case RLC_UM:
2489 proto_item_append_text(ti, " UM (PS DTCH)");
2490 dissect_rlc_um(RLC_PS_DTCH, tvb, pinfo, tree, subtree);
2491 break;
2492 case RLC_AM:
2493 proto_item_append_text(ti, " AM (PS DTCH)");
2494 dissect_rlc_am(RLC_PS_DTCH, tvb, pinfo, tree, subtree);
2495 break;
2496 case RLC_TM:
2497 proto_item_append_text(ti, " TM (PS DTCH)");
2498 dissect_rlc_tm(RLC_PS_DTCH, tvb, pinfo, tree, subtree);
2499 break;
2503 static void
2504 dissect_rlc_dch_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2506 proto_item *ti = NULL;
2507 proto_tree *subtree = NULL;
2508 fp_info *fpi;
2509 rlc_info *rlci;
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;
2519 if (tree) {
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]) {
2525 case RLC_UM:
2526 proto_item_append_text(ti, " UM (Unknown)");
2527 dissect_rlc_um(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree);
2528 break;
2529 case RLC_AM:
2530 proto_item_append_text(ti, " AM (Unknown)");
2531 dissect_rlc_am(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree);
2532 break;
2533 case RLC_TM:
2534 proto_item_append_text(ti, " TM (Unknown)");
2535 dissect_rlc_tm(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree);
2536 break;
2541 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2542 static gboolean
2543 dissect_rlc_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2545 gint offset = 0;
2546 fp_info *fpi;
2547 rlc_info *rlci;
2548 tvbuff_t *rlc_tvb;
2549 guint8 tag = 0;
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) {
2563 return FALSE;
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
2571 - tag for data
2572 - at least one byte of RLC PDU payload */
2573 if (tvb_length_remaining(tvb, offset) < (gint)(strlen(RLC_START_STRING)+2+2)) {
2574 return FALSE;
2577 /* OK, compare with signature string */
2578 if (tvb_strneql(tvb, offset, RLC_START_STRING, (gint)strlen(RLC_START_STRING)) != 0) {
2579 return FALSE;
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);
2585 if (fpi == NULL) {
2586 /* Allocate new info struct for this frame */
2587 fpi = (fp_info *)wmem_alloc0(wmem_file_scope(), sizeof(fp_info));
2588 } else {
2589 fpInfoAlreadySet = TRUE;
2591 rlci = (rlc_info *)p_get_proto_data(pinfo->fd, proto_rlc, 0);
2592 if (rlci == NULL) {
2593 /* Allocate new info struct for this frame */
2594 rlci = (rlc_info *)wmem_alloc0(wmem_file_scope(), sizeof(rlc_info));
2595 } else {
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++);
2603 switch (tag) {
2604 case RLC_CHANNEL_TYPE_TAG:
2605 channelType = tvb_get_guint8(tvb, offset);
2606 offset++;
2607 channelTypePresent = TRUE;
2608 break;
2609 case RLC_MODE_TAG:
2610 rlci->mode[fpi->cur_tb] = tvb_get_guint8(tvb, offset);
2611 offset++;
2612 rlcModePresent = TRUE;
2613 break;
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;
2618 } else {
2619 fpi->is_uplink = FALSE;
2620 pinfo->p2p_dir = P2P_DIR_DL;
2622 offset++;
2623 break;
2624 case RLC_URNTI_TAG:
2625 rlci->urnti[fpi->cur_tb] = tvb_get_ntohl(tvb, offset);
2626 offset += 4;
2627 break;
2628 case RLC_RADIO_BEARER_ID_TAG:
2629 rlci->rbid[fpi->cur_tb] = tvb_get_guint8(tvb, offset);
2630 offset++;
2631 break;
2632 case RLC_LI_SIZE_TAG:
2633 rlci->li_size[fpi->cur_tb] = (enum rlc_li_size) tvb_get_guint8(tvb, offset);
2634 offset++;
2635 break;
2636 case RLC_PAYLOAD_TAG:
2637 /* Have reached data, so get out of loop */
2638 continue;
2639 default:
2640 /* It must be a recognised tag */
2641 return FALSE;
2645 if ((channelTypePresent == FALSE) && (rlcModePresent == FALSE)) {
2646 /* Conditional fields are missing */
2647 return FALSE;
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);
2669 if (tree) {
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);
2680 } else {
2681 proto_item_append_text(ti, " TM");
2682 dissect_rlc_tm(RLC_UNKNOWN_CH, rlc_tvb, pinfo, tree, subtree);
2684 break;
2685 case UMTS_CHANNEL_TYPE_PCCH:
2686 dissect_rlc_pcch(rlc_tvb, pinfo, tree);
2687 break;
2688 case UMTS_CHANNEL_TYPE_CCCH:
2689 dissect_rlc_ccch(rlc_tvb, pinfo, tree);
2690 break;
2691 case UMTS_CHANNEL_TYPE_DCCH:
2692 dissect_rlc_dcch(rlc_tvb, pinfo, tree);
2693 break;
2694 case UMTS_CHANNEL_TYPE_PS_DTCH:
2695 dissect_rlc_ps_dtch(rlc_tvb, pinfo, tree);
2696 break;
2697 case UMTS_CHANNEL_TYPE_CTCH:
2698 dissect_rlc_ctch(rlc_tvb, pinfo, tree);
2699 break;
2700 case UMTS_CHANNEL_TYPE_BCCH:
2701 dissect_rlc_bcch(rlc_tvb, pinfo, tree);
2702 break;
2703 default:
2704 /* Unknown channel type */
2705 return FALSE;
2708 return TRUE;
2711 gboolean
2712 rlc_is_ciphered(packet_info * pinfo){
2713 fp_info *fpinf;
2714 rlc_info *rlcinf;
2716 if (!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);
2727 void
2728 proto_register_rlc(void)
2730 module_t *rlc_module;
2731 expert_module_t* expert_rlc;
2732 static hf_register_info hf[] = {
2733 { &hf_rlc_dc,
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 }
2741 { &hf_rlc_r1,
2742 { "Reserved 1", "rlc.r1",
2743 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2745 { &hf_rlc_rsn,
2746 { "Reset Sequence Number", "rlc.rsn",
2747 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2749 { &hf_rlc_hfni,
2750 { "Hyper Frame Number Indicator", "rlc.hfni",
2751 FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL }
2753 { &hf_rlc_seq,
2754 { "Sequence Number", "rlc.seq",
2755 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2757 { &hf_rlc_ext,
2758 { "Extension Bit", "rlc.ext",
2759 FT_BOOLEAN, BASE_NONE, TFS(&rlc_ext_val), 0, NULL, HFILL }
2761 { &hf_rlc_he,
2762 { "Header Extension Type", "rlc.he",
2763 FT_UINT8, BASE_DEC, VALS(rlc_he_vals), 0, NULL, HFILL }
2765 { &hf_rlc_p,
2766 { "Polling Bit", "rlc.p",
2767 FT_BOOLEAN, BASE_NONE, TFS(&rlc_p_val), 0, NULL, HFILL }
2769 { &hf_rlc_pad,
2770 { "Padding", "rlc.padding",
2771 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2773 { &hf_rlc_frags,
2774 { "Reassembled Fragments", "rlc.fragments",
2775 FT_NONE, BASE_NONE, NULL, 0, "Fragments", HFILL }
2777 { &hf_rlc_frag,
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 }
2789 { &hf_rlc_data,
2790 { "Data", "rlc.data",
2791 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2793 /* LI information */
2794 { &hf_rlc_li,
2795 { "LI", "rlc.li",
2796 FT_NONE, BASE_NONE, NULL, 0, "Length Indicator", HFILL }
2798 { &hf_rlc_li_value,
2799 { "LI value", "rlc.li.value",
2800 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2802 { &hf_rlc_li_ext,
2803 { "LI extension bit", "rlc.li.ext",
2804 FT_BOOLEAN, BASE_NONE, TFS(&rlc_ext_val), 0, NULL, HFILL }
2806 { &hf_rlc_li_data,
2807 { "LI Data", "rlc.li.data",
2808 FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
2810 /* SUFI information */
2811 { &hf_rlc_sufi,
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 }
2819 { &hf_rlc_sufi_lsn,
2820 { "Last Sequence Number", "rlc.sufi.lsn",
2821 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2823 { &hf_rlc_sufi_wsn,
2824 { "Window Size Number", "rlc.sufi.wsn",
2825 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2827 { &hf_rlc_sufi_sn,
2828 { "Sequence Number", "rlc.sufi.sn",
2829 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2831 { &hf_rlc_sufi_l,
2832 { "Length", "rlc.sufi.l",
2833 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2835 { &hf_rlc_sufi_len,
2836 { "Length", "rlc.sufi.len",
2837 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2839 { &hf_rlc_sufi_fsn,
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 }
2847 { &hf_rlc_sufi_cw,
2848 { "Codeword", "rlc.sufi.cw",
2849 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2851 { &hf_rlc_sufi_n,
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 }
2872 { &hf_rlc_channel,
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[] = {
2890 &ett_rlc,
2891 &ett_rlc_frag,
2892 &ett_rlc_fragments,
2893 &ett_rlc_sdu,
2894 &ett_rlc_sufi,
2895 &ett_rlc_bitmap,
2896 &ett_rlc_rlist,
2897 &ett_rlc_channel
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));
2932 /* Preferences */
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 "
2938 "UDP framing",
2939 &global_rlc_heur);
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",
2953 "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",
2963 "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);
2975 void
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);