Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-umts_rlc.c
blobb3e2a3940041489dc87762b032f3f8279bdf852d
1 /* packet-umts_rlc.c
2 * Routines for UMTS RLC (Radio Link Control) v9.3.0 disassembly
3 * http://www.3gpp.org/ftp/Specs/archive/25_series/25.322/
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <epan/conversation.h>
15 #include <epan/exceptions.h>
16 #include <epan/expert.h>
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
19 #include <epan/proto_data.h>
20 #include <epan/show_exception.h>
21 #include <epan/tfs.h>
22 #include <wsutil/array.h>
24 #include <wiretap/wtap.h>
27 * Optional include, for KASUMI support,
28 * see header file for more information.
29 * */
31 #include "packet-umts_fp.h"
32 #include "packet-umts_rlc.h"
33 #include "packet-rrc.h"
35 /* TODO:
36 * - distinguish between startpoints and endpoints?
37 * - use sub_num in fragment identification?
40 void proto_register_rlc(void);
41 void proto_reg_handoff_rlc(void);
43 int proto_umts_rlc;
45 extern int proto_fp;
47 /* Preference to perform reassembly */
48 static bool global_rlc_perform_reassemby = true;
50 /* Preference to expect RLC headers without payloads */
51 static bool global_rlc_headers_expected;
53 /* Preference to expect ONLY ciphered data */
54 static bool global_rlc_ciphered;
56 /* Preference to ignore ciphering state reported from RRC */
57 /* This is important for captures with deciphered traffic AND the original security RRC messages present*/
58 static bool global_ignore_rrc_ciphering_indication;
60 /* Preference to try deciphering */
61 static bool global_rlc_try_decipher;
63 #ifdef HAVE_UMTS_KASUMI
64 static const char *global_rlc_kasumi_key;
65 #endif
67 /* LI size preference */
68 #define RLC_LI_UPPERLAYER 255 /* LI-size comes from rlc_info struct rather than preference */
69 static int global_rlc_li_size = RLC_LI_UPPERLAYER;
71 static const enum_val_t li_size_enumvals[] = {
72 {"7", "7 bits", RLC_LI_7BITS},
73 {"15", "15 bits", RLC_LI_15BITS},
74 {"per_upper_layer", "Let upper layers decide", RLC_LI_UPPERLAYER},
75 {NULL, NULL, -1}};
77 /* fields */
78 static int hf_rlc_seq;
79 static int hf_rlc_ext;
80 static int hf_rlc_pad;
81 static int hf_rlc_reassembled_data;
82 static int hf_rlc_frags;
83 static int hf_rlc_frag;
84 static int hf_rlc_duplicate_of;
85 static int hf_rlc_reassembled_in;
86 static int hf_rlc_he;
87 static int hf_rlc_dc;
88 static int hf_rlc_p;
89 static int hf_rlc_li;
90 static int hf_rlc_li_value;
91 static int hf_rlc_li_ext;
92 static int hf_rlc_li_data;
93 static int hf_rlc_data;
94 static int hf_rlc_ciphered_data;
95 static int hf_rlc_ciphered_lis_data;
96 static int hf_rlc_ctrl_type;
97 static int hf_rlc_r1;
98 static int hf_rlc_rsn;
99 static int hf_rlc_hfni;
100 static int hf_rlc_sufi;
101 static int hf_rlc_sufi_type;
102 static int hf_rlc_sufi_lsn;
103 static int hf_rlc_sufi_wsn;
104 static int hf_rlc_sufi_sn;
105 static int hf_rlc_sufi_l;
106 static int hf_rlc_sufi_fsn;
107 static int hf_rlc_sufi_len;
108 static int hf_rlc_sufi_bitmap;
109 static int hf_rlc_sufi_cw;
110 static int hf_rlc_sufi_n;
111 static int hf_rlc_sufi_sn_ack;
112 static int hf_rlc_sufi_sn_mrw;
113 static int hf_rlc_sufi_poll_sn;
114 static int hf_rlc_header_only;
115 static int hf_rlc_channel;
116 static int hf_rlc_channel_rbid;
117 static int hf_rlc_channel_dir;
118 static int hf_rlc_channel_ueid;
119 static int hf_rlc_sequence_number;
120 static int hf_rlc_length;
121 static int hf_rlc_bitmap_string;
123 /* subtrees */
124 static int ett_rlc;
125 static int ett_rlc_frag;
126 static int ett_rlc_fragments;
127 static int ett_rlc_sdu;
128 static int ett_rlc_sufi;
129 static int ett_rlc_bitmap;
130 static int ett_rlc_rlist;
131 static int ett_rlc_channel;
133 static expert_field ei_rlc_li_reserved;
134 static expert_field ei_rlc_he;
135 static expert_field ei_rlc_li_incorrect_mal;
136 static expert_field ei_rlc_sufi_cw;
137 static expert_field ei_rlc_kasumi_implementation_missing;
138 static expert_field ei_rlc_reassembly_unknown_error;
139 static expert_field ei_rlc_reassembly_lingering_endpoint;
140 static expert_field ei_rlc_sufi_len;
141 static expert_field ei_rlc_reassembly_fail_unfinished_sequence;
142 static expert_field ei_rlc_reassembly_fail_flag_set;
143 static expert_field ei_rlc_sufi_type;
144 static expert_field ei_rlc_reserved_bits_not_zero;
145 static expert_field ei_rlc_ctrl_type;
146 static expert_field ei_rlc_li_incorrect_warn;
147 static expert_field ei_rlc_li_too_many;
148 static expert_field ei_rlc_header_only;
149 static expert_field ei_rlc_ciphered_data;
150 static expert_field ei_rlc_no_per_frame_data;
151 static expert_field ei_rlc_incomplete_sequence;
152 static expert_field ei_rlc_unknown_udp_framing_tag;
153 static expert_field ei_rlc_missing_udp_framing_tag;
155 static dissector_handle_t ip_handle;
156 static dissector_handle_t rrc_handle;
157 static dissector_handle_t bmc_handle;
159 enum rlc_channel_type {
160 RLC_PCCH,
161 RLC_BCCH,
162 RLC_UL_CCCH,
163 RLC_DL_CCCH,
164 RLC_UL_DCCH,
165 RLC_DL_DCCH,
166 RLC_PS_DTCH,
167 RLC_DL_CTCH,
168 RLC_UNKNOWN_CH
171 static const value_string rlc_dir_vals[] = {
172 { P2P_DIR_UL, "Uplink" },
173 { P2P_DIR_DL, "Downlink" },
174 { 0, NULL }
177 static const true_false_string rlc_header_only_val = {
178 "RLC PDU header only", "RLC PDU header and body present"
181 static const true_false_string rlc_ext_val = {
182 "Next field is Length Indicator and E Bit", "Next field is data, piggybacked STATUS PDU or padding"
185 static const true_false_string rlc_dc_val = {
186 "Data", "Control"
189 static const true_false_string rlc_p_val = {
190 "Request a status report", "Status report not requested"
193 static const value_string rlc_he_vals[] = {
194 { 0, "The succeeding octet contains data" },
195 { 1, "The succeeding octet contains a length indicator and E bit" },
196 { 2, "The succeeding octet contains data and the last octet of the PDU is the last octet of an SDU" },
197 { 0, NULL }
200 #define RLC_STATUS 0x0
201 #define RLC_RESET 0x1
202 #define RLC_RESET_ACK 0x2
203 static const value_string rlc_ctrl_vals[] = {
204 { RLC_STATUS, "Status" },
205 { RLC_RESET, "Reset" },
206 { RLC_RESET_ACK, "Reset Ack" },
207 { 0, NULL }
210 #define RLC_SUFI_NOMORE 0x0
211 #define RLC_SUFI_WINDOW 0x1
212 #define RLC_SUFI_ACK 0x2
213 #define RLC_SUFI_LIST 0x3
214 #define RLC_SUFI_BITMAP 0x4
215 #define RLC_SUFI_RLIST 0x5
216 #define RLC_SUFI_MRW 0x6
217 #define RLC_SUFI_MRW_ACK 0x7
218 #define RLC_SUFI_POLL 0x8
219 static const value_string rlc_sufi_vals[] = {
220 { RLC_SUFI_NOMORE, "No more data" },
221 { RLC_SUFI_WINDOW, "Window size" },
222 { RLC_SUFI_ACK, "Acknowledgement" },
223 { RLC_SUFI_LIST, "List" },
224 { RLC_SUFI_BITMAP, "Bitmap" },
225 { RLC_SUFI_RLIST, "Relative list" },
226 { RLC_SUFI_MRW, "Move receiving window" },
227 { RLC_SUFI_MRW_ACK, "Move receiving window acknowledgement" },
228 { RLC_SUFI_POLL, "Poll" },
229 { 0, NULL }
232 /* reassembly related data */
233 static GHashTable *fragment_table; /* table of not yet assembled fragments */
234 static GHashTable *endpoints; /* List of SDU-endpoints */
235 static GHashTable *reassembled_table; /* maps fragment -> complete sdu */
236 static GHashTable *sequence_table; /* channel -> seq */
237 static GHashTable *duplicate_table; /* duplicates */
239 /* identify an RLC channel, using one of two options:
240 * - via Radio Bearer ID and unique UE ID
241 * - via Radio Bearer ID and (VPI/VCI/CID) + Link ID
243 struct rlc_channel {
244 uint32_t ueid;
245 uint16_t vpi;
246 uint16_t vci;
247 uint8_t cid;
248 uint16_t link; /* link number */
249 uint8_t rbid; /* radio bearer ID */
250 uint8_t dir; /* direction */
251 enum rlc_li_size li_size;
252 enum rlc_mode mode;
255 /* used for duplicate detection */
256 struct rlc_seq {
257 uint32_t frame_num;
258 nstime_t arrival;
259 uint16_t seq;
260 uint16_t oc; /* overflow counter, this is not used? */
263 struct rlc_seqlist {
264 struct rlc_channel ch;
265 GList *list;
266 /* We will store one seqlist per channel so this is a good place to indicate
267 * whether or not this channel's reassembly has failed or not. */
268 unsigned fail_packet; /* Equal to packet where fail flag was set or 0 otherwise. */
271 /* fragment representation */
272 struct rlc_frag {
273 uint32_t frame_num;
274 struct rlc_channel ch;
275 uint16_t seq; /* RLC sequence number */
276 uint16_t li; /* LI within current RLC frame */
277 uint16_t len; /* length of fragment data */
278 uint8_t *data; /* store fragment data here */
280 struct rlc_frag *next; /* next fragment */
283 struct rlc_sdu {
284 tvbuff_t *tvb; /* contains reassembled tvb */
285 uint16_t len; /* total length of reassembled SDU */
286 uint16_t fragcnt; /* number of fragments within this SDU */
287 uint8_t *data; /* reassembled data buffer */
289 struct rlc_frag *reassembled_in;
290 struct rlc_frag *frags; /* pointer to list of fragments */
291 struct rlc_frag *last; /* pointer to last fragment */
294 struct rlc_li {
295 uint16_t li; /* original li */
296 uint16_t len; /* length of this data fragment */
297 uint8_t ext; /* extension bit value */
298 proto_tree *tree; /* subtree for this LI */
301 /*** KASUMI related variables and structs ***/
302 typedef struct umts_kat_key{ /*Stores 128-bits KASUMI key*/
303 uint64_t high; /*64 MSB*/
304 uint64_t low; /*64 LSB*/
305 }kasumi_key;
308 /*Counter used as input for confidentiality algorithm*/
309 static uint32_t ps_counter[31][2] ;
310 static bool counter_init[31][2];
311 static uint32_t max_counter;
312 static GTree * counter_map; /*Saves the countervalues at first pass through, since they will be update*/
314 /* hashtable functions for fragment table
315 * rlc_channel -> SDU
317 static unsigned
318 rlc_channel_hash(const void *key)
320 const struct rlc_channel *ch = (const struct rlc_channel *)key;
322 if (ch->ueid)
323 return ch->ueid | ch->rbid | ch->mode;
325 return (ch->vci << 16) | (ch->link << 16) | ch->vpi | ch->vci;
328 static gboolean
329 rlc_channel_equal(const void *a, const void *b)
331 const struct rlc_channel *x = (const struct rlc_channel *)a, *y = (const struct rlc_channel *)b;
333 if (x->ueid || y->ueid)
334 return x->ueid == y->ueid &&
335 x->rbid == y->rbid &&
336 x->mode == y->mode &&
337 x->dir == y->dir ? true : false;
339 return x->vpi == y->vpi &&
340 x->vci == y->vci &&
341 x->cid == y->cid &&
342 x->rbid == y->rbid &&
343 x->mode == y->mode &&
344 x->dir == y->dir &&
345 x->link == y->link ? true : false;
348 static int
349 rlc_channel_assign(struct rlc_channel *ch, enum rlc_mode mode, packet_info *pinfo, struct atm_phdr *atm)
351 rlc_info *rlcinf;
352 fp_info *fpinf;
354 fpinf = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
355 rlcinf = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
356 if (!fpinf || !rlcinf) return -1;
358 if (rlcinf->ueid[fpinf->cur_tb]) {
359 ch->ueid = rlcinf->ueid[fpinf->cur_tb];
360 ch->vpi = ch->vci = ch->link = ch->cid = 0;
361 } else {
362 if (!atm) return -1;
363 ch->ueid = 1;
364 ch->vpi = atm->vpi;
365 ch->vci = atm->vci;
366 ch->cid = atm->aal2_cid;
367 ch->link = pinfo->link_number;
369 ch->rbid = rlcinf->rbid[fpinf->cur_tb];
370 ch->dir = pinfo->link_dir;
371 ch->mode = mode;
372 ch->li_size = rlcinf->li_size[fpinf->cur_tb];
374 return 0;
377 static struct rlc_channel *
378 rlc_channel_create(enum rlc_mode mode, packet_info *pinfo, struct atm_phdr *atm)
380 struct rlc_channel *ch;
381 int rv;
383 ch = g_new0(struct rlc_channel, 1);
384 rv = rlc_channel_assign(ch, mode, pinfo, atm);
386 if (rv != 0) {
387 /* channel assignment failed */
388 g_free(ch);
389 ch = NULL;
390 REPORT_DISSECTOR_BUG("Failed to assign channel");
392 return ch;
395 static void
396 rlc_channel_delete(void *data)
398 g_free(data);
401 /* hashtable functions for reassembled table
402 * fragment -> SDU
404 static unsigned
405 rlc_frag_hash(const void *key)
407 const struct rlc_frag *frag = (const struct rlc_frag *)key;
408 return (frag->frame_num << 12) | frag->seq;
411 static gboolean
412 rlc_frag_equal(const void *a, const void *b)
414 const struct rlc_frag *x = (const struct rlc_frag *)a;
415 const struct rlc_frag *y = (const struct rlc_frag *)b;
417 return rlc_channel_equal(&x->ch, &y->ch) &&
418 x->seq == y->seq &&
419 x->frame_num == y->frame_num &&
420 x->li == y->li ? true : false;
423 static struct rlc_sdu *
424 rlc_sdu_create(void)
426 struct rlc_sdu *sdu;
428 sdu = wmem_new0(wmem_file_scope(), struct rlc_sdu);
429 return sdu;
432 static void
433 rlc_frag_delete(void *data)
435 struct rlc_frag *frag = (struct rlc_frag *)data;
437 if (frag->data) {
438 wmem_free(wmem_file_scope(), frag->data);
439 frag->data = NULL;
443 static void
444 rlc_sdu_frags_delete(void *data)
446 struct rlc_sdu *sdu = (struct rlc_sdu *)data;
447 struct rlc_frag *frag;
449 frag = sdu->frags;
450 while (frag) {
451 if (frag->data) {
452 wmem_free(wmem_file_scope(), frag->data);
454 frag->data = NULL;
455 frag = frag->next;
459 static int
460 rlc_frag_assign(struct rlc_frag *frag, enum rlc_mode mode, packet_info *pinfo,
461 uint16_t seq, uint16_t li, struct atm_phdr *atm)
463 frag->frame_num = pinfo->num;
464 frag->seq = seq;
465 frag->li = li;
466 frag->len = 0;
467 frag->data = NULL;
468 rlc_channel_assign(&frag->ch, mode, pinfo, atm);
470 return 0;
473 static int
474 rlc_frag_assign_data(struct rlc_frag *frag, tvbuff_t *tvb,
475 uint16_t offset, uint16_t length)
477 frag->len = length;
478 frag->data = (uint8_t *)tvb_memdup(wmem_file_scope(), tvb, offset, length);
479 return 0;
482 static struct rlc_frag *
483 rlc_frag_create(tvbuff_t *tvb, enum rlc_mode mode, packet_info *pinfo,
484 uint16_t offset, uint16_t length, uint16_t seq, uint16_t li,
485 struct atm_phdr *atm)
487 struct rlc_frag *frag;
489 frag = wmem_new0(wmem_file_scope(), struct rlc_frag);
490 rlc_frag_assign(frag, mode, pinfo, seq, li, atm);
491 rlc_frag_assign_data(frag, tvb, offset, length);
493 return frag;
496 static int
497 rlc_cmp_seq(const void *a, const void *b)
499 const struct rlc_seq *_a = (const struct rlc_seq *)a, *_b = (const struct rlc_seq *)b;
501 return _a->seq < _b->seq ? -1 :
502 _a->seq > _b->seq ? 1 :
506 static int moduloCompare(uint16_t a, uint16_t b, uint16_t modulus)
508 int ret;
509 a = a % modulus;
510 b = b % modulus;
512 if( a <= b ){
513 ret = a - b;
514 } else {
515 ret = a - (b + modulus);
517 if( ret == (1 - modulus) ){
518 ret = 1;
520 return ret;
523 static uint16_t getChannelSNModulus(struct rlc_channel * ch_lookup)
525 if( RLC_UM == ch_lookup->mode){ /*FIXME: This is a very heuristic way to determine SN bitwidth. */
526 return 128;
527 } else {
528 return 4096;
532 /* "Value destroy" function called each time an entry is removed
533 * from the sequence_table hash.
534 * It frees the GList pointed to by the entry.
536 static void
537 free_sequence_table_entry_data(void *data)
539 struct rlc_seqlist *list = (struct rlc_seqlist *)data;
540 if (list->list != NULL) {
541 g_list_free(list->list);
542 list->list = NULL; /* for good measure */
546 /** Utility functions used for various comparisons/cleanups in tree **/
547 static int
548 rlc_simple_key_cmp(const void *b_ptr, const void *a_ptr, void *ignore _U_){
549 if( GPOINTER_TO_INT(a_ptr) > GPOINTER_TO_INT(b_ptr) ){
550 return -1;
552 return GPOINTER_TO_INT(a_ptr) < GPOINTER_TO_INT(b_ptr);
555 static void
556 fragment_table_init(void)
558 int i;
559 fragment_table = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, rlc_channel_delete, NULL);
560 endpoints = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal, rlc_channel_delete, NULL);
561 reassembled_table = g_hash_table_new_full(rlc_frag_hash, rlc_frag_equal,
562 rlc_frag_delete, rlc_sdu_frags_delete);
563 sequence_table = g_hash_table_new_full(rlc_channel_hash, rlc_channel_equal,
564 NULL, free_sequence_table_entry_data);
565 duplicate_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
567 /*Reset and or clear deciphering variables*/
568 counter_map = g_tree_new_full(rlc_simple_key_cmp,NULL,NULL,rlc_channel_delete);
569 for(i = 0; i< 31; i++ ){
570 ps_counter[i][0] = 0;
571 ps_counter[i][1] = 0;
572 counter_init[i][0] = 0;
573 counter_init[i][1] = 0;
575 max_counter = 0;
578 static void
579 fragment_table_cleanup(void)
581 g_tree_destroy(counter_map);
582 g_hash_table_destroy(fragment_table);
583 g_hash_table_destroy(endpoints);
584 g_hash_table_destroy(reassembled_table);
585 g_hash_table_destroy(sequence_table);
586 g_hash_table_destroy(duplicate_table);
589 /* add the list of fragments for this sdu to 'tree' */
590 static void
591 tree_add_fragment_list(struct rlc_sdu *sdu, tvbuff_t *tvb,packet_info *pinfo, proto_tree *tree)
593 proto_item *ti;
594 proto_tree *frag_tree;
595 uint16_t offset;
596 struct rlc_frag *sdufrag;
598 ti = proto_tree_add_item(tree, hf_rlc_frags, tvb, 0, -1, ENC_NA);
599 proto_item_set_generated(ti);
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);
616 mark_frame_as_depended_upon(pinfo->fd, sdufrag->frame_num);
618 offset += sdufrag->len;
619 sdufrag = sdufrag->next;
621 ti = proto_tree_add_item(ti, hf_rlc_reassembled_data, tvb, 0, -1, ENC_NA);
622 proto_item_set_generated(ti);
625 /* add the list of fragments for this sdu to 'tree' */
626 static void
627 tree_add_fragment_list_incomplete(struct rlc_sdu *sdu, tvbuff_t *tvb, proto_tree *tree)
629 proto_item *ti;
630 proto_tree *frag_tree;
631 uint16_t offset;
632 struct rlc_frag *sdufrag;
634 ti = proto_tree_add_item(tree, hf_rlc_frags, tvb, 0, 0, ENC_NA);
635 proto_item_set_generated(ti);
636 frag_tree = proto_item_add_subtree(ti, ett_rlc_fragments);
637 proto_item_append_text(ti, " (%u bytes, %u fragments) ",
638 sdu->len, sdu->fragcnt);
639 sdufrag = sdu->frags;
640 offset = 0;
641 while (sdufrag) {
642 proto_tree_add_uint_format(frag_tree, hf_rlc_frag, tvb, 0,
643 0, sdufrag->frame_num, "Frame: %u, payload %u-%u (%u bytes) (Seq: %u)",
644 sdufrag->frame_num, offset, offset + sdufrag->len - 1, sdufrag->len, sdufrag->seq);
645 offset += sdufrag->len;
646 sdufrag = sdufrag->next;
650 /* Add the same description to too the two given proto_items */
651 static void
652 add_description(proto_item *li_ti, proto_item *length_ti,
653 const char *format, ...) G_GNUC_PRINTF(3, 4);
654 static void
655 add_description(proto_item *li_ti, proto_item *length_ti,
656 const char *format, ...)
658 #define MAX_INFO_BUFFER 256
659 static char info_buffer[MAX_INFO_BUFFER];
661 va_list ap;
663 va_start(ap, format);
664 vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
665 va_end(ap);
667 proto_item_append_text(li_ti, " (%s)", info_buffer);
668 proto_item_append_text(length_ti, " (%s)", info_buffer);
671 /* add information for an LI to 'tree' */
672 static proto_tree *
673 tree_add_li(enum rlc_mode mode, struct rlc_li *li, uint8_t li_idx, uint32_t hdr_offs,
674 bool li_is_on_2_bytes, tvbuff_t *tvb, proto_tree *tree)
676 proto_item *root_ti, *ti;
677 proto_tree *li_tree;
678 uint32_t li_offs;
679 uint64_t length;
681 if (!tree) return NULL;
683 if (li_is_on_2_bytes) {
684 li_offs = hdr_offs + li_idx*2;
685 root_ti = proto_tree_add_item(tree, hf_rlc_li, tvb, li_offs, 2, ENC_NA);
686 li_tree = proto_item_add_subtree(root_ti, ett_rlc_frag);
687 ti = proto_tree_add_bits_ret_val(li_tree, hf_rlc_li_value, tvb, li_offs*8, 15, &length, ENC_BIG_ENDIAN);
689 switch (li->li) {
690 case 0x0000:
691 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");
692 break;
693 case 0x7ffa:
694 if (mode == RLC_UM) {
695 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");
696 } else {
697 add_description(root_ti, ti, "Reserved");
699 break;
700 case 0x7ffb:
701 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");
702 break;
703 case 0x7ffc:
704 if (mode == RLC_UM) {
705 add_description(root_ti, ti, "The first data octet in this RLC PDU is the first octet of an RLC SDU");
706 } else {
707 add_description(root_ti, ti, "Reserved");
709 break;
710 case 0x7ffd:
711 if (mode == RLC_UM) {
712 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");
713 } else {
714 add_description(root_ti, ti, "Reserved");
716 break;
717 case 0x7ffe:
718 if (mode == RLC_UM) {
719 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");
720 } else {
721 add_description(root_ti, ti, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
723 break;
724 case 0x7fff:
725 add_description(root_ti, ti, "The rest of the RLC PDU is padding");
726 break;
728 default:
729 add_description(root_ti, ti, "length=%u", (uint16_t)length);
730 break;
732 proto_tree_add_bits_item(li_tree, hf_rlc_li_ext, tvb, li_offs*8+15, 1, ENC_BIG_ENDIAN);
733 } else {
734 li_offs = hdr_offs + li_idx;
735 root_ti = proto_tree_add_item(tree, hf_rlc_li, tvb, li_offs, 1, ENC_NA);
736 li_tree = proto_item_add_subtree(root_ti, ett_rlc_frag);
737 ti = proto_tree_add_bits_ret_val(li_tree, hf_rlc_li_value, tvb, li_offs*8, 7, &length, ENC_BIG_ENDIAN);
738 switch (li->li) {
739 case 0x00:
740 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");
741 break;
742 case 0x7c:
743 if (mode == RLC_UM) {
744 add_description(root_ti, ti, "The first data octet in this RLC PDU is the first octet of an RLC SDU");
745 } else {
746 add_description(root_ti, ti, "Reserved");
748 break;
749 case 0x7d:
750 if (mode == RLC_UM) {
751 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");
752 } else {
753 add_description(root_ti, ti, "Reserved");
755 break;
756 case 0x7e:
757 if (mode == RLC_UM) {
758 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");
759 } else {
760 add_description(root_ti, ti, "The rest of the RLC PDU includes a piggybacked STATUS PDU");
762 break;
763 case 0x7f:
764 add_description(root_ti, ti, "The rest of the RLC PDU is padding");
765 break;
767 default:
768 add_description(root_ti, ti, "length=%u", (uint16_t)length);
769 break;
771 proto_tree_add_bits_item(li_tree, hf_rlc_li_ext, tvb, li_offs*8+7, 1, ENC_BIG_ENDIAN);
774 if (li->len > 0) {
775 if (li->li > tvb_reported_length_remaining(tvb, hdr_offs)) return li_tree;
776 if (li->len > li->li) return li_tree;
777 ti = proto_tree_add_item(li_tree, hf_rlc_li_data, tvb, hdr_offs + li->li - li->len, li->len, ENC_NA);
778 proto_item_set_hidden(ti);
781 return li_tree;
784 /* add a fragment to an SDU */
785 static int
786 rlc_sdu_add_fragment(enum rlc_mode mode, struct rlc_sdu *sdu, struct rlc_frag *frag)
788 struct rlc_frag *tmp;
790 if (!sdu->frags) {
791 /* insert as first element */
792 sdu->frags = frag;
793 sdu->last = frag;
794 sdu->fragcnt++;
795 sdu->len += frag->len;
796 return 0;
798 switch (mode) {
799 case RLC_UM:
800 /* insert as last element */
801 sdu->last->next = frag;
802 frag->next = NULL;
803 sdu->last = frag;
804 sdu->len += frag->len;
805 break;
806 case RLC_AM:
807 /* insert ordered */
808 tmp = sdu->frags;
810 /* If receiving exotic border line sequence, e.g. 4094, 4095, 0, 1 */
811 if (frag->seq+2048 < tmp->seq) {
812 while (tmp->next && frag->seq+2048 < tmp->seq)
813 tmp = tmp->next;
814 if (tmp->next == NULL) {
815 tmp->next = frag;
816 sdu->last = frag;
817 } else {
818 while (tmp->next && tmp->next->seq < frag->seq)
819 tmp = tmp->next;
820 frag->next = tmp->next;
821 tmp->next = frag;
822 if (frag->next == NULL) sdu->last = frag;
824 } else { /* Receiving ordinary sequence */
825 if (frag->seq < tmp->seq) {
826 /* insert as first element */
827 frag->next = tmp;
828 sdu->frags = frag;
829 } else {
830 while (tmp->next && tmp->next->seq < frag->seq)
831 tmp = tmp->next;
832 frag->next = tmp->next;
833 tmp->next = frag;
834 if (frag->next == NULL) sdu->last = frag;
837 sdu->len += frag->len;
838 break;
839 default:
840 return -2;
842 sdu->fragcnt++;
843 return 0;
846 static void
847 reassemble_data(struct rlc_channel *ch, struct rlc_sdu *sdu, struct rlc_frag *frag)
849 struct rlc_frag *temp;
850 uint16_t offs = 0;
852 if (!sdu || !ch || !sdu->frags) return;
854 if (sdu->data) return; /* already assembled */
856 if (frag)
857 sdu->reassembled_in = frag;
858 else
859 sdu->reassembled_in = sdu->last;
861 sdu->data = (uint8_t *)wmem_alloc(wmem_file_scope(), sdu->len);
862 temp = sdu->frags;
863 while (temp && ((offs + temp->len) <= sdu->len)) {
864 if (temp->data) {
865 memcpy(sdu->data + offs, temp->data, temp->len);
866 wmem_free(wmem_file_scope(), temp->data);
868 temp->data = NULL;
869 /* mark this fragment in reassembled table */
870 g_hash_table_insert(reassembled_table, temp, sdu);
872 offs += temp->len;
873 temp = temp->next;
877 #define RLC_ADD_FRAGMENT_FAIL_PRINT 0
878 #define RLC_ADD_FRAGMENT_DEBUG_PRINT 0
879 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
880 static void
881 printends(GList * list)
883 if (list == NULL)
884 return;
885 g_print("-> length: %d\n[", g_list_length(list));
886 while (list)
888 g_print("%d ", GPOINTER_TO_INT(list->data));
889 list = list->next;
891 g_print("]\n");
893 #endif
895 static struct rlc_frag **
896 get_frags(packet_info * pinfo, struct rlc_channel * ch_lookup, struct atm_phdr *atm)
898 void *value = NULL;
899 struct rlc_frag ** frags = NULL;
900 /* Look for already created frags table */
901 if (g_hash_table_lookup_extended(fragment_table, ch_lookup, NULL, &value)) {
902 frags = (struct rlc_frag **)value;
903 } else if (pinfo != NULL) {
904 struct rlc_channel *ch;
905 ch = rlc_channel_create(ch_lookup->mode, pinfo, atm);
906 frags = (struct rlc_frag **)wmem_alloc0(wmem_file_scope(), sizeof(struct rlc_frag *) * 4096);
907 g_hash_table_insert(fragment_table, ch, frags);
908 } else {
909 return NULL;
911 return frags;
913 static struct rlc_seqlist *
914 get_endlist(packet_info * pinfo, struct rlc_channel * ch_lookup, struct atm_phdr *atm)
916 void *value = NULL;
917 struct rlc_seqlist * endlist = NULL;
918 /* If there already exists a frag table for this channel use that one. */
919 if (g_hash_table_lookup_extended(endpoints, ch_lookup, NULL, &value)) {
920 endlist = (struct rlc_seqlist *)value;
921 } else if (pinfo != NULL) { /* Else create a new one. */
922 struct rlc_channel * ch;
924 endlist = wmem_new(wmem_file_scope(), struct rlc_seqlist);
925 ch = rlc_channel_create(ch_lookup->mode, pinfo, atm);
926 endlist->fail_packet = 0;
927 endlist->list = NULL;
928 endlist->list = g_list_prepend(endlist->list, GINT_TO_POINTER(-1));
929 g_hash_table_insert(endpoints, ch, endlist);
930 } else {
931 return NULL;
933 return endlist;
936 static void
937 reassemble_sequence(struct rlc_frag ** frags, struct rlc_seqlist * endlist,
938 struct rlc_channel * ch_lookup, uint16_t start, uint16_t end)
940 GList * element = NULL;
941 struct rlc_sdu * sdu = rlc_sdu_create();
943 uint16_t snmod = getChannelSNModulus(ch_lookup);
945 /* Insert fragments into SDU. */
946 for (; moduloCompare(start,end,snmod ) <= 0; start = (start+1)%snmod)
948 struct rlc_frag * tempfrag = NULL;
949 tempfrag = frags[start]->next;
950 frags[start]->next = NULL;
951 rlc_sdu_add_fragment(ch_lookup->mode, sdu, frags[start]);
952 frags[start] = tempfrag;
955 /* Remove first endpoint. */
956 element = g_list_first(endlist->list);
957 if (element) {
958 endlist->list = g_list_remove_link(endlist->list, element);
959 if (frags[end] != NULL) {
960 if (endlist->list) {
961 endlist->list->data = GINT_TO_POINTER((GPOINTER_TO_INT(endlist->list->data) - 1 + snmod) % snmod);
965 reassemble_data(ch_lookup, sdu, NULL);
968 /* Reset the specified channel's reassembly data, useful for when a sequence
969 * resets on transport channel swap. */
970 /* TODO: not currently called */
971 void
972 rlc_reset_channel(enum rlc_mode mode, uint8_t rbid, uint8_t dir, uint32_t ueid,
973 struct atm_phdr *atm)
975 struct rlc_frag ** frags = NULL;
976 struct rlc_seqlist * endlist = NULL;
977 struct rlc_channel ch_lookup;
978 unsigned i;
980 ch_lookup.mode = mode;
981 ch_lookup.rbid = rbid;
982 ch_lookup.dir = dir;
983 ch_lookup.ueid = ueid;
984 frags = get_frags(NULL, &ch_lookup, atm);
985 endlist = get_endlist(NULL, &ch_lookup, atm);
986 if (endlist) {
987 endlist->fail_packet = 0;
988 g_list_free(endlist->list);
989 endlist->list = NULL;
992 if (frags) {
993 for (i = 0; i < 4096; i++) {
994 frags[i] = NULL;
999 /* add a new fragment to an SDU
1000 * if length == 0, just finalize the specified SDU
1002 static struct rlc_frag *
1003 add_fragment(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
1004 proto_tree *tree, uint16_t offset, uint16_t seq, uint16_t num_li,
1005 uint16_t len, bool final, struct atm_phdr *atm)
1007 struct rlc_channel ch_lookup;
1008 struct rlc_frag frag_lookup, *frag = NULL;
1009 gpointer orig_key = NULL, value = NULL;
1010 struct rlc_sdu *sdu = NULL;
1011 struct rlc_frag ** frags = NULL;
1012 struct rlc_seqlist * endlist = NULL;
1013 GList * element = NULL;
1014 int snmod;
1016 if (rlc_channel_assign(&ch_lookup, mode, pinfo, atm) == -1) {
1017 return NULL;
1019 rlc_frag_assign(&frag_lookup, mode, pinfo, seq, num_li, atm);
1020 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1021 g_print("packet: %d, channel (%d %d %d) seq: %u, num_li: %u, offset: %u, \n", pinfo->num, ch_lookup.dir, ch_lookup.rbid, ch_lookup.ueid, seq, num_li, offset);
1022 #endif
1024 snmod = getChannelSNModulus(&ch_lookup);
1026 /* look for an already assembled SDU */
1027 if (g_hash_table_lookup_extended(reassembled_table, &frag_lookup, &orig_key, &value)) {
1028 /* this fragment is already reassembled somewhere */
1029 frag = (struct rlc_frag *)orig_key;
1030 sdu = (struct rlc_sdu *)value;
1031 if (tree) {
1032 /* mark the fragment, if reassembly happened somewhere else */
1033 if (frag->seq != sdu->reassembled_in->seq ||
1034 frag->li != sdu->reassembled_in->li)
1035 proto_tree_add_uint(tree, hf_rlc_reassembled_in, tvb, 0, 0,
1036 sdu->reassembled_in->frame_num);
1038 return frag;
1041 frags = get_frags(pinfo, &ch_lookup, atm);
1042 endlist = get_endlist(pinfo, &ch_lookup, atm);
1044 /* If already done reassembly */
1045 if (PINFO_FD_VISITED(pinfo)) {
1046 if (tree && len > 0) {
1047 if (endlist->list && endlist->list->next) {
1048 int16_t start = (GPOINTER_TO_INT(endlist->list->data) + 1) % snmod;
1049 int16_t end = GPOINTER_TO_INT(endlist->list->next->data);
1050 int16_t missing = start;
1051 bool wecanreasmmore = true;
1053 for (; moduloCompare(missing,end,snmod ) <= 0; missing = (missing+1)%snmod)
1055 if (frags[missing] == NULL) {
1056 wecanreasmmore = false;
1057 break;
1061 if (wecanreasmmore) {
1062 reassemble_sequence(frags, endlist, &ch_lookup, start, end);
1063 } else {
1064 if (end >= 0 && end < snmod && frags[end]) {
1065 proto_tree_add_expert_format(tree, pinfo, &ei_rlc_reassembly_fail_unfinished_sequence, tvb, 0, 0,
1066 "Did not perform reassembly because of unfinished sequence (%d->%d [packet %u]), could not find %d.", start, end, frags[end]->frame_num, missing);
1067 } else {
1068 proto_tree_add_expert_format(tree, pinfo, &ei_rlc_reassembly_fail_unfinished_sequence, tvb, 0, 0,
1069 "Did not perform reassembly because of unfinished sequence (%d->%d [could not determine packet]), could not find %d.", start, end, missing);
1072 } else if (endlist->list) {
1073 if (endlist->fail_packet != 0 && endlist->fail_packet <= pinfo->num) {
1074 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);
1075 } else {
1076 int16_t end = GPOINTER_TO_INT(endlist->list->data);
1077 if (end >= 0 && end < snmod && frags[end]) {
1078 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);
1079 } else {
1080 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);
1083 } else {
1084 expert_add_info(pinfo, NULL, &ei_rlc_reassembly_unknown_error);
1087 return NULL; /* If already done reassembly and no SDU found, too bad */
1090 if (endlist->fail_packet != 0) { /* don't continue after sh*t has hit the fan */
1091 return NULL;
1094 frag = rlc_frag_create(tvb, mode, pinfo, offset, len, seq, num_li, atm);
1096 /* If frags[seq] is not NULL then we must have data from several PDUs in the
1097 * same RLC packet (using Length Indicators) or something has gone terribly
1098 * wrong. */
1099 if (frags[seq] != NULL) {
1100 if (num_li > 0) {
1101 struct rlc_frag * tempfrag = frags[seq];
1102 while (tempfrag->next != NULL)
1103 tempfrag = tempfrag->next;
1104 tempfrag->next = frag;
1105 } else { /* This should never happen */
1106 endlist->fail_packet = pinfo->num;
1107 return NULL;
1109 } else {
1110 frags[seq] = frag;
1113 /* It is also possible that frags[seq] is NULL even though we do have data
1114 * from several PDUs in the same RLC packet. This is if the reassembly is
1115 * not lagging behind at all because of perfectly ordered sequences. */
1116 if (endlist->list && num_li != 0) {
1117 int16_t first = GPOINTER_TO_INT(endlist->list->data);
1118 if (seq == first) {
1119 endlist->list->data = GINT_TO_POINTER(first-1);
1123 /* If this is an endpoint */
1124 if (final) {
1125 endlist->list = g_list_append(endlist->list, GINT_TO_POINTER((int)seq));
1128 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1129 printends(endlist->list);
1130 #endif
1132 /* Try to reassemble SDU. */
1133 if (endlist->list && endlist->list->next) {
1134 int16_t start = (GPOINTER_TO_INT(endlist->list->data) + 1) % snmod;
1135 int16_t end = GPOINTER_TO_INT(endlist->list->next->data);
1136 if (frags[end] == NULL) {
1137 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1138 proto_tree_add_debug_text(tree, "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->num);
1139 #endif
1140 endlist->fail_packet = pinfo->num;
1141 return NULL;
1144 /* If our endpoint is a LI=0 with no data. */
1145 if (start == end && frags[start]->len == 0) {
1146 element = g_list_first(endlist->list);
1147 if (element) {
1148 endlist->list = g_list_remove_link(endlist->list, element);
1150 frags[start] = frags[start]->next;
1152 /* If frags[start] is not NULL now, then that means that there was
1153 * another fragment with the same seq number because of LI. If we
1154 * don't decrease the endpoint by 1 then that fragment will be
1155 * skipped and all hell will break lose. */
1156 if (frags[start] != NULL) {
1157 endlist->list->data = GINT_TO_POINTER(start-1);
1159 /* NOTE: frags[start] is wmem_alloc'ed and will remain until file closes, we would want to free it here maybe. */
1160 return NULL;
1163 #if RLC_ADD_FRAGMENT_DEBUG_PRINT
1164 g_print("start: %d, end: %d\n",start, end);
1165 #endif
1167 for (; moduloCompare(start,end,snmod ) < 0; start = (start+1)%snmod)
1169 if (frags[start] == NULL) {
1170 if (MIN((start-seq+snmod)%snmod, (seq-start+snmod)%snmod) >= snmod/4) {
1171 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1172 proto_tree_add_debug_text(tree,
1173 "Packet %u. Setting fail flag because RLC fragment with sequence number %u was \
1174 too far away from an unfinished sequence (%u->%u). The missing sequence number \
1175 is %u. The most recently complete sequence ended in packet %u.", pinfo->num, seq, 0, end, start, 0);
1176 #endif
1177 endlist->fail_packet = pinfo->num; /* If it has gone too far, give up */
1178 return NULL;
1180 return frag;
1183 start = (GPOINTER_TO_INT(endlist->list->data) + 1) % snmod;
1184 reassemble_sequence(frags, endlist, &ch_lookup, start, end);
1185 } else if (endlist->list) {
1186 int16_t first = (GPOINTER_TO_INT(endlist->list->data) + 1) % snmod;
1187 /* If the distance between the oldest stored endpoint in endlist and
1188 * this endpoint is too large, set fail flag. */
1189 if (MIN((first-seq+snmod)%snmod, (seq-first+snmod)%snmod) >= snmod/4) {
1190 #if RLC_ADD_FRAGMENT_FAIL_PRINT
1191 proto_tree_add_debug_text(tree,
1192 "Packet %u. Setting fail flag because RLC fragment with sequence number %u was \
1193 too far away from an unfinished sequence with start %u and without end.", pinfo->num, seq, first);
1194 #endif
1195 endlist->fail_packet = pinfo->num; /* Give up if things have gone too far. */
1196 return NULL;
1200 return frag;
1203 /* is_data is used to identify rlc data parts that are not identified by an LI, but are at the end of
1204 * the RLC frame
1205 * these can be valid reassembly points, but only if the LI of the *next* relevant RLC frame is
1206 * set to '0' (this is indicated in the reassembled SDU
1208 static tvbuff_t *
1209 get_reassembled_data(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo,
1210 proto_tree *tree, uint16_t seq, uint16_t num_li,
1211 struct atm_phdr *atm)
1213 gpointer orig_frag, orig_sdu;
1214 struct rlc_sdu *sdu;
1215 struct rlc_frag lookup, *frag;
1217 rlc_frag_assign(&lookup, mode, pinfo, seq, num_li, atm);
1219 if (!g_hash_table_lookup_extended(reassembled_table, &lookup,
1220 &orig_frag, &orig_sdu))
1221 return NULL;
1223 sdu = (struct rlc_sdu *)orig_sdu;
1224 if (!sdu || !sdu->data)
1225 return NULL;
1227 /* TODO */
1228 #if 0
1229 if (!rlc_frag_equal(&lookup, sdu->reassembled_in)) return NULL;
1230 #endif
1232 frag = sdu->frags;
1233 while (frag->next) {
1234 if (frag->next->seq - frag->seq > 1) {
1235 proto_tree_add_expert(tree, pinfo, &ei_rlc_incomplete_sequence, tvb, 0, 0);
1236 tree_add_fragment_list_incomplete(sdu, tvb, tree);
1237 return NULL;
1239 frag = frag->next;
1242 sdu->tvb = tvb_new_child_real_data(tvb, sdu->data, sdu->len, sdu->len);
1243 add_new_data_source(pinfo, sdu->tvb, "Reassembled RLC Message");
1245 /* reassembly happened here, so create the fragment list */
1246 if (tree && sdu->fragcnt > 1)
1247 tree_add_fragment_list(sdu, sdu->tvb, pinfo, tree);
1249 return sdu->tvb;
1252 #define RLC_RETRANSMISSION_TIMEOUT 5 /* in seconds */
1253 static bool
1254 rlc_is_duplicate(enum rlc_mode mode, packet_info *pinfo, uint16_t seq,
1255 uint32_t *original, struct atm_phdr *atm)
1257 GList *element;
1258 struct rlc_seqlist lookup, *list;
1259 struct rlc_seq seq_item, *seq_new;
1260 uint16_t snmod;
1261 nstime_t delta;
1262 bool is_duplicate,is_unseen;
1264 if (rlc_channel_assign(&lookup.ch, mode, pinfo, atm) == -1)
1265 return false;
1266 list = (struct rlc_seqlist *)g_hash_table_lookup(sequence_table, &lookup.ch);
1267 if (!list) {
1268 /* we see this channel for the first time */
1269 list = (struct rlc_seqlist *)wmem_alloc0(wmem_file_scope(), sizeof(*list));
1270 rlc_channel_assign(&list->ch, mode, pinfo, atm);
1271 g_hash_table_insert(sequence_table, &list->ch, list);
1273 seq_item.seq = seq;
1274 seq_item.frame_num = pinfo->num;
1276 /* When seq is 12 bit (in RLC protocol), it will wrap around after 4096. */
1277 /* Window size is at most 4095 so we remove packets further away than that */
1278 element = g_list_first(list->list);
1279 snmod = getChannelSNModulus(&lookup.ch);
1280 if (element) {
1281 seq_new = (struct rlc_seq *)element->data;
1282 /* Add SN modulus because %-operation for negative values in C is not equal to mathematical modulus */
1283 if (MIN((seq_new->seq-seq+snmod)%snmod, (seq-seq_new->seq+snmod)%snmod) >= snmod/4) {
1284 list->list = g_list_remove_link(list->list, element);
1288 is_duplicate = false;
1289 is_unseen = true;
1290 element = g_list_find_custom(list->list, &seq_item, rlc_cmp_seq);
1291 while(element) {
1292 /* Check if this is a different frame (by comparing frame numbers) which arrived less than */
1293 /* RLC_RETRANSMISSION_TIMEOUT seconds ago */
1294 seq_new = (struct rlc_seq *)element->data;
1295 if (seq_new->frame_num < seq_item.frame_num) {
1296 nstime_delta(&delta, &pinfo->abs_ts, &seq_new->arrival);
1297 if (delta.secs < RLC_RETRANSMISSION_TIMEOUT) {
1298 /* This is a duplicate. */
1299 if (original) {
1300 /* Save the frame number where our sequence number was previously seen */
1301 *original = seq_new->frame_num;
1303 is_duplicate = true;
1306 else if (seq_new->frame_num == seq_item.frame_num) {
1307 /* Check if our frame is already in the list and this is a secondary check.*/
1308 /* in this case raise a flag so the frame isn't entered more than once to the list */
1309 is_unseen = false;
1311 element = g_list_find_custom(element->next, &seq_item, rlc_cmp_seq);
1313 if(is_unseen) {
1314 /* Add to list for the first time this frame is checked */
1315 seq_new = wmem_new0(wmem_file_scope(), struct rlc_seq);
1316 *seq_new = seq_item;
1317 seq_new->arrival = pinfo->abs_ts;
1318 list->list = g_list_append(list->list, seq_new); /* insert in order of arrival */
1320 return is_duplicate;
1323 static void
1324 rlc_call_subdissector(enum rlc_channel_type channel, tvbuff_t *tvb,
1325 packet_info *pinfo, proto_tree *tree)
1327 bool is_rrc_payload = true;
1328 volatile dissector_handle_t next_dissector = NULL;
1329 enum rrc_message_type msgtype;
1331 switch (channel) {
1332 case RLC_UL_CCCH:
1333 msgtype = RRC_MESSAGE_TYPE_UL_CCCH;
1334 break;
1335 case RLC_DL_CCCH:
1336 msgtype = RRC_MESSAGE_TYPE_DL_CCCH;
1337 break;
1338 case RLC_DL_CTCH:
1339 /* Payload of DL CTCH is BMC*/
1340 is_rrc_payload = false;
1341 msgtype = RRC_MESSAGE_TYPE_INVALID;
1342 next_dissector = bmc_handle;
1343 break;
1344 case RLC_UL_DCCH:
1345 msgtype = RRC_MESSAGE_TYPE_UL_DCCH;
1346 break;
1347 case RLC_DL_DCCH:
1348 msgtype = RRC_MESSAGE_TYPE_DL_DCCH;
1349 break;
1350 case RLC_PCCH:
1351 msgtype = RRC_MESSAGE_TYPE_PCCH;
1352 break;
1353 case RLC_BCCH:
1354 msgtype = RRC_MESSAGE_TYPE_BCCH_FACH;
1355 break;
1356 case RLC_PS_DTCH:
1357 /* Payload of PS DTCH is PDCP or just IP*/
1358 is_rrc_payload = false;
1359 msgtype = RRC_MESSAGE_TYPE_INVALID;
1360 /* assume transparent PDCP for now */
1361 next_dissector = ip_handle;
1362 break;
1363 default:
1364 return; /* stop dissecting */
1367 if (is_rrc_payload && msgtype != RRC_MESSAGE_TYPE_INVALID) {
1368 /* Passing the RRC sub type in the 'rrc_info' struct */
1369 struct rrc_info *rrcinf;
1370 fp_info *fpinf;
1371 fpinf = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
1372 rrcinf = (rrc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rrc, 0);
1373 if (!rrcinf) {
1374 rrcinf = (rrc_info *)wmem_alloc0(wmem_file_scope(), sizeof(struct rrc_info));
1375 p_add_proto_data(wmem_file_scope(), pinfo, proto_rrc, 0, rrcinf);
1377 rrcinf->msgtype[fpinf->cur_tb] = msgtype;
1378 next_dissector = rrc_handle;
1381 if(next_dissector != NULL) {
1382 TRY {
1383 call_dissector(next_dissector, tvb, pinfo, tree);
1385 CATCH_NONFATAL_ERRORS {
1387 * Sub dissector threw an exception
1388 * Show the exception and continue dissecting other SDUs.
1390 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
1392 ENDTRY;
1393 /* once the packet has been dissected, protect it from further changes using a 'fence' in the INFO column */
1394 col_append_str(pinfo->cinfo, COL_INFO," ");
1395 col_set_fence(pinfo->cinfo, COL_INFO);
1399 static void
1400 add_channel_info(packet_info * pinfo, proto_tree * tree, fp_info * fpinf, rlc_info * rlcinf)
1402 proto_item * item;
1403 proto_tree * channel_tree ;
1405 item = proto_tree_add_item(tree, hf_rlc_channel, NULL, 0, 0, ENC_NA);
1406 channel_tree = proto_item_add_subtree(item, ett_rlc_channel);
1407 proto_item_append_text(item, " (rbid: %u, dir: %s, uid: 0x%08x)", rlcinf->rbid[fpinf->cur_tb],
1408 val_to_str_const(pinfo->link_dir, rlc_dir_vals, "Unknown"), rlcinf->ueid[fpinf->cur_tb]);
1409 proto_item_set_generated(item);
1410 item = proto_tree_add_uint(channel_tree, hf_rlc_channel_rbid, NULL, 0, 0, rlcinf->rbid[fpinf->cur_tb]);
1411 proto_item_set_generated(item);
1412 item = proto_tree_add_uint(channel_tree, hf_rlc_channel_dir, NULL, 0, 0, pinfo->link_dir);
1413 proto_item_set_generated(item);
1414 item = proto_tree_add_uint(channel_tree, hf_rlc_channel_ueid, NULL, 0, 0, rlcinf->ueid[fpinf->cur_tb]);
1415 proto_item_set_generated(item);
1419 #ifdef HAVE_UMTS_KASUMI
1420 static uint8_t *
1421 translate_hex_key(char * char_key){
1422 int i,j;
1423 uint8_t * key_in;
1425 key_in = wmem_alloc0(pinfo->pool, sizeof(uint8_t)*16);
1426 j= (int)(strlen(char_key)/2)-1;
1427 /*Translate "hex-string" into a byte aligned block */
1428 for(i = (int)strlen(char_key); i> 0; i-=2 ){
1429 key_in[j] = ( (uint8_t) (strtol( &char_key[i-2], NULL, 16 ) ));
1430 char_key[i-2] = '\0';
1431 j--;
1433 return key_in;
1436 #endif
1438 /** @brief Deciphers a given tvb
1440 * Note that the actual KASUMI implementation needs to be placed into
1441 * epan/crypt/kasumi.* by "end users" since due to patents the actual implementation
1442 * cannot be distributed openly at the moment.
1444 * Refer to 3GPP TS 35.201 and 3GPP TS 35.202 for further information.
1446 * @param tvb The ciphered data.
1447 * @param pinfo Packet info.
1448 * @param counter the COUNTER value input
1449 * @param rbid the radiobear id
1450 * @param dir Direction of the link
1451 * @param header_size Size of the unciphered header
1452 * @return tvb Returns a deciphered tvb
1454 static tvbuff_t *
1455 #ifndef HAVE_UMTS_KASUMI
1456 rlc_decipher_tvb(tvbuff_t *tvb _U_, packet_info *pinfo, uint32_t counter _U_,
1457 uint8_t rbid _U_, bool dir _U_, uint8_t header_size _U_) {
1458 /*Check if we have a KASUMI implementation*/
1459 expert_add_info(pinfo, NULL, &ei_rlc_kasumi_implementation_missing);
1460 return NULL;
1461 #else
1462 rlc_decipher_tvb(tvbuff_t *tvb, packet_info *pinfo, uint32_t counter, uint8_t rbid, bool dir, uint8_t header_size) {
1463 uint8_t* out=NULL,*key_in = NULL;
1464 tvbuff_t *t;
1466 /*Fix the key into a byte block*/
1467 /*TODO: This should be done in a preferences callback function*/
1468 out = wmem_alloc0(pinfo->pool, strlen(global_rlc_kasumi_key)+1);
1469 memcpy(out,global_rlc_kasumi_key,strlen(global_rlc_kasumi_key)); /*Copy from preference const pointer*/
1470 key_in = translate_hex_key(out); /*Translation*/
1472 /*Location for decrypted data & original RLC header*/
1473 out = tvb_memdup(pinfo->pool, tvb, 0, tvb_captured_length(tvb));
1475 /*Call f8 confidentiality function, note that rbid is zero indexed*/
1476 f8( key_in, counter, rbid-1, dir, &out[header_size], (tvb_captured_length(tvb)-header_size)*8 );
1478 /*Create new tvb.*/
1479 t = tvb_new_real_data(out,tvb_captured_length(tvb), tvb_reported_length(tvb));
1480 add_new_data_source(pinfo, t, "Deciphered RLC");
1481 return t;
1482 #endif /* HAVE_UMTS_KASUMI */
1485 /** @brief Checks if an RLC packet is ciphered, according to information reported from the RRC layer
1487 * @param pinfo Packet info.
1488 * @param fpinf FP info
1489 * @param rlcinf RLC info
1490 * @param seq Sequence number of the RLC packet
1491 * @return bool Returns true if the packet is ciphered and false otherwise
1493 static bool
1494 is_ciphered_according_to_rrc(packet_info *pinfo, fp_info *fpinf, rlc_info *rlcinf ,uint16_t seq) {
1495 int16_t cur_tb;
1496 uint32_t ueid;
1497 rrc_ciphering_info *ciphering_info;
1498 uint8_t rbid;
1499 uint8_t direction;
1500 uint32_t security_mode_frame_num;
1501 int32_t ciphering_begin_seq;
1503 if(global_ignore_rrc_ciphering_indication) {
1504 return false;
1507 cur_tb = fpinf->cur_tb;
1508 ueid = rlcinf->ueid[cur_tb];
1509 ciphering_info = (rrc_ciphering_info *)g_tree_lookup(rrc_ciph_info_tree, GINT_TO_POINTER((int)ueid));
1510 if(ciphering_info != NULL) {
1511 rbid = rlcinf->rbid[cur_tb];
1512 direction = fpinf->is_uplink ? P2P_DIR_UL : P2P_DIR_DL;
1513 security_mode_frame_num = ciphering_info->setup_frame[direction];
1514 ciphering_begin_seq = ciphering_info->seq_no[rbid][direction];
1515 /* Making sure the rrc security message's frame number makes sense */
1516 if( security_mode_frame_num > 0 && security_mode_frame_num <= pinfo->num) {
1517 /* Making sure the sequence number where ciphering starts makes sense */
1518 /* TODO: This check is incorrect if the sequence numbers wrap around */
1519 if(ciphering_begin_seq >= 0 && ciphering_begin_seq <= seq){
1520 /* Finally, make sure the encryption algorithm isn't set to UEA0 (no ciphering)*/
1521 return ciphering_info->ciphering_algorithm != 0;
1525 return false;
1529 * @param key is created with GINT_TO_POINTER
1530 * @param value is a pointer to a uint32_t
1531 * @param data is a pointer to a uint32_t
1533 static gboolean
1534 iter_same(void *key, void *value, void *data) {
1535 /*If true we found the correct frame*/
1536 if ((uint32_t)GPOINTER_TO_INT(key) > *(uint32_t*)data){
1537 *((uint32_t*)data) = *((uint32_t*)value);
1538 return true;
1540 *((uint32_t*)data) = (uint32_t)GPOINTER_TO_INT(key);
1542 return true;
1546 * Used for looking up and old ciphering counter value in the counter_map tree.
1547 * @param key is created with GINT_TO_POINTER
1548 * @param value is pointer to an array of 2 uint32_t
1549 * @param data is a pointer to an array of 3 uint32_t
1551 static gboolean
1552 rlc_find_old_counter(void *key, void *value, void *data) {
1554 /*If true we found the correct frame*/
1555 if( (uint32_t)GPOINTER_TO_INT(key) >= ((uint32_t *)data)[0] ){
1556 return TRUE;
1558 /*Overwrite the data since the previous one wasn't correct*/
1559 ((uint32_t*)data)[1] = ((uint32_t*)value)[0];
1560 ((uint32_t*)data)[2] = ((uint32_t*)value)[1];
1562 return FALSE;
1565 static void
1566 rlc_decipher(tvbuff_t *tvb, packet_info * pinfo, proto_tree * tree, fp_info * fpinf,
1567 rlc_info * rlcinf, uint16_t seq, enum rlc_mode mode)
1569 rrc_ciphering_info *ciphering_info;
1570 uint8_t indx, header_size, hfn_shift;
1571 int16_t pos;
1572 uint8_t ext;
1573 int ciphered_data_hf;
1575 indx = fpinf->is_uplink ? P2P_DIR_UL : P2P_DIR_DL;
1576 pos = fpinf->cur_tb;
1577 if (mode ==RLC_UM) {
1578 header_size = 1;
1579 hfn_shift = 7;
1580 } else {
1581 header_size = 2;
1582 hfn_shift = 12;
1585 /*Ciphering info singled in RRC by securitymodecommands */
1586 ciphering_info = (rrc_ciphering_info *)g_tree_lookup(rrc_ciph_info_tree, GINT_TO_POINTER((int)rlcinf->ueid[fpinf->cur_tb]));
1588 /*TODO: This doesn't really work for all packets..*/
1589 /*Check if we have ciphering info and that this frame is ciphered*/
1590 if(ciphering_info!=NULL && ( (ciphering_info->setup_frame[indx] > 0 && ciphering_info->setup_frame[indx] < pinfo->num && ciphering_info->seq_no[rlcinf->rbid[pos]][indx] == -1) ||
1591 (ciphering_info->setup_frame[indx] < pinfo->num && ciphering_info->seq_no[rlcinf->rbid[pos]][indx] >= 0 && ciphering_info->seq_no[rlcinf->rbid[pos]][indx] <= seq) )){
1593 tvbuff_t *t;
1595 /*Check if this counter has been initialized*/
1596 if(!counter_init[rlcinf->rbid[pos]][indx] ){
1597 uint32_t frame_num = pinfo->num;
1599 /*Initializes counter*/
1600 counter_init[rlcinf->rbid[pos]][0] = true;
1601 counter_init[rlcinf->rbid[pos]][1] = true;
1602 /*Find appropriate start value*/
1603 g_tree_foreach(ciphering_info->start_ps, (GTraverseFunc)iter_same, &frame_num);
1605 /*Set COUNTER value accordingly as specified by 6.4.8 in 3GPP TS 33.102 */
1606 if(max_counter +2 > frame_num && ciphering_info->seq_no[rlcinf->rbid[pos]][indx] == -1){
1607 ps_counter[rlcinf->rbid[pos]][0] = (max_counter+2) << hfn_shift;
1608 ps_counter[rlcinf->rbid[pos]][1] = (max_counter+2) << hfn_shift;
1609 }else{
1610 ps_counter[rlcinf->rbid[pos]][0] = frame_num << hfn_shift;
1611 ps_counter[rlcinf->rbid[pos]][1] = frame_num << hfn_shift;
1614 if(!tree){
1615 /*Preserve counter value for next dissection round*/
1616 uint32_t * ciph;
1617 ciph = g_new(uint32_t, 2);
1618 ciph[0] = ps_counter[rlcinf->rbid[pos]][0];
1619 ciph[1] = ps_counter[rlcinf->rbid[pos]][1];
1620 g_tree_insert(counter_map, GINT_TO_POINTER((int)pinfo->num), ciph);
1624 /*Update the maximal COUNTER value seen so far*/
1625 max_counter = MAX(max_counter,((ps_counter[rlcinf->rbid[pos]][indx]) | seq) >> hfn_shift);
1627 /*XXX: Since RBID in umts isn't configured properly..*/
1628 if(rlcinf->rbid[pos] == 9 ){
1629 if(tree){
1630 uint32_t frame_num[3];
1631 /*Set frame num we will be "searching" around*/
1632 frame_num[0] = pinfo->num;
1633 /*Find the correct counter value*/
1634 g_tree_foreach(counter_map, (GTraverseFunc)rlc_find_old_counter, &frame_num[0]);
1635 t = rlc_decipher_tvb(tvb, pinfo, (frame_num[indx+1] | seq),16,!fpinf->is_uplink,header_size);
1636 }else{
1637 t = rlc_decipher_tvb(tvb, pinfo, ((ps_counter[rlcinf->rbid[pos]][indx]) | seq),16,!fpinf->is_uplink,header_size);
1639 }else{
1640 if(tree){
1641 /*We need to find the original counter value for second dissection pass*/
1642 uint32_t frame_num[3];
1643 frame_num[0] = pinfo->num;
1644 g_tree_foreach(counter_map, (GTraverseFunc)rlc_find_old_counter, &frame_num[0]);
1645 t = rlc_decipher_tvb(tvb, pinfo, (frame_num[indx+1] | seq),rlcinf->rbid[pos],!fpinf->is_uplink,header_size);
1646 }else
1647 t = rlc_decipher_tvb(tvb, pinfo, ((ps_counter[rlcinf->rbid[pos]][indx]) | seq),rlcinf->rbid[pos],!fpinf->is_uplink,header_size);
1650 /*Update the hyperframe number*/
1651 if(seq == 4095){
1653 ps_counter[rlcinf->rbid[pos]][indx] += 1 << hfn_shift;
1655 if(!tree){/*Preserve counter for second packet analysis run*/
1656 uint32_t * ciph;
1657 ciph = g_new(uint32_t, 2);
1658 ciph[0] = ps_counter[rlcinf->rbid[pos]][0];
1659 ciph[1] = ps_counter[rlcinf->rbid[pos]][1];
1660 g_tree_insert(counter_map, GINT_TO_POINTER((int)pinfo->num+1), ciph);
1664 /*Unable to decipher the packet*/
1665 if(t == NULL){
1666 /* Choosing the right field text ("LIs & Data" or just "Data") based on extension bit / header extension */
1667 ext = tvb_get_uint8(tvb, header_size - 1) & 0x01;
1668 ciphered_data_hf = (ext == 1) ? hf_rlc_ciphered_lis_data : hf_rlc_ciphered_data;
1669 /* Adding ciphered payload field to tree */
1670 proto_tree_add_item(tree, ciphered_data_hf, tvb, header_size, -1, ENC_NA);
1671 proto_tree_add_expert(tree, pinfo, &ei_rlc_ciphered_data, tvb, header_size, -1);
1672 col_append_str(pinfo->cinfo, COL_INFO, "[Ciphered Data]");
1673 return;
1675 }else{
1676 col_append_str(pinfo->cinfo, COL_INFO, "[Deciphered Data]");
1678 /*TODO: Old tvb should be freed here?*/
1683 static void
1684 dissect_rlc_tm(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
1685 proto_tree *top_level, proto_tree *tree)
1687 fp_info *fpinf;
1688 rlc_info *rlcinf;
1690 fpinf = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
1691 rlcinf = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
1693 if (tree) {
1694 if (fpinf && rlcinf) {
1695 /* Add "channel" information, very useful for debugging. */
1696 add_channel_info(pinfo, tree, fpinf, rlcinf);
1698 proto_tree_add_item(tree, hf_rlc_data, tvb, 0, -1, ENC_NA);
1700 rlc_call_subdissector(channel, tvb, pinfo, top_level);
1704 static void
1705 rlc_um_reassemble(tvbuff_t *tvb, uint16_t offs, packet_info *pinfo, proto_tree *tree,
1706 proto_tree *top_level, enum rlc_channel_type channel, uint16_t seq,
1707 struct rlc_li *li, uint16_t num_li, bool li_is_on_2_bytes,
1708 struct atm_phdr *atm)
1710 uint8_t i;
1711 bool dissected = false;
1712 int length;
1713 tvbuff_t *next_tvb = NULL;
1715 /* perform reassembly now */
1716 for (i = 0; i < num_li; i++) {
1717 if ((!li_is_on_2_bytes && (li[i].li == 0x7f)) || (li[i].li == 0x7fff)) {
1718 /* padding, must be last LI */
1719 if (tree) {
1720 proto_tree_add_item(tree, hf_rlc_pad, tvb, offs, tvb_captured_length_remaining(tvb, offs), ENC_NA);
1722 offs += tvb_captured_length_remaining(tvb, offs);
1723 } else if ((!li_is_on_2_bytes && (li[i].li == 0x7c)) || (li[i].li == 0x7ffc)) {
1724 /* a new SDU starts here, mark this seq as the first PDU. */
1725 struct rlc_channel ch_lookup;
1726 struct rlc_seqlist * endlist = NULL;
1727 if( -1 != rlc_channel_assign(&ch_lookup, RLC_UM, pinfo, atm ) ){
1728 endlist = get_endlist(pinfo, &ch_lookup, atm);
1729 endlist->list->data = GINT_TO_POINTER((int)seq);
1730 endlist->fail_packet=0;
1733 } else if (li[i].li == 0x7ffa) {
1734 /* the first data octet in this RLC PDU is the first octet of an RLC SDU
1735 and the second last octet in this RLC PDU is the last octet of the same RLC SDU */
1736 length = tvb_reported_length_remaining(tvb, offs);
1737 if (length > 1) {
1738 length--;
1739 if (tree && length) {
1740 proto_tree_add_item(tree, hf_rlc_data, tvb, offs, length, ENC_NA);
1742 if (global_rlc_perform_reassemby) {
1743 add_fragment(RLC_UM, tvb, pinfo, li[i].tree, offs, seq, i, length, true, atm);
1744 next_tvb = get_reassembled_data(RLC_UM, tvb, pinfo, tree, seq, i, atm);
1746 offs += length;
1748 if (tree) {
1749 proto_tree_add_item(tree, hf_rlc_pad, tvb, offs, 1, ENC_NA);
1751 offs += 1;
1752 } else {
1753 if (tree && li[i].len) {
1754 proto_tree_add_item(tree, hf_rlc_data, tvb, offs, li[i].len, ENC_NA);
1756 if (global_rlc_perform_reassemby) {
1757 add_fragment(RLC_UM, tvb, pinfo, li[i].tree, offs, seq, i, li[i].len, true, atm);
1758 next_tvb = get_reassembled_data(RLC_UM, tvb, pinfo, tree, seq, i, atm);
1761 if (next_tvb) {
1762 dissected = true;
1763 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
1764 next_tvb = NULL;
1766 offs += li[i].len;
1769 /* is there data left? */
1770 if (tvb_reported_length_remaining(tvb, offs) > 0) {
1771 if (tree) {
1772 proto_tree_add_item(tree, hf_rlc_data, tvb, offs, -1, ENC_NA);
1774 if (global_rlc_perform_reassemby) {
1775 /* add remaining data as fragment */
1776 add_fragment(RLC_UM, tvb, pinfo, tree, offs, seq, i, tvb_captured_length_remaining(tvb, offs), false, atm);
1777 if (dissected == false)
1778 col_set_str(pinfo->cinfo, COL_INFO, "[RLC UM Fragment]");
1781 if (dissected == false)
1782 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Fragment] SN=%u", seq);
1783 else
1784 if (channel == RLC_UNKNOWN_CH)
1785 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Data] SN=%u", seq);
1788 static int16_t
1789 rlc_decode_li(enum rlc_mode mode, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1790 struct rlc_li *li, uint8_t max_li, bool li_on_2_bytes)
1792 uint32_t hdr_len, offs = 0, li_offs;
1793 uint8_t ext, num_li = 0;
1794 uint16_t next_bytes, prev_li = 0;
1795 proto_item *malformed;
1796 uint16_t total_len;
1798 switch (mode) {
1799 case RLC_AM:
1800 offs = 1;
1801 break;
1802 case RLC_UM:
1803 offs = 0;
1804 break;
1805 case RLC_TM:
1806 /* fall through */
1807 case RLC_UNKNOWN_MODE:
1808 default:
1809 return -1;
1811 hdr_len = offs;
1812 /* calculate header length */
1813 ext = tvb_get_uint8(tvb, hdr_len++) & 0x01;
1814 while (ext) {
1815 next_bytes = li_on_2_bytes ? tvb_get_ntohs(tvb, hdr_len) : tvb_get_uint8(tvb, hdr_len);
1816 ext = next_bytes & 0x01;
1817 hdr_len += li_on_2_bytes ? 2 : 1;
1819 total_len = tvb_captured_length_remaining(tvb, hdr_len);
1821 /* do actual evaluation of LIs */
1822 ext = tvb_get_uint8(tvb, offs++) & 0x01;
1823 li_offs = offs;
1824 while (ext) {
1825 if (li_on_2_bytes) {
1826 next_bytes = tvb_get_ntohs(tvb, offs);
1827 offs += 2;
1828 } else {
1829 next_bytes = tvb_get_uint8(tvb, offs++);
1831 ext = next_bytes & 0x01;
1832 li[num_li].ext = ext;
1833 li[num_li].li = next_bytes >> 1;
1835 if (li_on_2_bytes) {
1836 switch (li[num_li].li) {
1837 case 0x0000: /* previous segment was the last one */
1838 case 0x7ffb: /* previous PDU contains last segment of SDU (minus last byte) */
1839 case 0x7ffe: /* contains piggybacked STATUS in AM or segment in UM */
1840 case 0x7fff: /* padding */
1841 li[num_li].len = 0;
1842 break;
1843 case 0x7ffa: /* contains exactly one SDU (minus last byte), UM only */
1844 case 0x7ffc: /* start of a new SDU, UM only */
1845 case 0x7ffd: /* contains exactly one SDU, UM only */
1846 li[num_li].len = 0;
1847 if (mode == RLC_UM) {
1848 /* valid for UM */
1849 break;
1851 /*invalid for AM */
1852 /* add malformed LI for investigation */
1853 malformed = tree_add_li(mode, &li[num_li], num_li, li_offs, li_on_2_bytes, tvb, tree);
1854 expert_add_info(pinfo, malformed, &ei_rlc_li_reserved);
1855 return -1; /* just give up on this */
1856 default:
1857 /* since the LI is an offset (from the end of the header), it
1858 * may not be larger than the total remaining length and no
1859 * LI may be smaller than its preceding one
1861 if (((li[num_li].li > total_len) && !global_rlc_headers_expected)
1862 || (li[num_li].li < prev_li)) {
1863 /* add malformed LI for investigation */
1864 li[num_li].len = 0;
1865 malformed = tree_add_li(mode, &li[num_li], num_li, li_offs, li_on_2_bytes, tvb, tree);
1866 expert_add_info(pinfo, malformed, &ei_rlc_li_incorrect_warn);
1867 return -1; /* just give up on this */
1869 li[num_li].len = li[num_li].li - prev_li;
1870 prev_li = li[num_li].li;
1872 } else {
1873 switch (li[num_li].li) {
1874 case 0x00: /* previous segment was the last one */
1875 case 0x7e: /* contains piggybacked STATUS in AM or segment in UM */
1876 case 0x7f: /* padding */
1877 li[num_li].len = 0;
1878 break;
1879 case 0x7c: /* start of a new SDU, UM only */
1880 case 0x7d: /* contains exactly one SDU, UM only */
1881 li[num_li].len = 0;
1882 if (mode == RLC_UM) {
1883 /* valid for UM */
1884 break;
1886 /*invalid for AM */
1887 /* add malformed LI for investigation */
1888 malformed = tree_add_li(mode, &li[num_li], num_li, li_offs, li_on_2_bytes, tvb, tree);
1889 expert_add_info(pinfo, malformed, &ei_rlc_li_reserved);
1890 return -1; /* just give up on this */
1891 default:
1892 /* since the LI is an offset (from the end of the header), it
1893 * may not be larger than the total remaining length and no
1894 * LI may be smaller than its preceding one
1896 li[num_li].len = li[num_li].li - prev_li;
1897 if (((li[num_li].li > total_len) && !global_rlc_headers_expected)
1898 || (li[num_li].li < prev_li)) {
1899 /* add malformed LI for investigation */
1900 li[num_li].len = 0;
1901 malformed = tree_add_li(mode, &li[num_li], num_li, li_offs, li_on_2_bytes, tvb, tree);
1902 expert_add_info_format(pinfo, malformed, &ei_rlc_li_incorrect_mal, "Incorrect LI value 0x%x", li[num_li].li);
1903 return -1; /* just give up on this */
1905 prev_li = li[num_li].li;
1908 li[num_li].tree = tree_add_li(mode, &li[num_li], num_li, li_offs, li_on_2_bytes, tvb, tree);
1909 num_li++;
1911 if (num_li >= max_li) {
1912 /* OK, so this is not really a malformed packet, but for now,
1913 * we will treat it as such, so that it is marked in some way */
1914 expert_add_info(pinfo, li[num_li-1].tree, &ei_rlc_li_too_many);
1915 return -1;
1918 return num_li;
1921 static void
1922 dissect_rlc_um(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
1923 proto_tree *top_level, proto_tree *tree, struct atm_phdr *atm)
1925 #define MAX_LI 16
1926 struct rlc_li li[MAX_LI];
1927 fp_info *fpinf;
1928 rlc_info *rlcinf;
1929 uint32_t orig_num;
1930 uint8_t seq;
1931 uint8_t ext;
1932 uint8_t next_byte;
1933 uint16_t offs = 0;
1934 int16_t cur_tb, num_li = 0;
1935 bool is_truncated, li_is_on_2_bytes;
1936 proto_item *truncated_ti;
1937 bool ciphered_according_to_rrc = false;
1938 bool ciphered_flag = false;
1939 bool deciphered_flag = false;
1940 int ciphered_data_hf;
1943 next_byte = tvb_get_uint8(tvb, offs++);
1944 seq = next_byte >> 1;
1946 fpinf = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
1947 rlcinf = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
1949 if (tree) {
1950 if (fpinf && rlcinf) {
1951 /* Add "channel" information, very useful for debugging. */
1952 add_channel_info(pinfo, tree, fpinf, rlcinf);
1954 /* show sequence number and extension bit */
1955 proto_tree_add_bits_item(tree, hf_rlc_seq, tvb, 0, 7, ENC_BIG_ENDIAN);
1956 proto_tree_add_bits_item(tree, hf_rlc_ext, tvb, 7, 1, ENC_BIG_ENDIAN);
1959 if (!fpinf || !rlcinf) {
1960 proto_tree_add_expert(tree, pinfo, &ei_rlc_no_per_frame_data, tvb, 0, -1);
1961 return;
1964 cur_tb = fpinf->cur_tb;
1965 ciphered_according_to_rrc = is_ciphered_according_to_rrc(pinfo, fpinf, rlcinf, (uint16_t)seq);
1966 ciphered_flag = rlcinf->ciphered[cur_tb];
1967 deciphered_flag = rlcinf->deciphered[cur_tb];
1968 if (((ciphered_according_to_rrc || ciphered_flag) && !deciphered_flag) || global_rlc_ciphered) {
1969 if(global_rlc_try_decipher){
1970 rlc_decipher(tvb, pinfo, tree, fpinf, rlcinf, seq, RLC_UM);
1971 }else{
1972 /* Choosing the right field text ("LIs & Data" or just "Data") based on extension bit */
1973 ext = tvb_get_uint8(tvb, 0) & 0x01;
1974 ciphered_data_hf = (ext == 1) ? hf_rlc_ciphered_lis_data : hf_rlc_ciphered_data;
1975 /* Adding ciphered payload field to tree */
1976 proto_tree_add_item(tree, ciphered_data_hf, tvb, offs, -1, ENC_NA);
1977 proto_tree_add_expert(tree, pinfo, &ei_rlc_ciphered_data, tvb, offs, -1);
1978 col_append_str(pinfo->cinfo, COL_INFO, "[Ciphered Data]");
1979 return;
1983 if (global_rlc_li_size == RLC_LI_UPPERLAYER) {
1984 if (rlcinf->li_size[cur_tb] == RLC_LI_VARIABLE) {
1985 li_is_on_2_bytes = (tvb_reported_length(tvb) > 125) ? true : false;
1986 } else {
1987 li_is_on_2_bytes = (rlcinf->li_size[cur_tb] == RLC_LI_15BITS) ? true : false;
1989 } else { /* Override rlcinf configuration with preference. */
1990 li_is_on_2_bytes = (global_rlc_li_size == RLC_LI_15BITS) ? true : false;
1995 num_li = rlc_decode_li(RLC_UM, tvb, pinfo, tree, li, MAX_LI, li_is_on_2_bytes);
1996 if (num_li == -1) return; /* something went wrong */
1997 offs += ((li_is_on_2_bytes) ? 2 : 1) * num_li;
1999 if (global_rlc_headers_expected) {
2000 /* There might not be any data, if only header was logged */
2001 is_truncated = (tvb_captured_length_remaining(tvb, offs) == 0);
2002 truncated_ti = proto_tree_add_boolean(tree, hf_rlc_header_only, tvb, 0, 0,
2003 is_truncated);
2004 if (is_truncated) {
2005 proto_item_set_generated(truncated_ti);
2006 expert_add_info(pinfo, truncated_ti, &ei_rlc_header_only);
2007 return;
2008 } else {
2009 proto_item_set_hidden(truncated_ti);
2013 /* do not detect duplicates or reassemble, if prefiltering is done */
2014 if (pinfo->num == 0) return;
2015 /* check for duplicates */
2016 if (rlc_is_duplicate(RLC_UM, pinfo, seq, &orig_num, atm) == true) {
2017 col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC UM Fragment] [Duplicate] SN=%u", seq);
2018 proto_tree_add_uint(tree, hf_rlc_duplicate_of, tvb, 0, 0, orig_num);
2019 return;
2021 rlc_um_reassemble(tvb, offs, pinfo, tree, top_level, channel, seq, li, num_li, li_is_on_2_bytes, atm);
2024 static void
2025 dissect_rlc_status(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, uint16_t offset)
2027 uint8_t sufi_type, bits;
2028 uint64_t len, sn, wsn, lsn, l;
2029 uint16_t value, previous_sn;
2030 bool isErrorBurstInd;
2031 int bit_offset, previous_bit_offset;
2032 unsigned i, j;
2033 proto_tree *sufi_tree, *bitmap_tree, *rlist_tree;
2034 proto_item *sufi_item, *ti;
2035 #define BUFF_SIZE 41
2036 char *buff = NULL;
2037 uint8_t cw[15];
2038 uint8_t sufi_start_offset;
2039 bool seen_last = false;
2040 uint16_t number_of_bitmap_entries = 0;
2042 bit_offset = offset*8 + 4; /* first SUFI type is always 4 bit shifted */
2044 while (!seen_last && tvb_reported_length_remaining(tvb, bit_offset/8) > 0) {
2045 /* SUFI */
2046 sufi_type = tvb_get_bits8(tvb, bit_offset, 4);
2047 sufi_start_offset = bit_offset/8;
2048 sufi_item = proto_tree_add_item(tree, hf_rlc_sufi, tvb, sufi_start_offset, 0, ENC_NA);
2049 sufi_tree = proto_item_add_subtree(sufi_item, ett_rlc_sufi);
2050 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_type, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
2051 proto_item_append_text(sufi_item, " (%s)", val_to_str_const(sufi_type, rlc_sufi_vals, "Unknown"));
2052 bit_offset += 4;
2053 switch (sufi_type) {
2054 case RLC_SUFI_NOMORE:
2055 seen_last = true;
2056 break;
2057 case RLC_SUFI_ACK:
2058 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_lsn, tvb, bit_offset, 12, &lsn, ENC_BIG_ENDIAN);
2059 col_append_fstr(pinfo->cinfo, COL_INFO, " LSN=%u", (uint16_t)lsn);
2060 proto_item_append_text(sufi_item, " LSN=%u", (uint16_t)lsn);
2061 bit_offset += 12;
2062 seen_last = true;
2063 break;
2064 case RLC_SUFI_WINDOW:
2065 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_wsn, tvb, bit_offset, 12, &wsn, ENC_BIG_ENDIAN);
2066 col_append_fstr(pinfo->cinfo, COL_INFO, " WSN=%u", (uint16_t)wsn);
2067 bit_offset += 12;
2068 break;
2069 case RLC_SUFI_LIST:
2070 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_len, tvb, bit_offset, 4, &len, ENC_BIG_ENDIAN);
2071 col_append_fstr(pinfo->cinfo, COL_INFO, " LIST(%u) - ", (uint8_t)len);
2072 bit_offset += 4;
2073 if (len) {
2074 while (len) {
2075 ti = proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_sn, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2076 proto_item_append_text(ti, " (AMD PDU not correctly received)");
2077 bit_offset += 12;
2078 ti = proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_l, tvb, bit_offset, 4, &l, ENC_BIG_ENDIAN);
2079 if (l) {
2080 proto_item_append_text(ti, " (all consecutive AMD PDUs up to SN %u not correctly received)",
2081 (unsigned)(sn+l)&0xfff);
2082 col_append_fstr(pinfo->cinfo, COL_INFO, "%u-%u ", (uint16_t)sn, (unsigned)(sn+l)&0xfff);
2084 else {
2085 col_append_fstr(pinfo->cinfo, COL_INFO, "%u ", (uint16_t)sn);
2087 bit_offset += 4;
2088 len--;
2090 } else {
2091 expert_add_info(pinfo, tree, &ei_rlc_sufi_len);
2093 break;
2094 case RLC_SUFI_BITMAP:
2095 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_len, tvb, bit_offset, 4, &len, ENC_BIG_ENDIAN);
2096 bit_offset += 4;
2097 len++; /* bitmap is len + 1 */
2098 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_fsn, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2099 bit_offset += 12;
2100 proto_tree_add_item(sufi_tree, hf_rlc_sufi_bitmap, tvb, bit_offset/8, (int)len, ENC_NA);
2101 bitmap_tree = proto_tree_add_subtree(sufi_tree, tvb, bit_offset/8, (int)len, ett_rlc_bitmap, &ti, "Decoded bitmap:");
2102 col_append_str(pinfo->cinfo, COL_INFO, " BITMAP=(");
2104 buff = (char *)wmem_alloc(pinfo->pool, BUFF_SIZE);
2105 for (i=0; i<len; i++) {
2106 bits = tvb_get_bits8(tvb, bit_offset, 8);
2107 for (l=0, j=0; l<8; l++) {
2108 if ((bits << l) & 0x80) {
2109 j += snprintf(&buff[j], BUFF_SIZE-j, "%4u,", (unsigned)(sn+(8*i)+l)&0xfff);
2110 col_append_fstr(pinfo->cinfo, COL_INFO, " %u", (unsigned)(sn+(8*i)+l)&0xfff);
2111 number_of_bitmap_entries++;
2112 } else {
2113 j += snprintf(&buff[j], BUFF_SIZE-j, " ,");
2116 proto_tree_add_string_format(bitmap_tree, hf_rlc_bitmap_string, tvb, bit_offset/8, 1, buff, "%s", buff);
2117 bit_offset += 8;
2119 proto_item_append_text(ti, " (%u SNs)", number_of_bitmap_entries);
2120 col_append_str(pinfo->cinfo, COL_INFO, " )");
2121 break;
2122 case RLC_SUFI_RLIST:
2123 previous_bit_offset = bit_offset;
2124 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_len, tvb, bit_offset, 4, &len, ENC_BIG_ENDIAN);
2125 bit_offset += 4;
2126 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_fsn, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2127 bit_offset += 12;
2128 proto_item_append_text(sufi_item, " (%u codewords)", (uint16_t)len);
2130 for (i=0; i<len; i++) {
2131 ti = proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_cw, tvb, bit_offset, 4, &l, ENC_BIG_ENDIAN);
2132 if (l == 0x01) {
2133 proto_item_append_text(ti, " (Error burst indication)");
2135 bit_offset += 4;
2136 cw[i] = (uint8_t)l;
2138 if (len && (((cw[len-1] & 0x01) == 0) || (cw[len-1] == 0x01))) {
2139 expert_add_info(pinfo, tree, &ei_rlc_sufi_cw);
2140 } else {
2141 rlist_tree = proto_tree_add_subtree(sufi_tree, tvb, previous_bit_offset/8, (bit_offset-previous_bit_offset)/8, ett_rlc_rlist, NULL, "Decoded list:");
2142 proto_tree_add_uint_format_value(rlist_tree, hf_rlc_sequence_number, tvb, (previous_bit_offset+4)/8, 12/8, (uint32_t)sn, "%u (AMD PDU not correctly received)", (unsigned)sn);
2143 col_append_fstr(pinfo->cinfo, COL_INFO, " RLIST=(%u", (unsigned)sn);
2145 for (i=0, isErrorBurstInd=false, j=0, previous_sn=(uint16_t)sn, value=0; i<len; i++) {
2146 if (cw[i] == 0x01) {
2147 isErrorBurstInd = true;
2148 } else {
2149 value |= (cw[i] >> 1) << j;
2150 j += 3;
2151 if (cw[i] & 0x01) {
2152 if (isErrorBurstInd) {
2153 previous_sn = (previous_sn + value) & 0xfff;
2154 ti = proto_tree_add_uint(rlist_tree, hf_rlc_length, tvb, (previous_bit_offset+16+4*i)/8, 1, value);
2155 if (value) {
2156 proto_item_append_text(ti, " (all consecutive AMD PDUs up to SN %u not correctly received)", previous_sn);
2157 col_append_fstr(pinfo->cinfo, COL_INFO, " ->%u", previous_sn);
2159 isErrorBurstInd = false;
2160 } else {
2161 value = (value + previous_sn) & 0xfff;
2162 proto_tree_add_uint_format_value(rlist_tree, hf_rlc_sequence_number, tvb, (previous_bit_offset+16+4*i)/8, 1, value, "%u (AMD PDU not correctly received)",value);
2163 col_append_fstr(pinfo->cinfo, COL_INFO, " %u", value);
2164 previous_sn = value;
2166 value = j = 0;
2170 col_append_str(pinfo->cinfo, COL_INFO, ")");
2172 break;
2173 case RLC_SUFI_MRW_ACK:
2174 col_append_str(pinfo->cinfo, COL_INFO, " MRW-ACK");
2175 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_n, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
2176 bit_offset += 4;
2177 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_sn_ack, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2178 bit_offset += 12;
2179 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u", (uint16_t)sn);
2180 break;
2181 case RLC_SUFI_MRW:
2182 col_append_str(pinfo->cinfo, COL_INFO, " MRW");
2183 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_len, tvb, bit_offset, 4, &len, ENC_BIG_ENDIAN);
2184 bit_offset += 4;
2185 if (len) {
2186 while (len) {
2187 proto_tree_add_bits_ret_val(sufi_tree, hf_rlc_sufi_sn_mrw, tvb, bit_offset, 12, &sn, ENC_BIG_ENDIAN);
2188 col_append_fstr(pinfo->cinfo, COL_INFO, " SN=%u", (uint16_t)sn);
2189 bit_offset += 12;
2190 len--;
2192 } else {
2193 /* only one SN_MRW field is present */
2194 ti = proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_sn_mrw, tvb, bit_offset, 12, ENC_BIG_ENDIAN);
2195 proto_item_append_text(ti, " (RLC SDU to be discarded in the Receiver extends above the configured transmission window in the Sender)");
2196 bit_offset += 12;
2198 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_n, tvb, bit_offset, 4, ENC_BIG_ENDIAN);
2199 bit_offset += 4;
2200 break;
2201 case RLC_SUFI_POLL:
2202 proto_tree_add_bits_item(sufi_tree, hf_rlc_sufi_poll_sn, tvb, bit_offset, 12, ENC_BIG_ENDIAN);
2203 bit_offset += 12;
2204 break;
2206 default:
2207 expert_add_info(pinfo, tree, &ei_rlc_sufi_type);
2208 return; /* invalid value, ignore the rest */
2211 /* Set extent of SUFI root */
2212 proto_item_set_len(sufi_item, ((bit_offset+7)/8) - sufi_start_offset);
2216 static void
2217 dissect_rlc_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2219 uint8_t type, next_byte;
2220 proto_item *ti;
2221 uint64_t r1;
2222 uint64_t rsn, hfn;
2224 next_byte = tvb_get_uint8(tvb, 0);
2225 type = (next_byte >> 4) & 0x07;
2227 ti = proto_tree_add_bits_item(tree, hf_rlc_ctrl_type, tvb, 1, 3, ENC_BIG_ENDIAN);
2228 switch (type) {
2229 case RLC_STATUS:
2230 dissect_rlc_status(tvb, pinfo, tree, 0);
2231 break;
2232 case RLC_RESET:
2233 case RLC_RESET_ACK:
2234 col_append_str(pinfo->cinfo, COL_INFO, (type == RLC_RESET) ? " RESET" : " RESET-ACK");
2235 proto_tree_add_bits_ret_val(tree, hf_rlc_rsn, tvb, 4, 1, &rsn, ENC_BIG_ENDIAN);
2236 proto_tree_add_bits_ret_val(tree, hf_rlc_r1, tvb, 5, 3, &r1, ENC_BIG_ENDIAN);
2237 if (r1) {
2238 expert_add_info(pinfo, ti, &ei_rlc_reserved_bits_not_zero);
2239 return;
2241 proto_tree_add_bits_ret_val(tree, hf_rlc_hfni, tvb, 8, 20, &hfn, ENC_BIG_ENDIAN);
2242 col_append_fstr(pinfo->cinfo, COL_INFO, " RSN=%u HFN=%u", (uint16_t)rsn, (uint32_t)hfn);
2243 break;
2244 default:
2245 expert_add_info_format(pinfo, ti, &ei_rlc_ctrl_type, "Invalid RLC AM control type %u", type);
2246 return; /* invalid */
2250 static void
2251 rlc_am_reassemble(tvbuff_t *tvb, uint16_t offs, packet_info *pinfo,
2252 proto_tree *tree, proto_tree *top_level,
2253 enum rlc_channel_type channel, uint16_t seq, bool poll_set, struct rlc_li *li,
2254 uint16_t num_li, bool final, bool li_is_on_2_bytes,
2255 struct atm_phdr *atm)
2257 uint8_t i;
2258 bool piggyback = false, dissected = false;
2259 tvbuff_t *next_tvb = NULL;
2261 struct rlc_channel ch_lookup;
2262 struct rlc_seqlist * endlist = NULL;
2263 if( 0 == seq ){ /* assuming that a new RRC Connection is established when 0==seq. */
2264 if( -1 != rlc_channel_assign(&ch_lookup, RLC_AM, pinfo, atm ) ){
2265 endlist = get_endlist(pinfo, &ch_lookup, atm);
2266 endlist->list->data = GINT_TO_POINTER( -1);
2270 /* perform reassembly now */
2271 for (i = 0; i < num_li; i++) {
2272 if ((!li_is_on_2_bytes && (li[i].li == 0x7e)) || (li[i].li == 0x7ffe)) {
2273 /* piggybacked status */
2274 piggyback = true;
2275 } else if ((!li_is_on_2_bytes && (li[i].li == 0x7f)) || (li[i].li == 0x7fff)) {
2276 /* padding, must be last LI */
2277 if (tvb_reported_length_remaining(tvb, offs) > 0) {
2278 if (tree) {
2279 proto_tree_add_item(tree, hf_rlc_pad, tvb, offs, -1, ENC_NA);
2281 if (i == 0) {
2282 /* Insert empty RLC frag so RLC doesn't miss this seq number. */
2283 add_fragment(RLC_AM, tvb, pinfo, li[i].tree, offs, seq, i, 0, true, atm);
2286 offs += tvb_captured_length_remaining(tvb, offs);
2287 } else {
2288 if (tree) {
2289 proto_tree_add_item(tree, hf_rlc_data, tvb, offs, li[i].len, ENC_NA);
2291 if (global_rlc_perform_reassemby) {
2292 add_fragment(RLC_AM, tvb, pinfo, li[i].tree, offs, seq, i, li[i].len, true, atm);
2293 next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, tree, seq, i, atm);
2296 if (next_tvb) {
2297 dissected = true;
2298 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
2299 next_tvb = NULL;
2301 offs += li[i].len;
2304 if (piggyback) {
2305 dissect_rlc_status(tvb, pinfo, tree, offs);
2306 } else {
2307 if (tvb_reported_length_remaining(tvb, offs) > 0) {
2308 /* we have remaining data, which we need to mark in the tree */
2309 if (tree) {
2310 proto_tree_add_item(tree, hf_rlc_data, tvb, offs, -1, ENC_NA);
2312 if (global_rlc_perform_reassemby) {
2313 add_fragment(RLC_AM, tvb, pinfo, tree, offs, seq, i,
2314 tvb_captured_length_remaining(tvb,offs), final, atm);
2315 if (final) {
2316 next_tvb = get_reassembled_data(RLC_AM, tvb, pinfo, tree, seq, i, atm);
2320 if (next_tvb) {
2321 dissected = true;
2322 rlc_call_subdissector(channel, next_tvb, pinfo, top_level);
2323 next_tvb = NULL;
2326 if (dissected == false)
2327 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] SN=%u %s",
2328 seq, poll_set ? "(P)" : "");
2329 else
2330 if (channel == RLC_UNKNOWN_CH)
2331 col_append_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Data] SN=%u %s",
2332 seq, poll_set ? "(P)" : "");
2335 static void
2336 dissect_rlc_am(enum rlc_channel_type channel, tvbuff_t *tvb, packet_info *pinfo,
2337 proto_tree *top_level, proto_tree *tree, struct atm_phdr *atm)
2339 #define MAX_LI 16
2340 struct rlc_li li[MAX_LI];
2341 fp_info *fpinf;
2342 rlc_info *rlcinf;
2343 uint8_t ext, dc;
2344 uint8_t next_byte;
2345 uint32_t orig_num = 0;
2346 int16_t num_li = 0;
2347 int16_t cur_tb;
2348 uint16_t seq, offs = 0;
2349 bool is_truncated, li_is_on_2_bytes;
2350 proto_item *truncated_ti, *ti;
2351 uint64_t polling;
2352 bool ciphered_according_to_rrc = false;
2353 bool ciphered_flag = false;
2354 bool deciphered_flag = false;
2355 int ciphered_data_hf;
2357 fpinf = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2358 rlcinf = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
2360 next_byte = tvb_get_uint8(tvb, offs++);
2361 dc = next_byte >> 7;
2362 if (tree) {
2363 if (fpinf && rlcinf) {
2364 /* Add "channel" information, very useful for debugging. */
2365 add_channel_info(pinfo, tree, fpinf, rlcinf);
2367 proto_tree_add_bits_item(tree, hf_rlc_dc, tvb, 0, 1, ENC_BIG_ENDIAN);
2369 if (dc == 0) {
2370 col_set_str(pinfo->cinfo, COL_INFO, "[RLC Control Frame]");
2371 dissect_rlc_control(tvb, pinfo, tree);
2372 return;
2375 seq = next_byte & 0x7f;
2376 seq <<= 5;
2377 next_byte = tvb_get_uint8(tvb, offs++);
2378 seq |= (next_byte >> 3);
2380 ext = next_byte & 0x03;
2381 /* show header fields */
2382 proto_tree_add_bits_item(tree, hf_rlc_seq, tvb, 1, 12, ENC_BIG_ENDIAN);
2383 proto_tree_add_bits_ret_val(tree, hf_rlc_p, tvb, 13, 1, &polling, ENC_BIG_ENDIAN);
2384 ti = proto_tree_add_bits_item(tree, hf_rlc_he, tvb, 14, 2, ENC_BIG_ENDIAN);
2386 /* header extension may only be 00, 01 or 10 */
2387 if (ext > 2) {
2388 expert_add_info(pinfo, ti, &ei_rlc_he);
2389 return;
2392 if (!fpinf || !rlcinf) {
2393 proto_tree_add_expert(tree, pinfo, &ei_rlc_no_per_frame_data, tvb, 0, -1);
2394 return;
2397 cur_tb = fpinf->cur_tb;
2399 * WARNING DECIPHERING IS HIGHLY EXPERIMENTAL!!!
2400 * */
2401 ciphered_according_to_rrc = is_ciphered_according_to_rrc(pinfo, fpinf, rlcinf, (uint16_t)seq);
2402 ciphered_flag = rlcinf->ciphered[cur_tb];
2403 deciphered_flag = rlcinf->deciphered[cur_tb];
2404 if (((ciphered_according_to_rrc || ciphered_flag) && !deciphered_flag) || global_rlc_ciphered) {
2405 if(global_rlc_try_decipher){
2406 rlc_decipher(tvb, pinfo, tree, fpinf, rlcinf, seq, RLC_AM);
2407 }else{
2408 /* Choosing the right field text ("LIs & Data" or just "Data") based on header extension field */
2409 ciphered_data_hf = (ext == 0x01) ? hf_rlc_ciphered_lis_data : hf_rlc_ciphered_data;
2410 /* Adding ciphered payload field to tree */
2411 proto_tree_add_item(tree, ciphered_data_hf, tvb, offs, -1, ENC_NA);
2412 proto_tree_add_expert(tree, pinfo, &ei_rlc_ciphered_data, tvb, offs, -1);
2413 col_append_str(pinfo->cinfo, COL_INFO, "[Ciphered Data]");
2414 return;
2418 if (global_rlc_li_size == RLC_LI_UPPERLAYER) {
2419 if (rlcinf->li_size[cur_tb] == RLC_LI_VARIABLE) {
2420 li_is_on_2_bytes = (tvb_reported_length(tvb) > 126) ? true : false;
2421 } else {
2422 li_is_on_2_bytes = (rlcinf->li_size[cur_tb] == RLC_LI_15BITS) ? true : false;
2424 } else { /* Override rlcinf configuration with preference. */
2425 li_is_on_2_bytes = (global_rlc_li_size == RLC_LI_15BITS) ? true : false;
2428 num_li = rlc_decode_li(RLC_AM, tvb, pinfo, tree, li, MAX_LI, li_is_on_2_bytes);
2429 if (num_li == -1) return; /* something went wrong */
2430 offs += ((li_is_on_2_bytes) ? 2 : 1) * num_li;
2431 if (global_rlc_headers_expected) {
2432 /* There might not be any data, if only header was logged */
2433 is_truncated = (tvb_captured_length_remaining(tvb, offs) == 0);
2434 truncated_ti = proto_tree_add_boolean(tree, hf_rlc_header_only, tvb, 0, 0,
2435 is_truncated);
2436 if (is_truncated) {
2437 proto_item_set_generated(truncated_ti);
2438 expert_add_info(pinfo, truncated_ti, &ei_rlc_header_only);
2439 return;
2440 } else {
2441 proto_item_set_hidden(truncated_ti);
2445 /* do not detect duplicates or reassemble, if prefiltering is done */
2446 if (pinfo->num == 0) return;
2447 /* check for duplicates, but not if already visited */
2448 if (!PINFO_FD_VISITED(pinfo) && rlc_is_duplicate(RLC_AM, pinfo, seq, &orig_num, atm) == true) {
2449 g_hash_table_insert(duplicate_table, GUINT_TO_POINTER(pinfo->num), GUINT_TO_POINTER(orig_num));
2450 return;
2451 } else if (PINFO_FD_VISITED(pinfo) && tree) {
2452 void *value = g_hash_table_lookup(duplicate_table, GUINT_TO_POINTER(pinfo->num));
2453 if (value != NULL) {
2454 col_add_fstr(pinfo->cinfo, COL_INFO, "[RLC AM Fragment] [Duplicate] SN=%u %s", seq, (polling != 0) ? "(P)" : "");
2455 proto_tree_add_uint(tree, hf_rlc_duplicate_of, tvb, 0, 0, GPOINTER_TO_UINT(value));
2456 return;
2460 rlc_am_reassemble(tvb, offs, pinfo, tree, top_level, channel, seq, polling != 0,
2461 li, num_li, ext == 2, li_is_on_2_bytes, atm);
2464 /* dissect entry functions */
2465 static int
2466 dissect_rlc_pcch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2468 proto_tree *subtree = NULL;
2470 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2471 col_clear(pinfo->cinfo, COL_INFO);
2473 /* PCCH is always RLC TM */
2474 if (tree) {
2475 proto_item *ti;
2476 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2477 subtree = proto_item_add_subtree(ti, ett_rlc);
2478 proto_item_append_text(ti, " TM (PCCH)");
2480 dissect_rlc_tm(RLC_PCCH, tvb, pinfo, tree, subtree);
2481 return tvb_captured_length(tvb);
2484 static int
2485 dissect_rlc_bcch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2487 fp_info *fpi;
2488 proto_item *ti = NULL;
2489 proto_tree *subtree = NULL;
2491 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2492 col_clear(pinfo->cinfo, COL_INFO);
2494 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2495 if (!fpi) return 0; /* dissection failure */
2497 if (tree) {
2498 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2499 subtree = proto_item_add_subtree(ti, ett_rlc);
2501 proto_item_append_text(ti, " TM (BCCH)");
2502 dissect_rlc_tm(RLC_BCCH, tvb, pinfo, tree, subtree);
2503 return tvb_captured_length(tvb);
2506 static int
2507 dissect_rlc_ccch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2509 fp_info *fpi;
2510 proto_item *ti = NULL;
2511 proto_tree *subtree = NULL;
2512 struct atm_phdr *atm = (struct atm_phdr *)data;
2514 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2515 col_clear(pinfo->cinfo, COL_INFO);
2517 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2518 if (!fpi) return 0; /* dissection failure */
2520 if (tree) {
2521 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2522 subtree = proto_item_add_subtree(ti, ett_rlc);
2525 if (fpi->is_uplink) {
2526 /* UL CCCH is always RLC TM */
2527 proto_item_append_text(ti, " TM (CCCH)");
2528 dissect_rlc_tm(RLC_UL_CCCH, tvb, pinfo, tree, subtree);
2529 } else {
2530 /* DL CCCH is always UM */
2531 proto_item_append_text(ti, " UM (CCCH)");
2532 dissect_rlc_um(RLC_DL_CCCH, tvb, pinfo, tree, subtree, atm);
2534 return tvb_captured_length(tvb);
2537 static int
2538 dissect_rlc_ctch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2540 fp_info *fpi;
2541 proto_item *ti = NULL;
2542 proto_tree *subtree = NULL;
2543 struct atm_phdr *atm = (struct atm_phdr *)data;
2545 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2546 col_clear(pinfo->cinfo, COL_INFO);
2548 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2549 if (!fpi) return 0; /* dissection failure */
2551 if (tree) {
2552 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2553 subtree = proto_item_add_subtree(ti, ett_rlc);
2556 /* CTCH is always UM */
2557 proto_item_append_text(ti, " UM (CTCH)");
2558 dissect_rlc_um(RLC_DL_CTCH, tvb, pinfo, tree, subtree, atm);
2559 return tvb_captured_length(tvb);
2562 static int
2563 dissect_rlc_dcch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2565 proto_item *ti = NULL;
2566 proto_tree *subtree = NULL;
2567 fp_info *fpi;
2568 rlc_info *rlci;
2569 enum rlc_channel_type channel;
2570 struct atm_phdr *atm = (struct atm_phdr *)data;
2572 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2573 col_clear(pinfo->cinfo, COL_INFO);
2575 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2576 rlci = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
2578 if (!fpi || !rlci){
2579 proto_tree_add_expert(tree, pinfo, &ei_rlc_no_per_frame_data, tvb, 0, -1);
2580 return 1;
2583 if (tree) {
2584 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2585 subtree = proto_item_add_subtree(ti, ett_rlc);
2588 channel = fpi->is_uplink ? RLC_UL_DCCH : RLC_DL_DCCH;
2590 switch (rlci->mode[fpi->cur_tb]) {
2591 case RLC_UM:
2592 proto_item_append_text(ti, " UM (DCCH)");
2593 dissect_rlc_um(channel, tvb, pinfo, tree, subtree, atm);
2594 break;
2595 case RLC_AM:
2596 proto_item_append_text(ti, " AM (DCCH)");
2597 dissect_rlc_am(channel, tvb, pinfo, tree, subtree, atm);
2598 break;
2600 return tvb_captured_length(tvb);
2603 static int
2604 dissect_rlc_ps_dtch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2606 proto_item *ti = NULL;
2607 proto_tree *subtree = NULL;
2608 fp_info *fpi;
2609 rlc_info *rlci;
2610 struct atm_phdr *atm = (struct atm_phdr *)data;
2612 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2613 col_clear(pinfo->cinfo, COL_INFO);
2615 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2616 rlci = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
2618 if (!fpi || !rlci) {
2619 proto_tree_add_expert(tree, pinfo, &ei_rlc_no_per_frame_data, tvb, 0, -1);
2620 return 1;
2623 if (tree) {
2624 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2625 subtree = proto_item_add_subtree(ti, ett_rlc);
2628 switch (rlci->mode[fpi->cur_tb]) {
2629 case RLC_UM:
2630 proto_item_append_text(ti, " UM (PS DTCH)");
2631 dissect_rlc_um(RLC_PS_DTCH, tvb, pinfo, tree, subtree, atm);
2632 break;
2633 case RLC_AM:
2634 proto_item_append_text(ti, " AM (PS DTCH)");
2635 dissect_rlc_am(RLC_PS_DTCH, tvb, pinfo, tree, subtree, atm);
2636 break;
2637 case RLC_TM:
2638 proto_item_append_text(ti, " TM (PS DTCH)");
2639 dissect_rlc_tm(RLC_PS_DTCH, tvb, pinfo, tree, subtree);
2640 break;
2642 return tvb_captured_length(tvb);
2645 static int
2646 dissect_rlc_dch_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2648 proto_item *ti = NULL;
2649 proto_tree *subtree = NULL;
2650 fp_info *fpi;
2651 rlc_info *rlci;
2652 struct atm_phdr *atm = (struct atm_phdr *)data;
2654 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2655 col_clear(pinfo->cinfo, COL_INFO);
2657 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2658 rlci = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
2660 if (!fpi || !rlci) return 0;
2662 if (tree) {
2663 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2664 subtree = proto_item_add_subtree(ti, ett_rlc);
2667 switch (rlci->mode[fpi->cur_tb]) {
2668 case RLC_UM:
2669 proto_item_append_text(ti, " UM (Unknown)");
2670 dissect_rlc_um(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree, atm);
2671 break;
2672 case RLC_AM:
2673 proto_item_append_text(ti, " AM (Unknown)");
2674 dissect_rlc_am(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree, atm);
2675 break;
2676 case RLC_TM:
2677 proto_item_append_text(ti, " TM (Unknown)");
2678 dissect_rlc_tm(RLC_UNKNOWN_CH, tvb, pinfo, tree, subtree);
2679 break;
2681 return tvb_captured_length(tvb);
2684 static void
2685 report_heur_error(proto_tree *tree, packet_info *pinfo, expert_field *eiindex,
2686 tvbuff_t *tvb, int start, int length)
2688 proto_item *ti;
2689 proto_tree *subtree;
2691 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2692 col_clear(pinfo->cinfo, COL_INFO);
2693 ti = proto_tree_add_item(tree, proto_umts_rlc, tvb, 0, -1, ENC_NA);
2694 subtree = proto_item_add_subtree(ti, ett_rlc);
2695 proto_tree_add_expert(subtree, pinfo, eiindex, tvb, start, length);
2698 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
2699 static bool
2700 dissect_rlc_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2702 int offset = 0;
2703 fp_info *fpi;
2704 rlc_info *rlci;
2705 tvbuff_t *rlc_tvb;
2706 uint8_t tag = 0;
2707 unsigned channelType = UMTS_CHANNEL_TYPE_UNSPECIFIED;
2708 bool fpInfoAlreadySet = false;
2709 bool rlcInfoAlreadySet = false;
2710 bool channelTypePresent = false;
2711 bool rlcModePresent = false;
2712 proto_item *ti = NULL;
2713 proto_tree *subtree = NULL;
2714 struct atm_phdr *atm = (struct atm_phdr *)data;
2716 /* Do this again on re-dissection to re-discover offset of actual PDU */
2718 /* Needs to be at least as long as:
2719 - the signature string
2720 - conditional header bytes
2721 - tag for data
2722 - at least one byte of RLC PDU payload */
2723 if (tvb_captured_length_remaining(tvb, offset) < (int)(strlen(RLC_START_STRING)+2+2)) {
2724 return false;
2727 /* OK, compare with signature string */
2728 if (tvb_strneql(tvb, offset, RLC_START_STRING, (int)strlen(RLC_START_STRING)) != 0) {
2729 return false;
2731 offset += (int)strlen(RLC_START_STRING);
2733 /* If redissecting, use previous info struct (if available) */
2734 fpi = (fp_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fp, 0);
2735 if (fpi == NULL) {
2736 /* Allocate new info struct for this frame */
2737 fpi = wmem_new0(wmem_file_scope(), fp_info);
2738 } else {
2739 fpInfoAlreadySet = true;
2741 rlci = (rlc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0);
2742 if (rlci == NULL) {
2743 /* Allocate new info struct for this frame */
2744 rlci = wmem_new0(wmem_file_scope(), rlc_info);
2745 } else {
2746 rlcInfoAlreadySet = true;
2749 /* Setting non-zero UE-ID for RLC reassembly to work, might be
2750 * overriden if the optional URNTI tag is present */
2751 rlci->ueid[fpi->cur_tb] = 1;
2753 /* Read conditional/optional fields */
2754 while (tag != RLC_PAYLOAD_TAG) {
2755 /* Process next tag */
2756 tag = tvb_get_uint8(tvb, offset++);
2757 switch (tag) {
2758 case RLC_CHANNEL_TYPE_TAG:
2759 channelType = tvb_get_uint8(tvb, offset);
2760 offset++;
2761 channelTypePresent = true;
2762 break;
2763 case RLC_MODE_TAG:
2764 rlci->mode[fpi->cur_tb] = tvb_get_uint8(tvb, offset);
2765 offset++;
2766 rlcModePresent = true;
2767 break;
2768 case RLC_DIRECTION_TAG:
2769 if (tvb_get_uint8(tvb, offset) == DIRECTION_UPLINK) {
2770 fpi->is_uplink = true;
2771 pinfo->link_dir = P2P_DIR_UL;
2772 } else {
2773 fpi->is_uplink = false;
2774 pinfo->link_dir = P2P_DIR_DL;
2776 offset++;
2777 break;
2778 case RLC_URNTI_TAG:
2779 rlci->ueid[fpi->cur_tb] = tvb_get_ntohl(tvb, offset);
2780 offset += 4;
2781 break;
2782 case RLC_RADIO_BEARER_ID_TAG:
2783 rlci->rbid[fpi->cur_tb] = tvb_get_uint8(tvb, offset);
2784 offset++;
2785 break;
2786 case RLC_LI_SIZE_TAG:
2787 rlci->li_size[fpi->cur_tb] = (enum rlc_li_size) tvb_get_uint8(tvb, offset);
2788 offset++;
2789 break;
2790 case RLC_PAYLOAD_TAG:
2791 /* Have reached data, so get out of loop */
2792 continue;
2793 default:
2794 /* It must be a recognised tag */
2795 report_heur_error(tree, pinfo, &ei_rlc_unknown_udp_framing_tag, tvb, offset-1, 1);
2796 return true;
2800 if ((channelTypePresent == false) && (rlcModePresent == false)) {
2801 /* Conditional fields are missing */
2802 report_heur_error(tree, pinfo, &ei_rlc_missing_udp_framing_tag, tvb, 0, offset);
2803 return true;
2806 /* Store info in packet if needed */
2807 if (!fpInfoAlreadySet) {
2808 p_add_proto_data(wmem_file_scope(), pinfo, proto_fp, 0, fpi);
2810 if (!rlcInfoAlreadySet) {
2811 p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_rlc, 0, rlci);
2814 /**************************************/
2815 /* OK, now dissect as RLC */
2817 /* Create tvb that starts at actual RLC PDU */
2818 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
2819 switch (channelType) {
2820 case UMTS_CHANNEL_TYPE_UNSPECIFIED:
2821 /* Call relevant dissector according to RLC mode */
2822 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC");
2823 col_clear(pinfo->cinfo, COL_INFO);
2825 if (tree) {
2826 ti = proto_tree_add_item(tree, proto_umts_rlc, rlc_tvb, 0, -1, ENC_NA);
2827 subtree = proto_item_add_subtree(ti, ett_rlc);
2830 if (rlci->mode[fpi->cur_tb] == RLC_AM) {
2831 proto_item_append_text(ti, " AM");
2832 dissect_rlc_am(RLC_UNKNOWN_CH, rlc_tvb, pinfo, tree, subtree, atm);
2833 } else if (rlci->mode[fpi->cur_tb] == RLC_UM) {
2834 proto_item_append_text(ti, " UM");
2835 dissect_rlc_um(RLC_UNKNOWN_CH, rlc_tvb, pinfo, tree, subtree, atm);
2836 } else {
2837 proto_item_append_text(ti, " TM");
2838 dissect_rlc_tm(RLC_UNKNOWN_CH, rlc_tvb, pinfo, tree, subtree);
2840 break;
2841 case UMTS_CHANNEL_TYPE_PCCH:
2842 dissect_rlc_pcch(rlc_tvb, pinfo, tree, data);
2843 break;
2844 case UMTS_CHANNEL_TYPE_CCCH:
2845 dissect_rlc_ccch(rlc_tvb, pinfo, tree, data);
2846 break;
2847 case UMTS_CHANNEL_TYPE_DCCH:
2848 dissect_rlc_dcch(rlc_tvb, pinfo, tree, data);
2849 break;
2850 case UMTS_CHANNEL_TYPE_PS_DTCH:
2851 dissect_rlc_ps_dtch(rlc_tvb, pinfo, tree, data);
2852 break;
2853 case UMTS_CHANNEL_TYPE_CTCH:
2854 dissect_rlc_ctch(rlc_tvb, pinfo, tree, data);
2855 break;
2856 case UMTS_CHANNEL_TYPE_BCCH:
2857 dissect_rlc_bcch(rlc_tvb, pinfo, tree, data);
2858 break;
2859 default:
2860 /* Unknown channel type */
2861 return false;
2864 return true;
2867 void
2868 proto_register_rlc(void)
2870 module_t *rlc_module;
2871 expert_module_t* expert_rlc;
2872 static hf_register_info hf[] = {
2873 { &hf_rlc_dc,
2874 { "D/C Bit", "rlc.dc",
2875 FT_BOOLEAN, BASE_NONE, TFS(&rlc_dc_val), 0, NULL, HFILL }
2877 { &hf_rlc_ctrl_type,
2878 { "Control PDU Type", "rlc.ctrl_pdu_type",
2879 FT_UINT8, BASE_DEC, VALS(rlc_ctrl_vals), 0, NULL, HFILL }
2881 { &hf_rlc_r1,
2882 { "Reserved 1", "rlc.r1",
2883 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2885 { &hf_rlc_rsn,
2886 { "Reset Sequence Number", "rlc.rsn",
2887 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2889 { &hf_rlc_hfni,
2890 { "Hyper Frame Number Indicator", "rlc.hfni",
2891 FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL }
2893 { &hf_rlc_seq,
2894 { "Sequence Number", "rlc.seq",
2895 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2897 { &hf_rlc_ext,
2898 { "Extension Bit", "rlc.ext",
2899 FT_BOOLEAN, BASE_NONE, TFS(&rlc_ext_val), 0, NULL, HFILL }
2901 { &hf_rlc_he,
2902 { "Header Extension Type", "rlc.he",
2903 FT_UINT8, BASE_DEC, VALS(rlc_he_vals), 0, NULL, HFILL }
2905 { &hf_rlc_p,
2906 { "Polling Bit", "rlc.p",
2907 FT_BOOLEAN, BASE_NONE, TFS(&rlc_p_val), 0, NULL, HFILL }
2909 { &hf_rlc_pad,
2910 { "Padding", "rlc.padding",
2911 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2913 { &hf_rlc_reassembled_data,
2914 { "Reassembled RLC Data", "rlc.reassembled_data",
2915 FT_BYTES, BASE_NONE, NULL, 0, "The reassembled payload", HFILL }
2917 { &hf_rlc_frags,
2918 { "Reassembled Fragments", "rlc.fragments",
2919 FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
2921 { &hf_rlc_frag,
2922 { "RLC Fragment", "rlc.fragment",
2923 FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }
2925 { &hf_rlc_duplicate_of,
2926 { "Duplicate of", "rlc.duplicate_of",
2927 FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }
2929 { &hf_rlc_reassembled_in,
2930 { "Reassembled Message in frame", "rlc.reassembled_in",
2931 FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }
2933 { &hf_rlc_data,
2934 { "Data", "rlc.data",
2935 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2937 { &hf_rlc_ciphered_data,
2938 { "Ciphered Data", "rlc.ciphered_data",
2939 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2941 { &hf_rlc_ciphered_lis_data,
2942 { "Ciphered LIs & Data", "rlc.ciphered_data",
2943 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2945 /* LI information */
2946 { &hf_rlc_li,
2947 { "LI", "rlc.li",
2948 FT_NONE, BASE_NONE, NULL, 0, "Length Indicator", HFILL }
2950 { &hf_rlc_li_value,
2951 { "LI value", "rlc.li.value",
2952 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2954 { &hf_rlc_li_ext,
2955 { "LI extension bit", "rlc.li.ext",
2956 FT_BOOLEAN, BASE_NONE, TFS(&rlc_ext_val), 0, NULL, HFILL }
2958 { &hf_rlc_li_data,
2959 { "LI Data", "rlc.li.data",
2960 FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
2962 /* SUFI information */
2963 { &hf_rlc_sufi,
2964 { "SUFI", "rlc.sufi",
2965 FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
2967 { &hf_rlc_sufi_type,
2968 { "SUFI Type", "rlc.sufi.type",
2969 FT_UINT8, BASE_DEC, VALS(rlc_sufi_vals), 0, NULL, HFILL }
2971 { &hf_rlc_sufi_lsn,
2972 { "Last Sequence Number", "rlc.sufi.lsn",
2973 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2975 { &hf_rlc_sufi_wsn,
2976 { "Window Size Number", "rlc.sufi.wsn",
2977 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2979 { &hf_rlc_sufi_sn,
2980 { "Sequence Number", "rlc.sufi.sn",
2981 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2983 { &hf_rlc_sufi_l,
2984 { "Length", "rlc.sufi.l",
2985 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2987 { &hf_rlc_sufi_len,
2988 { "Length", "rlc.sufi.len",
2989 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
2991 { &hf_rlc_sufi_fsn,
2992 { "First Sequence Number", "rlc.sufi.fsn",
2993 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
2995 { &hf_rlc_sufi_bitmap,
2996 { "Bitmap", "rlc.sufi.bitmap",
2997 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
2999 { &hf_rlc_sufi_cw,
3000 { "Codeword", "rlc.sufi.cw",
3001 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
3003 { &hf_rlc_sufi_n,
3004 { "Nlength", "rlc.sufi.n",
3005 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
3007 { &hf_rlc_sufi_sn_ack,
3008 { "SN ACK", "rlc.sufi.sn_ack",
3009 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
3011 { &hf_rlc_sufi_sn_mrw,
3012 { "SN MRW", "rlc.sufi.sn_mrw",
3013 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
3015 { &hf_rlc_sufi_poll_sn,
3016 { "Poll SN", "rlc.sufi.poll_sn",
3017 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
3019 /* Other information */
3020 { &hf_rlc_header_only,
3021 { "RLC PDU header only", "rlc.header_only",
3022 FT_BOOLEAN, BASE_NONE, TFS(&rlc_header_only_val), 0 ,NULL, HFILL }
3024 { &hf_rlc_channel,
3025 { "Channel", "rlc.channel",
3026 FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
3028 { &hf_rlc_channel_rbid,
3029 { "Radio Bearer ID", "rlc.channel.rbid",
3030 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
3032 { &hf_rlc_channel_dir,
3033 { "Direction", "rlc.channel.dir",
3034 FT_UINT8, BASE_DEC, VALS(rlc_dir_vals), 0, NULL, HFILL }
3036 { &hf_rlc_channel_ueid,
3037 { "User Equipment ID", "rlc.channel.ueid",
3038 FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }
3040 { &hf_rlc_sequence_number,
3041 { "Sequence Number", "rlc.sequence_number",
3042 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }
3044 { &hf_rlc_length,
3045 { "Length", "rlc.length",
3046 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }
3048 { &hf_rlc_bitmap_string,
3049 { "Bitmap string", "rlc.bitmap_string",
3050 FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
3054 static int *ett[] = {
3055 &ett_rlc,
3056 &ett_rlc_frag,
3057 &ett_rlc_fragments,
3058 &ett_rlc_sdu,
3059 &ett_rlc_sufi,
3060 &ett_rlc_bitmap,
3061 &ett_rlc_rlist,
3062 &ett_rlc_channel
3064 static ei_register_info ei[] = {
3065 { &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 }},
3066 { &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 }},
3067 { &ei_rlc_reassembly_lingering_endpoint, { "rlc.lingering_endpoint", PI_REASSEMBLE, PI_ERROR, "Lingering endpoint.", EXPFILL }},
3068 { &ei_rlc_reassembly_unknown_error, { "rlc.reassembly.unknown_error", PI_REASSEMBLE, PI_ERROR, "Unknown error.", EXPFILL }},
3069 { &ei_rlc_kasumi_implementation_missing, { "rlc.kasumi_implementation_missing", PI_UNDECODED, PI_WARN, "Unable to decipher packet since KASUMI implementation is missing.", EXPFILL }},
3070 { &ei_rlc_li_reserved, { "rlc.li.reserved", PI_PROTOCOL, PI_WARN, "Uses reserved LI", EXPFILL }},
3071 { &ei_rlc_li_incorrect_warn, { "rlc.li.incorrect", PI_PROTOCOL, PI_WARN, "Incorrect LI value", EXPFILL }},
3072 { &ei_rlc_li_incorrect_mal, { "rlc.li.incorrect", PI_MALFORMED, PI_ERROR, "Incorrect LI value", EXPFILL }},
3073 { &ei_rlc_li_too_many, { "rlc.li.too_many", PI_MALFORMED, PI_ERROR, "Too many LI entries", EXPFILL }},
3074 { &ei_rlc_header_only, { "rlc.header_only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3075 { &ei_rlc_sufi_len, { "rlc.sufi.len.invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
3076 { &ei_rlc_sufi_cw, { "rlc.sufi.cw.invalid", PI_PROTOCOL, PI_WARN, "Invalid last codeword", EXPFILL }},
3077 { &ei_rlc_sufi_type, { "rlc.sufi.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid SUFI type", EXPFILL }},
3078 { &ei_rlc_reserved_bits_not_zero, { "rlc.reserved_bits_not_zero", PI_PROTOCOL, PI_WARN, "reserved bits not zero", EXPFILL }},
3079 { &ei_rlc_ctrl_type, { "rlc.ctrl_pdu_type.invalid", PI_PROTOCOL, PI_WARN, "Invalid RLC AM control type", EXPFILL }},
3080 { &ei_rlc_he, { "rlc.he.invalid", PI_PROTOCOL, PI_WARN, "Incorrect HE value", EXPFILL }},
3081 { &ei_rlc_ciphered_data, { "rlc.ciphered", PI_UNDECODED, PI_WARN, "Cannot dissect RLC frame because it is ciphered", EXPFILL }},
3082 { &ei_rlc_no_per_frame_data, { "rlc.no_per_frame_data", PI_PROTOCOL, PI_WARN, "Can't dissect RLC frame because no per-frame info was attached!", EXPFILL }},
3083 { &ei_rlc_incomplete_sequence, { "rlc.incomplete_sequence", PI_MALFORMED, PI_ERROR, "Error: Incomplete sequence", EXPFILL }},
3084 { &ei_rlc_unknown_udp_framing_tag, { "rlc.unknown_udp_framing_tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }},
3085 { &ei_rlc_missing_udp_framing_tag, { "rlc.missing_udp_framing_tag", PI_UNDECODED, PI_WARN, "Missing UDP framing conditional tag, aborting dissection", EXPFILL }}
3088 proto_umts_rlc = proto_register_protocol("Radio Link Control", "RLC", "rlc");
3089 register_dissector("rlc.bcch", dissect_rlc_bcch, proto_umts_rlc);
3090 register_dissector("rlc.pcch", dissect_rlc_pcch, proto_umts_rlc);
3091 register_dissector("rlc.ccch", dissect_rlc_ccch, proto_umts_rlc);
3092 register_dissector("rlc.ctch", dissect_rlc_ctch, proto_umts_rlc);
3093 register_dissector("rlc.dcch", dissect_rlc_dcch, proto_umts_rlc);
3094 register_dissector("rlc.ps_dtch", dissect_rlc_ps_dtch, proto_umts_rlc);
3095 register_dissector("rlc.dch_unknown", dissect_rlc_dch_unknown, proto_umts_rlc);
3097 proto_register_field_array(proto_umts_rlc, hf, array_length(hf));
3098 proto_register_subtree_array(ett, array_length(ett));
3099 expert_rlc = expert_register_protocol(proto_umts_rlc);
3100 expert_register_field_array(expert_rlc, ei, array_length(ei));
3102 /* Preferences */
3103 rlc_module = prefs_register_protocol(proto_umts_rlc, NULL);
3105 prefs_register_obsolete_preference(rlc_module, "heuristic_rlc_over_udp");
3107 prefs_register_bool_preference(rlc_module, "perform_reassembly",
3108 "Try to reassemble SDUs",
3109 "When enabled, try to reassemble SDUs from the various PDUs received",
3110 &global_rlc_perform_reassemby);
3112 prefs_register_bool_preference(rlc_module, "header_only_mode",
3113 "May see RLC headers only",
3114 "When enabled, if data is not present, don't report as an error, but instead "
3115 "add expert info to indicate that headers were omitted",
3116 &global_rlc_headers_expected);
3118 prefs_register_bool_preference(rlc_module, "ignore_rrc_cipher_indication",
3119 "Ignore ciphering indication from higher layers",
3120 "When enabled, RLC will ignore sequence numbers reported in 'Security Mode Command'/'Security Mode Complete' (RRC) messages when checking if frames are ciphered",
3121 &global_ignore_rrc_ciphering_indication);
3123 prefs_register_bool_preference(rlc_module, "ciphered_data",
3124 "All data is ciphered",
3125 "When enabled, RLC will assume all payloads in RLC frames are ciphered",
3126 &global_rlc_ciphered);
3128 #ifdef HAVE_UMTS_KASUMI
3129 prefs_register_bool_preference(rlc_module, "try_decipher",
3130 "Try to decipher data",
3131 "When enabled, RLC will try to decipher data. (Experimental)",
3132 &global_rlc_try_decipher);
3134 prefs_register_string_preference(rlc_module, "kasumi_key",
3135 "KASUMI key", "Key for kasumi 32 characters long hex-string", &global_rlc_kasumi_key);
3136 #else
3137 /* If Wireshark isn't compiled with KASUMI we still want to register the above preferences
3138 * We are doing so for two reasons:
3139 * 1. To inform the user about the disabled preferences (using static text preference)
3140 * 2. To prevent errors when Wireshark reads a preferences file which includes records for these preferences
3142 prefs_register_static_text_preference(rlc_module, "try_decipher",
3143 "Data deciphering is disabled", "Wireshark was compiled without the KASUMI decryption algorithm");
3145 prefs_register_obsolete_preference(rlc_module, "kasumi_key");
3146 #endif /* HAVE_UMTS_KASUMI */
3148 prefs_register_enum_preference(rlc_module, "li_size",
3149 "LI size",
3150 "LI size in bits, either 7 or 15 bit",
3151 &global_rlc_li_size, li_size_enumvals, false);
3153 register_init_routine(fragment_table_init);
3154 register_cleanup_routine(fragment_table_cleanup);
3157 void
3158 proto_reg_handoff_rlc(void)
3160 rrc_handle = find_dissector_add_dependency("rrc", proto_umts_rlc);
3161 ip_handle = find_dissector_add_dependency("ip", proto_umts_rlc);
3162 bmc_handle = find_dissector_add_dependency("bmc", proto_umts_rlc);
3163 /* Add as a heuristic UDP dissector */
3164 heur_dissector_add("udp", dissect_rlc_heur, "RLC over UDP", "rlc_udp", proto_umts_rlc, HEURISTIC_DISABLE);
3168 * Editor modelines
3170 * Local Variables:
3171 * c-basic-offset: 4
3172 * tab-width: 8
3173 * indent-tabs-mode: nil
3174 * End:
3176 * ex: set shiftwidth=4 tabstop=8 expandtab:
3177 * :indentSize=4:tabSize=8:noTabs=true: