Add RLC LTE dissector.
[obnox/wireshark/wip.git] / epan / dissectors / packet-rlc-lte.c
1 /* Routines for LTE RLC disassembly
2  *
3  * Martin Mathieson
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <epan/packet.h>
31 #include <epan/expert.h>
32
33 #include "packet-rlc-lte.h"
34
35
36 /* Described in:
37  * 3GPP TS 36.322 Evolved Universal Terrestial Radio Access (E-UTRA)
38  * Radio Link Control (RLC) Protocol specification
39  */
40
41 /* Initialize the protocol and registered fields. */
42 int proto_rlc_lte = -1;
43
44 /* Decoding context */
45 static int hf_rlc_lte_context_mode = -1;
46 static int hf_rlc_lte_context_direction = -1;
47 static int hf_rlc_lte_context_priority = -1;
48 static int hf_rlc_lte_context_ueid = -1;
49 static int hf_rlc_lte_context_channel_type = -1;
50 static int hf_rlc_lte_context_channel_id = -1;
51 static int hf_rlc_lte_context_pdu_length = -1;
52 static int hf_rlc_lte_context_um_sn_length = -1;
53
54 /* Transparent mode fields */
55 static int hf_rlc_lte_tm_data = -1;
56
57 /* Unacknowledged mode fields */
58 static int hf_rlc_lte_um_header = -1;
59 static int hf_rlc_lte_um_fi = -1;
60 static int hf_rlc_lte_um_fixed_e = -1;
61 static int hf_rlc_lte_um_sn = -1;
62 static int hf_rlc_lte_um_fixed_reserved = -1;
63 static int hf_rlc_lte_um_data = -1;
64 static int hf_rlc_lte_extension_part = -1;
65
66 /* Extended header (common to UM and AM) */
67 static int hf_rlc_lte_extension_e = -1;
68 static int hf_rlc_lte_extension_li = -1;
69 static int hf_rlc_lte_extension_padding = -1;
70
71
72 /* Acknowledged mode fields */
73 static int hf_rlc_lte_am_header = -1;
74 static int hf_rlc_lte_am_data_control = -1;
75 static int hf_rlc_lte_am_rf = -1;
76 static int hf_rlc_lte_am_p = -1;
77 static int hf_rlc_lte_am_fi = -1;
78 static int hf_rlc_lte_am_fixed_e = -1;
79 static int hf_rlc_lte_am_fixed_sn = -1;
80 static int hf_rlc_lte_am_segment_lsf = -1;
81 static int hf_rlc_lte_am_segment_so = -1;
82 static int hf_rlc_lte_am_data = -1;
83
84 /* Control fields */
85 static int hf_rlc_lte_am_cpt = -1;
86 static int hf_rlc_lte_am_ack_sn = -1;
87 static int hf_rlc_lte_am_e1 = -1;
88 static int hf_rlc_lte_am_e2 = -1;
89 static int hf_rlc_lte_am_nack_sn = -1;
90 static int hf_rlc_lte_am_so_start = -1;
91 static int hf_rlc_lte_am_so_end = -1;
92
93 /* Subtrees. */
94 static int ett_rlc_lte = -1;
95 static int ett_rlc_lte_um_header = -1;
96 static int ett_rlc_lte_am_header = -1;
97 static int ett_rlc_lte_extension_part = -1;
98
99
100 static const value_string direction_vals[] =
101 {
102     { 0,      "Uplink"},
103     { 1,      "Downlink"},
104     { 0, NULL }
105 };
106
107
108 #define RLC_TM_MODE 1
109 #define RLC_UM_MODE 2
110 #define RLC_AM_MODE 3
111
112
113 static const value_string rlc_mode_short_vals[] =
114 {
115     { RLC_TM_MODE,      "TM"},
116     { RLC_UM_MODE,      "UM"},
117     { RLC_AM_MODE,      "AM"},
118     { 0, NULL }
119 };
120
121 static const value_string rlc_mode_vals[] =
122 {
123     { RLC_TM_MODE,      "Transparent Mode"},
124     { RLC_UM_MODE,      "Unacknowledged Mode"},
125     { RLC_AM_MODE,      "Acknowledged Mode"},
126     { 0, NULL }
127 };
128
129
130 static const value_string rlc_channel_type_vals[] =
131 {
132     { 1,      "CCCH"},
133     { 2,      "BCCH"},
134     { 3,      "PCCH"},
135     { 4,      "SRB"},
136     { 5,      "DRB"},
137     { 0, NULL }
138 };
139
140
141 static const value_string framing_info_vals[] =
142 {
143     { 0,      "First byte begins an RLC SDU and last byte ends an RLC SDU"},
144     { 1,      "First byte begins an RLC SDU and last byte does not end an RLC SDU"},
145     { 2,      "First byte does not begin an RLC SDU and last byte ends an RLC SDU"},
146     { 3,      "First byte does not begin an RLC SDU and last byte does not end an RLC SDU"},
147     { 0, NULL }
148 };
149
150 static const value_string fixed_extension_vals[] =
151 {
152     { 0,      "Data field follows from the octet following the fixed part of the header"},
153     { 1,      "A set of E field and LI field follows from the octet following the fixed part of the header"},
154     { 0, NULL }
155 };
156
157 static const value_string extension_extension_vals[] =
158 {
159     { 0,      "Data field follows from the octet following the LI field following this E field"},
160     { 1,      "A set of E field and LI field follows from the bit following the LI field following this E field"},
161     { 0, NULL }
162 };
163
164 static const value_string data_or_control_vals[] =
165 {
166     { 0,      "Control PDU"},
167     { 1,      "Data PDU"},
168     { 0, NULL }
169 };
170
171 static const value_string resegmentation_flag_vals[] =
172 {
173     { 0,      "AMD PDU"},
174     { 1,      "AND PDU segment"},
175     { 0, NULL }
176 };
177
178 static const value_string polling_bit_vals[] =
179 {
180     { 0,      "Status report not requested"},
181     { 1,      "Status report is requested"},
182     { 0, NULL }
183 };
184
185
186 static const value_string lsf_vals[] =
187 {
188     { 0,      "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
189     { 1,      "Last byte of the AMD PDU segment corresponds to the last byte of an AND PDU"},
190     { 0, NULL }
191 };
192
193
194 static const value_string control_pdu_type_vals[] =
195 {
196     { 0,      "STATUS PDU"},
197     { 0, NULL }
198 };
199
200 static const value_string am_e1_vals[] =
201 {
202     { 0,      "A set of NACK_SN, E1 and E2 does not follow"},
203     { 1,      "A set of NACK_SN, E1 and E2 follows"},
204     { 0, NULL }
205 };
206
207 static const value_string am_e2_vals[] =
208 {
209     { 0,      "A set of SOstart and SOend does not follow for this NACK_SN"},
210     { 1,      "A set of SOstart and SOend follows for this NACK_SN"},
211     { 0, NULL }
212 };
213
214 /* These are for keeping track of UM/AM extension headers, and the lengths found
215    in them */
216 guint8  s_number_of_extensions = 0;
217 #define MAX_RLC_SDUS 64
218 guint16 s_lengths[MAX_RLC_SDUS];
219
220
221 /* Dissect extension headers (common to both UM and AM) */
222 static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo,
223                                             proto_tree *tree,
224                                             int offset)
225 {
226     guint8  isOdd;
227     guint64 extension = 1;
228     guint64 length;
229
230     /* Reset this count */
231     s_number_of_extensions = 0;
232
233     while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
234         proto_tree *extension_part_tree;
235         proto_item *extension_part_ti;
236
237         isOdd = (s_number_of_extensions % 2);
238
239         /* Extension part subtree */
240         extension_part_ti = proto_tree_add_string_format(tree,
241                                                          hf_rlc_lte_extension_part,
242                                                          tvb, offset, 2,
243                                                          "",
244                                                          "Extension Part");
245         extension_part_tree = proto_item_add_subtree(extension_part_ti,
246                                                      ett_rlc_lte_extension_part);
247
248         /* Read next extension */
249         proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
250                                    (offset*8) + ((isOdd) ? 4 : 0),
251                                     1,
252                                     &extension, FALSE);
253
254         /* Read length field */
255         proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
256                                    (offset*8) + ((isOdd) ? 5 : 1),
257                                     11,
258                                     &length, FALSE);
259
260         proto_item_append_text(extension_part_tree, " (length=%u)", (guint16)length);
261
262         /* Move on to byte of next extension */
263         if (isOdd) {
264             offset += 2;
265         } else {
266             offset++;
267         }
268
269         s_lengths[s_number_of_extensions++] = (guint16)length;
270     }
271
272     /* May need to skip padding after last extension part */
273     isOdd = (s_number_of_extensions % 2);
274     if (isOdd) {
275         guint8 padding;
276         proto_item *ti;
277
278         padding = tvb_get_guint8(tvb, offset) & 0x0f;
279         ti = proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
280                                  tvb, offset, 1, FALSE);
281         if (padding != 0) {
282             expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
283                       "Extension Header padding not zero (found 0x%x)", padding);
284         }
285         offset++;
286     }
287
288     return offset;
289 }
290
291
292 /* Show in the info column how many bytes are in the UM/AM PDU, and indicate
293    whether or not the beginning and end are included in this packet */
294 static void show_PDU_in_info(packet_info *pinfo,
295                              guint16 length,
296                              guint8 first_includes_start,
297                              guint8 last_includes_end)
298 {
299     /* Reflect this PDU in the info column */
300     if (check_col(pinfo->cinfo, COL_INFO)) {
301         col_append_fstr(pinfo->cinfo, COL_INFO, "  %s%u-bytes%s",
302                         (first_includes_start) ? "[" : "..",
303                         length,
304                         (last_includes_end) ? "]" : "..");
305     }
306 }
307
308
309 /***************************************************/
310 /* Unacknowledged mode PDU                         */
311 static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
312                                proto_tree *tree,
313                                int offset,
314                                rlc_lte_info *p_rlc_lte_info)
315 {
316     guint64 framing_info;
317     guint8  first_includes_start;
318     guint8  last_includes_end;
319     guint64 fixed_extension;
320     guint64 sn;
321     gint    start_offset = offset;
322     proto_tree *um_header_tree;
323     proto_item *um_header_ti;
324
325     /* Add UM header subtree */
326     um_header_ti = proto_tree_add_string_format(tree,
327                                                 hf_rlc_lte_um_header,
328                                                 tvb, offset, 0,
329                                                 "",
330                                                 "UM header");
331     um_header_tree = proto_item_add_subtree(um_header_ti,
332                                             ett_rlc_lte_um_header);
333
334
335     /*******************************/
336     /* Fixed UM header             */
337     if (p_rlc_lte_info->UMSequenceNumberLength == 5) {
338         /* Framing info (2 bits) */
339         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
340                                     tvb, offset*8, 2,
341                                     &framing_info, FALSE);
342
343         /* Extension (1 bit) */
344         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
345                                     (offset*8) + 2, 1,
346                                     &fixed_extension, FALSE);
347
348         /* Sequence Number (5 bit) */
349         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
350                                     (offset*8) + 3, 5,
351                                     &sn, FALSE);
352         offset++;
353     }
354     else if (p_rlc_lte_info->UMSequenceNumberLength == 10) {
355         guint8 reserved;
356         proto_item *ti;
357
358         /* Check 3 Reserved bits */
359         reserved = (tvb_get_guint8(tvb, offset) & 0xe0) >> 5;
360         ti = proto_tree_add_item(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, FALSE);
361         if (reserved != 0) {
362             expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
363                       "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
364         }
365
366         /* Framing info (2 bits) */
367         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
368                                     tvb, (offset*8)+3, 2,
369                                     &framing_info, FALSE);
370
371         /* Extension (1 bit) */
372         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
373                                     (offset*8) + 5, 1,
374                                     &fixed_extension, FALSE);
375
376         /* Sequence Number (10 bits) */
377         proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
378                                     (offset*8) + 6, 10,
379                                     &sn, FALSE);
380         offset += 2;
381     }
382     else {
383         /* Invalid length of sequence number */
384         proto_item *ti;
385         ti = proto_tree_add_text(um_header_tree, tvb, 0, 0, "Invalid sequence number length (%u bits)",
386                                  p_rlc_lte_info->UMSequenceNumberLength);
387         expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
388                                "Invalid sequence number length (%u bits)",
389                                p_rlc_lte_info->UMSequenceNumberLength);
390         return;
391     }
392
393     /* Show SN in info column */
394     if (check_col(pinfo->cinfo, COL_INFO)) {
395         col_append_fstr(pinfo->cinfo, COL_INFO, "  SN=%04u",
396                         (guint16)sn);
397     }
398
399     /* Show SN in UM header root */
400     proto_item_append_text(um_header_ti, " (SN=%u)", (guint16)sn);
401     proto_item_set_len(um_header_ti, offset-start_offset);
402
403
404     /*************************************/
405     /* UM header extension               */
406     if (fixed_extension) {
407         offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
408     }
409
410
411     /* Extract these 2 flags from framing_info */
412     first_includes_start = ((guint8)framing_info & 0x02) == 0;
413     last_includes_end =    ((guint8)framing_info & 0x01) == 0;
414
415
416     /*************************************/
417     /* Data                              */
418     if (s_number_of_extensions > 0) {
419         /* Show each data segment separately */
420         int n;
421         for (n=0; n < s_number_of_extensions; n++) {
422             proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, s_lengths[n], FALSE);
423             show_PDU_in_info(pinfo, s_lengths[n],
424                              (n==0) ? first_includes_start : TRUE,
425                              TRUE);
426             offset += s_lengths[n];
427         }
428     }
429
430     /* Final data element */
431     proto_tree_add_item(tree, hf_rlc_lte_um_data, tvb, offset, -1, FALSE);
432     show_PDU_in_info(pinfo, tvb_length_remaining(tvb, offset),
433                      (s_number_of_extensions == 0) ? first_includes_start : TRUE,
434                      last_includes_end);
435 }
436
437
438
439
440 /* Dissect an AM STATUS PDU */
441 static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb, packet_info *pinfo,
442                                           proto_tree *tree,
443                                           int offset)
444 {
445     guint8     cpt;
446     guint64    ack_sn, nack_sn;
447     guint64    e1 = 0, e2 = 0;
448     guint64    so_start, so_end;
449     int        bit_offset = offset * 8;
450     proto_item *ti;
451
452     /****************************************************************/
453     /* Part of RLC control PDU header                               */
454
455     /* Control PDU Type (CPT) */
456     cpt = (tvb_get_guint8(tvb, offset) & 0xf0) >> 4;
457     ti = proto_tree_add_item(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, FALSE);
458     if (cpt != 0) {
459         /* Protest and stop - only know about STATUS PDUs */
460         expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
461                                "RLC Control frame type %u not handled", cpt);
462         return;
463     }
464
465
466     /*****************************************************************/
467     /* STATUS PDU                                                    */
468
469     /* The PDU itself starts 4 bits into the byte */
470     bit_offset += 4;
471
472     /* ACK SN */
473     proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
474                                 bit_offset, 10, &ack_sn, FALSE);
475     bit_offset += 10;
476
477     /* E1 */
478     proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
479                                 bit_offset, 1, &e1, FALSE);
480
481     /* Skip another bit to byte-align the next bit... */
482     bit_offset++;
483
484     /* Optional, extra fields */
485     do {
486         if (e1) {
487             /****************************/
488             /* Read NACK_SN, E1, E2     */
489
490             /* ACK_SN */
491             proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
492                                         bit_offset, 10, &nack_sn, FALSE);
493             bit_offset += 10;
494
495             /* E1 */
496             proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
497                                         bit_offset, 1, &e1, FALSE);
498             bit_offset++;
499
500             /* E2 */
501             proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
502                                         bit_offset, 1, &e2, FALSE);
503             bit_offset++;
504
505             /* Reset this flag here */
506             e1 = 0;
507         }
508         if (e2) {
509             /* Read SOstart, SOend */
510             proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
511                                         bit_offset, 15, &so_start, FALSE);
512             bit_offset += 15;
513
514             proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
515                                         bit_offset, 15, &so_end, FALSE);
516             bit_offset += 15;
517
518             /* Reset this flag here */
519             e2 = 0;
520         }
521     } while (e1 || e2);
522
523 }
524
525
526 /***************************************************/
527 /* Acknowledged mode PDU                           */
528 static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
529                                proto_tree *tree,
530                                int offset)
531 {
532     guint8 is_data;
533     guint8 is_segment;
534     guint8 fixed_extension;
535     guint8 framing_info;
536     guint8 first_includes_start;
537     guint8 last_includes_end;
538     proto_tree *am_header_tree;
539     proto_item *am_header_ti;
540     gint   start_offset = offset;
541     guint16    sn;
542
543     /* Add UM header subtree */
544     am_header_ti = proto_tree_add_string_format(tree,
545                                                 hf_rlc_lte_am_header,
546                                                 tvb, offset, 0,
547                                                 "",
548                                                 "AM header");
549     am_header_tree = proto_item_add_subtree(am_header_ti,
550                                             ett_rlc_lte_am_header);
551
552
553     /*******************************************/
554     /* First bit is Data/Control flag           */
555     is_data = (tvb_get_guint8(tvb, offset) & 0x80) >> 7;
556     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, FALSE);
557     if (check_col(pinfo->cinfo, COL_INFO)) {
558         col_append_str(pinfo->cinfo, COL_INFO, (is_data) ? " [DATA]" : " [CONTROL]");
559     }
560
561
562     /**************************************************/
563     /* Control PDUs are a completely separate format  */
564     if (!is_data) {
565         dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, offset);
566         return;
567     }
568
569
570     /******************************/
571     /* Data PDU fixed header      */
572
573     /* Re-segmentation Flag (RF) field */
574     is_segment = (tvb_get_guint8(tvb, offset) & 0x40) >> 6;
575     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1, FALSE);
576
577     /* Polling bit */
578     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1, FALSE);
579
580     /* Framing Info */
581     framing_info = (tvb_get_guint8(tvb, offset) & 0x18) >> 3;
582     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1, FALSE);
583
584     /* Extension bit */
585     fixed_extension = (tvb_get_guint8(tvb, offset) & 0x04) >> 2;
586     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1, FALSE);
587
588     /* Sequence Number */
589     sn = tvb_get_ntohs(tvb, offset) & 0x03ff;
590     proto_tree_add_item(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, FALSE);
591
592     offset += 2;
593
594     /* Show SN in AM header root */
595     proto_item_append_text(am_header_ti, " (SN=%u)", sn);
596     proto_item_set_len(am_header_ti, offset-start_offset);
597
598     /***************************************/
599     /* Dissect extra segment header fields */
600     if (is_segment) {
601         /* Last Segment Field (LSF) */
602         proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, FALSE);
603
604         /* SO */
605         proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, FALSE);
606
607         offset += 2;
608     }
609
610     /*************************************/
611     /* AM header extension               */
612     if (fixed_extension) {
613         offset = dissect_rlc_lte_extension_header(tvb, pinfo, tree, offset);
614     }
615
616
617     /* Extract these 2 flags from framing_info */
618     first_includes_start = (framing_info & 0x02) == 0;
619     last_includes_end =    (framing_info & 0x01) == 0;
620
621
622     /*************************************/
623     /* Data                        */
624     if (s_number_of_extensions > 0) {
625         /* Show each data segment separately */
626         int n;
627         for (n=0; n < s_number_of_extensions; n++) {
628             proto_tree_add_item(tree, hf_rlc_lte_am_data, tvb, offset, s_lengths[n], FALSE);
629             show_PDU_in_info(pinfo, s_lengths[n],
630                              (n==0) ? first_includes_start : TRUE,
631                              TRUE);
632             offset += s_lengths[n];
633         }
634     }
635
636     /* Final data element */
637     proto_tree_add_item(tree, hf_rlc_lte_am_data, tvb, offset, -1, FALSE);
638     show_PDU_in_info(pinfo, tvb_length_remaining(tvb, offset),
639                      (s_number_of_extensions == 0) ? first_includes_start : TRUE,
640                      last_includes_end);
641 }
642
643
644
645 /*****************************/
646 /* Main dissection function. */
647 /*****************************/
648
649 void dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
650 {
651     proto_tree             *rlc_lte_tree;
652     proto_item             *ti;
653     proto_item             *mode_ti;
654     gint                   offset = 0;
655     struct rlc_lte_info    *p_rlc_lte_info = NULL;
656
657     /* Set protocol name */
658     if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
659         col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
660     }
661
662     /* Create protocol tree. */
663     ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, FALSE);
664     rlc_lte_tree = proto_item_add_subtree(ti, ett_rlc_lte);
665
666
667     /* Look for packet info! */
668     p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
669
670     /* Can't dissect anything without it... */
671     if (p_rlc_lte_info == NULL) {
672         proto_item *ti =
673             proto_tree_add_text(rlc_lte_tree, tvb, offset, -1,
674                                 "Can't dissect LTE RLC frame because no per-frame info was attached!");
675         PROTO_ITEM_SET_GENERATED(ti);
676         return;
677     }
678
679     /*****************************************/
680     /* Show context information              */
681     /* TODO: hide inside own tree?           */
682
683     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_direction,
684                              tvb, 0, 0, p_rlc_lte_info->direction);
685     PROTO_ITEM_SET_GENERATED(ti);
686
687     mode_ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_mode,
688                                   tvb, 0, 0, p_rlc_lte_info->rlcMode);
689     PROTO_ITEM_SET_GENERATED(mode_ti);
690
691     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_ueid,
692                              tvb, 0, 0, p_rlc_lte_info->ueid);
693     PROTO_ITEM_SET_GENERATED(ti);
694
695     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_priority,
696                              tvb, 0, 0, p_rlc_lte_info->priority);
697     PROTO_ITEM_SET_GENERATED(ti);
698
699     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_type,
700                              tvb, 0, 0, p_rlc_lte_info->channelType);
701     PROTO_ITEM_SET_GENERATED(ti);
702
703     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_channel_id,
704                              tvb, 0, 0, p_rlc_lte_info->channelId);
705     PROTO_ITEM_SET_GENERATED(ti);
706
707     ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_pdu_length,
708                              tvb, 0, 0, p_rlc_lte_info->pduLength);
709     PROTO_ITEM_SET_GENERATED(ti);
710
711     if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
712         ti = proto_tree_add_uint(rlc_lte_tree, hf_rlc_lte_context_um_sn_length,
713                                  tvb, 0, 0, p_rlc_lte_info->UMSequenceNumberLength);
714         PROTO_ITEM_SET_GENERATED(ti);
715     }
716
717
718     /* Append context highlights to info column */
719     if (check_col(pinfo->cinfo, COL_INFO)) {
720         col_add_fstr(pinfo->cinfo, COL_INFO,
721                      "[%s] [%s] UEId=%u %s:%u",
722                      (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
723                      val_to_str(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"),
724                      p_rlc_lte_info->ueid,
725                      val_to_str(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
726                      p_rlc_lte_info->channelId);
727     }
728
729     /* Reset this count */
730     s_number_of_extensions = 0;
731
732     /* Dissect the RLC PDU itself. Format depends upon mode... */
733     switch (p_rlc_lte_info->rlcMode) {
734
735         case RLC_TM_MODE:
736             /* Remaining bytes are all data */
737             proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_tm_data, tvb, offset, -1, FALSE);
738             if (check_col(pinfo->cinfo, COL_INFO)) {
739                 col_append_fstr(pinfo->cinfo, COL_INFO, "   [%u-bytes]",
740                                tvb_length_remaining(tvb, offset));
741             }
742             break;
743
744         case RLC_UM_MODE:
745             dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info);
746             break;
747
748         case RLC_AM_MODE:
749             dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset);
750             break;
751
752         default:
753             /* Error - unrecognised mode */
754             expert_add_info_format(pinfo, mode_ti, PI_MALFORMED, PI_ERROR,
755                                    "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
756             break;
757     }
758 }
759
760
761 void proto_register_rlc_lte(void)
762 {
763     static hf_register_info hf[] =
764     {
765         /**********************************/
766         /* Items for decoding context     */
767         { &hf_rlc_lte_context_mode,
768             { "RLC Mode",
769               "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
770               "RLC Mode", HFILL
771             }
772         },
773         { &hf_rlc_lte_context_direction,
774             { "Direction",
775               "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
776               "Direction of message", HFILL
777             }
778         },
779         { &hf_rlc_lte_context_priority,
780             { "Priority",
781               "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
782               "Priority", HFILL
783             }
784         },
785         { &hf_rlc_lte_context_ueid,
786             { "UEId",
787               "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
788               "User Equipment Identifier associated with message", HFILL
789             }
790         },
791         { &hf_rlc_lte_context_channel_type,
792             { "Channel Type",
793               "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
794               "Channel Type associated with message", HFILL
795             }
796         },
797         { &hf_rlc_lte_context_channel_id,
798             { "Channel ID",
799               "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
800               "Channel ID associated with message", HFILL
801             }
802         },
803         { &hf_rlc_lte_context_pdu_length,
804             { "PDU Length",
805               "rlc-lte.pdu_length", FT_UINT16, BASE_DEC, 0, 0x0,
806               "Length of PDU (in bytes)", HFILL
807             }
808         },
809         { &hf_rlc_lte_context_um_sn_length,
810             { "UM Sequence number length",
811               "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
812               "Length of UM sequence number in bits", HFILL
813             }
814         },
815
816
817         /* Transparent mode fields */
818         { &hf_rlc_lte_tm_data,
819             { "TM Data",
820               "rlc-lte.tm.data", FT_BYTES, BASE_HEX, 0, 0x0,
821               "Transparent Mode Data", HFILL
822             }
823         },
824
825         /* Unacknowledged mode fields */
826         { &hf_rlc_lte_um_header,
827             { "UM Header",
828               "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
829               "Unackowledged Mode Header", HFILL
830             }
831         },
832         { &hf_rlc_lte_um_fi,
833             { "Framing Info",
834               "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
835               "Framing Info", HFILL
836             }
837         },
838         { &hf_rlc_lte_um_fixed_e,
839             { "Extension",
840               "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
841               "Extension in fixed part of UM header", HFILL
842             }
843         },
844         { &hf_rlc_lte_um_sn,
845             { "Sequence number",
846               "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
847               "Unacknowledged Mode Sequence Number", HFILL
848             }
849         },
850         { &hf_rlc_lte_um_fixed_reserved,
851             { "Reserved",
852               "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
853               "Unacknowledged Mode Fixed header reserved bits", HFILL
854             }
855         },
856         { &hf_rlc_lte_um_data,
857             { "UM Data",
858               "rlc-lte.um.data", FT_BYTES, BASE_HEX, 0, 0x0,
859               "Unacknowledged Mode Data", HFILL
860             }
861         },
862         { &hf_rlc_lte_extension_part,
863             { "Extension Part",
864               "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
865               "Extension Part", HFILL
866             }
867         },
868
869
870         { &hf_rlc_lte_extension_e,
871             { "Extension",
872               "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
873               "Extension in extended part of the header", HFILL
874             }
875         },
876         { &hf_rlc_lte_extension_li,
877             { "Length Indicator",
878               "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
879               "Length Indicator", HFILL
880             }
881         },
882         { &hf_rlc_lte_extension_padding,
883             { "Padding",
884               "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
885               "Extension header padding", HFILL
886             }
887         },
888
889
890         { &hf_rlc_lte_am_header,
891             { "UM Header",
892               "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
893               "Ackowledged Mode Header", HFILL
894             }
895         },
896         { &hf_rlc_lte_am_data_control,
897             { "Frame type",
898               "rlc-lte.am.frame_type", FT_UINT8, BASE_HEX, VALS(data_or_control_vals), 0x80,
899               "AM Frame Type (Control or Data)", HFILL
900             }
901         },
902         { &hf_rlc_lte_am_rf,
903             { "Re-segmentation Flag",
904               "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
905               "AM Re-segmentation Flag", HFILL
906             }
907         },
908         { &hf_rlc_lte_am_p,
909             { "Polling Bit",
910               "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
911               "Polling Bit", HFILL
912             }
913         },
914         { &hf_rlc_lte_am_fi,
915             { "Framing Info",
916               "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
917               "AM Framing Info", HFILL
918             }
919         },
920         { &hf_rlc_lte_am_fixed_e,
921             { "Extension",
922               "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
923               "Fixed Extension Bit", HFILL
924             }
925         },
926         { &hf_rlc_lte_am_fixed_sn,
927             { "Sequence Number",
928               "rlc-lte.am.fixed.sn", FT_UINT16, BASE_HEX, 0, 0x03ff,
929               "AM Fixed Sequence Number", HFILL
930             }
931         },
932         { &hf_rlc_lte_am_segment_lsf,
933             { "Last Segment Flag",
934               "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
935               "Last Segment Flag", HFILL
936             }
937         },
938         { &hf_rlc_lte_am_segment_so,
939             { "Segment Offset",
940               "rlc-lte.am.segment.so", FT_UINT16, BASE_HEX, 0, 0x7fff,
941               "Segment Offset", HFILL
942             }
943         },
944         { &hf_rlc_lte_am_data,
945             { "AM Data",
946               "rlc-lte.am.data", FT_BYTES, BASE_HEX, 0, 0x0,
947               "Acknowledged Mode Data", HFILL
948             }
949         },
950
951
952         { &hf_rlc_lte_am_cpt,
953             { "Control PDU Type",
954               "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
955               "AM Control PDU Type", HFILL
956             }
957         },
958         { &hf_rlc_lte_am_ack_sn,
959             { "ACK Sequence Number",
960               "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0ffc,
961               "Sequence Number we're next expecting to receive", HFILL
962             }
963         },
964         { &hf_rlc_lte_am_e1,
965             { "Extension bit 1",
966               "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
967               "Extension bit 1", HFILL
968             }
969         },
970         { &hf_rlc_lte_am_e2,
971             { "Extension bit 2",
972               "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
973               "Extension bit 2", HFILL
974             }
975         },
976         { &hf_rlc_lte_am_nack_sn,
977             { "NACK Sequence Number",
978               "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
979               "Negative Acknowledgement Sequence Number", HFILL
980             }
981         },
982         { &hf_rlc_lte_am_so_start,
983             { "SO Start",
984               "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
985               "SO Start", HFILL
986             }
987         },
988         { &hf_rlc_lte_am_so_end,
989             { "SO End",
990               "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
991               "SO End", HFILL
992             }
993         },
994
995     };
996
997     static gint *ett[] =
998     {
999         &ett_rlc_lte,
1000         &ett_rlc_lte_um_header,
1001         &ett_rlc_lte_am_header,
1002         &ett_rlc_lte_extension_part,
1003     };
1004
1005     /* Register protocol. */
1006     proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
1007     proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
1008     proto_register_subtree_array(ett, array_length(ett));
1009
1010     /* Allow other dissectors to find this one by name. */
1011     register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
1012 }
1013
1014