Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-rlc-lte.c
Line
Count
Source
1
/* Routines for LTE RLC disassembly
2
 *
3
 * Martin Mathieson
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <epan/packet.h>
15
#include <epan/exceptions.h>
16
#include <epan/expert.h>
17
#include <epan/prefs.h>
18
#include <epan/tap.h>
19
#include <epan/proto_data.h>
20
#include <epan/tfs.h>
21
#include <wsutil/array.h>
22
#include "packet-mac-lte.h"
23
#include "packet-rlc-lte.h"
24
#include "packet-rlc-3gpp-common.h"
25
#include "packet-pdcp-lte.h"
26
27
28
/* Described in:
29
 * 3GPP TS 36.322 Evolved Universal Terrestrial Radio Access (E-UTRA)
30
 * Radio Link Control (RLC) Protocol specification v14.0.0
31
 */
32
33
/* TODO:
34
   - add intermediate results to segments leading to final reassembly
35
   - use multiple active rlc_channel_reassembly_info's per channel
36
   - sequence analysis gets confused when we change cells and skip back
37
     to SN 0. Maybe add cell-id to context and add to channel/result key?
38
*/
39
40
void proto_register_rlc_lte(void);
41
void proto_reg_handoff_rlc_lte(void);
42
43
/********************************/
44
/* Preference settings          */
45
46
30
#define SEQUENCE_ANALYSIS_MAC_ONLY 1
47
16
#define SEQUENCE_ANALYSIS_RLC_ONLY 2
48
49
/* By default do try to analyse the sequence of messages for AM/UM channels
50
   using MAC PDUs */
51
static int global_rlc_lte_am_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
52
static int global_rlc_lte_um_sequence_analysis = SEQUENCE_ANALYSIS_MAC_ONLY;
53
54
/* By default do call PDCP/RRC dissectors for SDU data */
55
static bool global_rlc_lte_call_pdcp_for_srb = true;
56
57
enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12, PDCP_drb_SN_signalled, PDCP_drb_SN_15, PDCP_drb_SN_18};
58
static const enum_val_t pdcp_drb_col_vals[] = {
59
    {"pdcp-drb-off",           "Off",                 PDCP_drb_off},
60
    {"pdcp-drb-sn-7",          "7-bit SN",            PDCP_drb_SN_7},
61
    {"pdcp-drb-sn-12",         "12-bit SN",           PDCP_drb_SN_12},
62
    {"pdcp-drb-sn-15",         "15-bit SN",           PDCP_drb_SN_15},
63
    {"pdcp-drb-sn-18",         "18-bit SN",           PDCP_drb_SN_18},
64
    {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
65
    {NULL, NULL, -1}
66
};
67
static int global_rlc_lte_call_pdcp_for_drb = (int)PDCP_drb_SN_signalled;
68
69
static bool global_rlc_lte_call_rrc_for_ccch = true;
70
static bool global_rlc_lte_call_rrc_for_mcch;
71
static bool global_rlc_lte_call_ip_for_mtch;
72
73
/* Preference to expect RLC headers without payloads */
74
static bool global_rlc_lte_headers_expected;
75
76
/* Re-assembly of segments */
77
static bool global_rlc_lte_reassembly = true;
78
79
/* Tree storing UE related parameters */
80
5
#define NO_EXT_LI 0x0
81
0
#define UL_EXT_LI 0x1
82
0
#define DL_EXT_LI 0x2
83
typedef struct rlc_ue_parameters {
84
    uint32_t id;
85
    uint8_t ext_li_field;
86
    uint8_t pdcp_sn_bits;
87
} rlc_ue_parameters;
88
static wmem_tree_t *ue_parameters_tree;
89
90
/**************************************************/
91
/* Initialize the protocol and registered fields. */
92
static int proto_rlc_lte;
93
94
static int proto_mac_lte;
95
static int proto_pdcp_lte;
96
97
static dissector_handle_t pdcp_lte_handle;
98
static dissector_handle_t ip_handle;
99
static dissector_handle_t lte_rrc_mcch;
100
static dissector_handle_t lte_rrc_ul_ccch;
101
static dissector_handle_t lte_rrc_dl_ccch;
102
static dissector_handle_t lte_rrc_bcch_bch;
103
static dissector_handle_t lte_rrc_bcch_dl_sch;
104
static dissector_handle_t lte_rrc_pcch;
105
static dissector_handle_t lte_rrc_ul_ccch_nb;
106
static dissector_handle_t lte_rrc_dl_ccch_nb;
107
static dissector_handle_t lte_rrc_bcch_bch_nb;
108
static dissector_handle_t lte_rrc_bcch_dl_sch_nb;
109
static dissector_handle_t lte_rrc_pcch_nb;
110
111
112
static int rlc_lte_tap;
113
114
/* Decoding context */
115
static int hf_rlc_lte_context;
116
static int hf_rlc_lte_context_mode;
117
static int hf_rlc_lte_context_direction;
118
static int hf_rlc_lte_context_priority;
119
static int hf_rlc_lte_context_ueid;
120
static int hf_rlc_lte_context_channel_type;
121
static int hf_rlc_lte_context_channel_id;
122
static int hf_rlc_lte_context_pdu_length;
123
static int hf_rlc_lte_context_um_sn_length;
124
static int hf_rlc_lte_context_am_sn_length;
125
126
/* Transparent mode fields */
127
static int hf_rlc_lte_tm;
128
static int hf_rlc_lte_tm_data;
129
130
/* Unacknowledged mode fields */
131
static int hf_rlc_lte_um;
132
static int hf_rlc_lte_um_header;
133
static int hf_rlc_lte_um_fi;
134
static int hf_rlc_lte_um_fixed_e;
135
static int hf_rlc_lte_um_sn;
136
static int hf_rlc_lte_um_fixed_reserved;
137
static int hf_rlc_lte_um_data;
138
static int hf_rlc_lte_extension_part;
139
140
/* Extended header (common to UM and AM) */
141
static int hf_rlc_lte_extension_e;
142
static int hf_rlc_lte_extension_li;
143
static int hf_rlc_lte_extension_padding;
144
145
146
/* Acknowledged mode fields */
147
static int hf_rlc_lte_am;
148
static int hf_rlc_lte_am_header;
149
static int hf_rlc_lte_am_data_control;
150
static int hf_rlc_lte_am_rf;
151
static int hf_rlc_lte_am_p;
152
static int hf_rlc_lte_am_fi;
153
static int hf_rlc_lte_am_fixed_e;
154
static int hf_rlc_lte_am_fixed_sn;
155
static int hf_rlc_lte_am_fixed_reserved;
156
static int hf_rlc_lte_am_segment_lsf16;
157
static int hf_rlc_lte_am_fixed_reserved2;
158
static int hf_rlc_lte_am_fixed_sn16;
159
static int hf_rlc_lte_am_segment_lsf;
160
static int hf_rlc_lte_am_segment_so;
161
static int hf_rlc_lte_am_segment_so16;
162
static int hf_rlc_lte_am_data;
163
164
/* Control fields */
165
static int hf_rlc_lte_am_cpt;
166
static int hf_rlc_lte_am_ack_sn;
167
static int hf_rlc_lte_am_e1;
168
static int hf_rlc_lte_am_e2;
169
static int hf_rlc_lte_am_nack_sn;
170
static int hf_rlc_lte_am_nacks;
171
static int hf_rlc_lte_am_so_start;
172
static int hf_rlc_lte_am_so_end;
173
174
static int hf_rlc_lte_predefined_pdu;
175
static int hf_rlc_lte_header_only;
176
177
/* Sequence Analysis */
178
static int hf_rlc_lte_sequence_analysis;
179
static int hf_rlc_lte_sequence_analysis_ok;
180
static int hf_rlc_lte_sequence_analysis_previous_frame;
181
static int hf_rlc_lte_sequence_analysis_next_frame;
182
static int hf_rlc_lte_sequence_analysis_expected_sn;
183
static int hf_rlc_lte_sequence_analysis_framing_info_correct;
184
185
static int hf_rlc_lte_sequence_analysis_mac_retx;
186
static int hf_rlc_lte_sequence_analysis_retx;
187
static int hf_rlc_lte_sequence_analysis_repeated;
188
static int hf_rlc_lte_sequence_analysis_skipped;
189
190
static int hf_rlc_lte_sequence_analysis_repeated_nack;
191
static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame;
192
193
static int hf_rlc_lte_sequence_analysis_ack_out_of_range;
194
static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame;
195
196
/* Reassembly */
197
static int hf_rlc_lte_reassembly_source;
198
static int hf_rlc_lte_reassembly_source_number_of_segments;
199
static int hf_rlc_lte_reassembly_source_total_length;
200
static int hf_rlc_lte_reassembly_source_segment;
201
static int hf_rlc_lte_reassembly_source_segment_sn;
202
static int hf_rlc_lte_reassembly_source_segment_framenum;
203
static int hf_rlc_lte_reassembly_source_segment_length;
204
205
/* Subtrees. */
206
static int ett_rlc_lte;
207
static int ett_rlc_lte_context;
208
static int ett_rlc_lte_um_header;
209
static int ett_rlc_lte_am_header;
210
static int ett_rlc_lte_extension_part;
211
static int ett_rlc_lte_sequence_analysis;
212
static int ett_rlc_lte_reassembly_source;
213
static int ett_rlc_lte_reassembly_source_segment;
214
215
static expert_field ei_rlc_lte_context_mode;
216
static expert_field ei_rlc_lte_am_nack_sn;
217
static expert_field ei_rlc_lte_am_nack_sn_ahead_ack;
218
static expert_field ei_rlc_lte_um_sn_repeated;
219
static expert_field ei_rlc_lte_am_nack_sn_ack_same;
220
static expert_field ei_rlc_lte_am_cpt;
221
static expert_field ei_rlc_lte_am_data_no_data;
222
static expert_field ei_rlc_lte_sequence_analysis_last_segment_complete;
223
static expert_field ei_rlc_lte_sequence_analysis_mac_retx;
224
static expert_field ei_rlc_lte_am_nack_sn_partial;
225
static expert_field ei_rlc_lte_sequence_analysis_repeated_nack;
226
static expert_field ei_rlc_lte_bytes_after_status_pdu_complete;
227
static expert_field ei_rlc_lte_sequence_analysis_repeated;
228
static expert_field ei_rlc_lte_wrong_sequence_number;
229
static expert_field ei_rlc_lte_sequence_analysis_retx;
230
static expert_field ei_rlc_lte_am_sn_missing;
231
static expert_field ei_rlc_lte_um_sn;
232
static expert_field ei_rlc_lte_header_only;
233
static expert_field ei_rlc_lte_am_data_no_data_beyond_extensions;
234
static expert_field ei_rlc_lte_um_sn_missing;
235
static expert_field ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame;
236
static expert_field ei_rlc_lte_sequence_analysis_last_segment_not_continued;
237
static expert_field ei_rlc_lte_reserved_bits_not_zero;
238
static expert_field ei_rlc_lte_no_per_frame_info;
239
static expert_field ei_rlc_lte_unknown_udp_framing_tag;
240
static expert_field ei_rlc_lte_missing_udp_framing_tag;
241
242
/* Value-strings */
243
static const value_string direction_vals[] =
244
{
245
    { DIRECTION_UPLINK,      "Uplink"},
246
    { DIRECTION_DOWNLINK,    "Downlink"},
247
    { 0, NULL }
248
};
249
250
static const value_string rlc_mode_short_vals[] =
251
{
252
    { RLC_TM_MODE,      "TM"},
253
    { RLC_UM_MODE,      "UM"},
254
    { RLC_AM_MODE,      "AM"},
255
    { RLC_PREDEF,       "PREDEFINED"},  /* For data testing */
256
    { 0, NULL }
257
};
258
259
static const value_string rlc_mode_vals[] =
260
{
261
    { RLC_TM_MODE,      "Transparent Mode"},
262
    { RLC_UM_MODE,      "Unacknowledged Mode"},
263
    { RLC_AM_MODE,      "Acknowledged Mode"},
264
    { 0, NULL }
265
};
266
267
static const value_string rlc_channel_type_vals[] =
268
{
269
    { CHANNEL_TYPE_CCCH,         "CCCH"},
270
    { CHANNEL_TYPE_BCCH_BCH,     "BCCH_BCH"},
271
    { CHANNEL_TYPE_PCCH,         "PCCH"},
272
    { CHANNEL_TYPE_SRB,          "SRB"},
273
    { CHANNEL_TYPE_DRB,          "DRB"},
274
    { CHANNEL_TYPE_BCCH_DL_SCH,  "BCCH_DL_SCH"},
275
    { CHANNEL_TYPE_MCCH,         "MCCH"},
276
    { CHANNEL_TYPE_MTCH,         "MTCH"},
277
    { 0, NULL }
278
};
279
280
static const value_string framing_info_vals[] =
281
{
282
    { 0,      "First byte begins a RLC SDU and last byte ends a RLC SDU"},
283
    { 1,      "First byte begins a RLC SDU and last byte does not end a RLC SDU"},
284
    { 2,      "First byte does not begin a RLC SDU and last byte ends a RLC SDU"},
285
    { 3,      "First byte does not begin a RLC SDU and last byte does not end a RLC SDU"},
286
    { 0, NULL }
287
};
288
289
static const value_string fixed_extension_vals[] =
290
{
291
    { 0,      "Data field follows from the octet following the fixed part of the header"},
292
    { 1,      "A set of E field and LI field follows from the octet following the fixed part of the header"},
293
    { 0, NULL }
294
};
295
296
static const value_string extension_extension_vals[] =
297
{
298
    { 0,      "Data field follows from the octet following the LI field following this E field"},
299
    { 1,      "A set of E field and LI field follows from the bit following the LI field following this E field"},
300
    { 0, NULL }
301
};
302
303
static const value_string resegmentation_flag_vals[] =
304
{
305
    { 0,      "AMD PDU"},
306
    { 1,      "AMD PDU segment"},
307
    { 0, NULL }
308
};
309
310
static const value_string polling_bit_vals[] =
311
{
312
    { 0,      "Status report not requested"},
313
    { 1,      "Status report is requested"},
314
    { 0, NULL }
315
};
316
317
static const value_string lsf_vals[] =
318
{
319
    { 0,      "Last byte of the AMD PDU segment does not correspond to the last byte of an AMD PDU"},
320
    { 1,      "Last byte of the AMD PDU segment corresponds to the last byte of an AMD PDU"},
321
    { 0, NULL }
322
};
323
324
static const value_string control_pdu_type_vals[] =
325
{
326
    { 0,      "STATUS PDU"},
327
    { 0, NULL }
328
};
329
330
static const value_string am_e1_vals[] =
331
{
332
    { 0,      "A set of NACK_SN, E1 and E2 does not follow"},
333
    { 1,      "A set of NACK_SN, E1 and E2 follows"},
334
    { 0, NULL }
335
};
336
337
static const value_string am_e2_vals[] =
338
{
339
    { 0,      "A set of SOstart and SOend does not follow for this NACK_SN"},
340
    { 1,      "A set of SOstart and SOend follows for this NACK_SN"},
341
    { 0, NULL }
342
};
343
344
static const value_string header_only_vals[] =
345
{
346
    { 0,      "RLC PDU Headers and body present"},
347
    { 1,      "RLC PDU Headers only"},
348
    { 0, NULL }
349
};
350
351
352
353
/**********************************************************************************/
354
/* These are for keeping track of UM/AM extension headers, and the lengths found  */
355
/* in them                                                                        */
356
static uint8_t s_number_of_extensions;
357
3
#define MAX_RLC_SDUS 192
358
static uint16_t s_lengths[MAX_RLC_SDUS];
359
360
361
/*********************************************************************/
362
/* UM/AM sequence analysis                                           */
363
364
/* Types for RLC channel hash table                                   */
365
/* This table is maintained during initial dissection of RLC          */
366
/* frames, mapping from channel_hash_key -> sequence_analysis_report  */
367
368
/* Channel key */
369
typedef struct
370
{
371
    unsigned  ueId : 16;
372
    unsigned  channelType : 3;
373
    unsigned  channelId : 5;
374
    unsigned  direction : 1;
375
} channel_hash_key;
376
377
378
/******************************************************************/
379
/* State maintained for AM/UM reassembly                          */
380
381
typedef struct rlc_segment {
382
    uint32_t frameNum;
383
    uint16_t SN;
384
    uint8_t *data;
385
    uint16_t length;
386
} rlc_segment;
387
388
typedef struct rlc_channel_reassembly_info
389
{
390
    uint16_t number_of_segments;
391
1
    #define RLC_MAX_SEGMENTS 100
392
    rlc_segment segments[RLC_MAX_SEGMENTS];
393
} rlc_channel_reassembly_info;
394
395
396
397
398
/*******************************************************************/
399
/* Conversation-type status for sequence analysis on channel       */
400
typedef struct
401
{
402
    uint8_t  rlcMode;
403
404
    /* For UM, we always expect the SN to keep advancing, and these fields
405
       keep track of this.
406
       For AM, these correspond to new data */
407
    uint16_t previousSequenceNumber;
408
    uint32_t previousFrameNum;
409
    bool previousSegmentIncomplete;
410
411
    /* Accumulate info about current segmented SDU */
412
    struct rlc_channel_reassembly_info *reassembly_info;
413
} channel_sequence_analysis_status;
414
415
/* The sequence analysis channel hash table (channel_hash_key* -> channel_sequence_analysis_status*) */
416
static wmem_map_t *sequence_analysis_channel_hash;
417
418
419
/* Types for sequence analysis frame report hash table                  */
420
/* This is a table from framenum -> state_report_in_frame               */
421
/* This is necessary because the per-packet info is already being used  */
422
/* for context information before the dissector is called               */
423
424
/* Info to attach to frame when first read, recording what to show about sequence */
425
typedef enum {
426
    SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window, SN_Error
427
} sequence_analysis_state;
428
429
430
typedef struct
431
{
432
    bool      sequenceExpectedCorrect;
433
    uint16_t  sequenceExpected;
434
    uint32_t  previousFrameNum;
435
    bool      previousSegmentIncomplete;
436
    uint32_t  nextFrameNum;
437
438
    uint16_t  firstSN;
439
    uint16_t  lastSN;
440
441
    /* AM/UM */
442
    sequence_analysis_state state;
443
} sequence_analysis_report;
444
445
446
/* The sequence analysis frame report hash table instance itself, lookup when visited */
447
/* rlc_result_hash_key* -> sequence_analysis_report* */
448
static wmem_map_t *sequence_analysis_report_hash;
449
450
451
static void *get_report_hash_key(uint16_t SN, uint32_t frameNumber,
452
                                    rlc_lte_info *p_rlc_lte_info,
453
                                    bool do_persist);
454
455
456
457
458
/* The reassembly result hash table */
459
static wmem_map_t *reassembly_report_hash;
460
461
462
/* Create a new struct for reassembly */
463
static void reassembly_reset(channel_sequence_analysis_status *status)
464
1
{
465
1
    status->reassembly_info = wmem_new0(wmem_file_scope(), rlc_channel_reassembly_info);
466
1
}
467
468
/* Hide previous one */
469
static void reassembly_destroy(channel_sequence_analysis_status *status)
470
1
{
471
    /* Just "leak" it. There seems to be no way to free this memory... */
472
1
    status->reassembly_info = NULL;
473
1
}
474
475
/* Add a new segment to the accumulating segmented SDU */
476
static void reassembly_add_segment(channel_sequence_analysis_status *status,
477
                                   uint16_t SN, uint32_t frame,
478
                                   tvbuff_t *tvb, unsigned offset, int length)
479
1
{
480
1
    int segment_number =  status->reassembly_info->number_of_segments;
481
1
    uint8_t *segment_data;
482
483
    /* Give up if reach segment limit */
484
1
    if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
485
0
        reassembly_destroy(status);
486
0
        return;
487
0
    }
488
489
1
    segment_data = (uint8_t *)tvb_memdup(wmem_file_scope(),tvb, offset, length);
490
491
    /* Add new segment */
492
1
    status->reassembly_info->segments[segment_number].frameNum = frame;
493
1
    status->reassembly_info->segments[segment_number].SN = SN;
494
1
    status->reassembly_info->segments[segment_number].data = segment_data;
495
1
    status->reassembly_info->segments[segment_number].length = length;
496
497
1
    status->reassembly_info->number_of_segments++;
498
1
}
499
500
501
/* Record the current & complete segmented SDU by mapping from this frame number to
502
   struct with segment info. */
503
static void reassembly_record(channel_sequence_analysis_status *status, packet_info *pinfo,
504
                              uint16_t SN, rlc_lte_info *p_rlc_lte_info)
505
0
{
506
    /* Just store existing info in hash table */
507
0
    wmem_map_insert(reassembly_report_hash,
508
0
                        get_report_hash_key(SN, pinfo->num, p_rlc_lte_info, true),
509
0
                        status->reassembly_info);
510
0
}
511
512
/* Create and return a tvb based upon contents of reassembly info */
513
static tvbuff_t* reassembly_get_reassembled_tvb(rlc_channel_reassembly_info *reassembly_info,
514
                                                tvbuff_t *parent_tvb, packet_info *pinfo)
515
0
{
516
0
    int n;
517
0
    unsigned   combined_length = 0;
518
0
    uint8_t *combined_data;
519
0
    unsigned combined_offset = 0;
520
0
    tvbuff_t *reassembled_tvb;
521
522
    /* Allocate buffer big enough to hold re-assembled data */
523
0
    for (n=0; n < reassembly_info->number_of_segments; n++) {
524
0
        combined_length += reassembly_info->segments[n].length;
525
0
    }
526
0
    combined_data = (uint8_t *)wmem_alloc(pinfo->pool, combined_length);
527
528
    /* Copy data into contiguous buffer */
529
0
    for (n=0; n < reassembly_info->number_of_segments; n++) {
530
0
        uint8_t *data = reassembly_info->segments[n].data;
531
0
        int length = reassembly_info->segments[n].length;
532
0
        memcpy(combined_data+combined_offset, data, length);
533
0
        combined_offset += length;
534
0
    }
535
536
    /* Create and return tvb with this data */
537
0
    reassembled_tvb = tvb_new_child_real_data(parent_tvb, combined_data, combined_offset, combined_offset);
538
0
    add_new_data_source(pinfo, reassembled_tvb, "Reassembled SDU");
539
0
    return reassembled_tvb;
540
0
}
541
542
/* Show where the segments came from for a reassembled SDU */
543
static void reassembly_show_source(rlc_channel_reassembly_info *reassembly_info,
544
                                   proto_tree *tree, tvbuff_t *tvb, unsigned offset)
545
0
{
546
0
    int n;
547
0
    proto_item *source_ti, *ti;
548
0
    proto_tree *source_tree;
549
0
    proto_item *segment_ti;
550
0
    proto_tree *segment_tree;
551
0
    unsigned   total_length=0;
552
553
    /* Create root of source info */
554
0
    source_ti = proto_tree_add_item(tree,
555
0
                                    hf_rlc_lte_reassembly_source,
556
0
                                    tvb, 0, 0, ENC_ASCII);
557
0
    source_tree = proto_item_add_subtree(source_ti, ett_rlc_lte_reassembly_source);
558
0
    proto_item_set_generated(source_ti);
559
560
0
    for (n=0; n < reassembly_info->number_of_segments; n++) {
561
0
        total_length += reassembly_info->segments[n].length;
562
0
    }
563
0
    proto_item_append_text(source_ti, " %u segments, %u bytes", reassembly_info->number_of_segments,
564
0
                           total_length);
565
566
    /* Number of segments */
567
0
    ti = proto_tree_add_uint(source_tree,
568
0
                             hf_rlc_lte_reassembly_source_number_of_segments,
569
0
                             tvb, 0, 0, reassembly_info->number_of_segments);
570
0
    proto_item_set_generated(ti);
571
572
    /* Total length */
573
0
    ti = proto_tree_add_uint(source_tree,
574
0
                             hf_rlc_lte_reassembly_source_total_length,
575
0
                             tvb, 0, 0, total_length);
576
0
    proto_item_set_generated(ti);
577
578
    /* Now add info about each segment in turn */
579
0
    for (n=0; n < reassembly_info->number_of_segments; n++) {
580
581
        /* Add next segment as a subtree */
582
0
        rlc_segment *segment = &(reassembly_info->segments[n]);
583
0
        proto_item_append_text(source_ti, " (SN=%u frame=%u len=%u)",
584
0
                               segment->SN, segment->frameNum, segment->length);
585
586
        /* N.B. assume last segment from passed-in tvb! */
587
0
        segment_ti = proto_tree_add_item(source_tree,
588
0
                                         hf_rlc_lte_reassembly_source_segment,
589
0
                                         tvb,
590
0
                                         (n == reassembly_info->number_of_segments-1) ? offset : 0,
591
0
                                         (n == reassembly_info->number_of_segments-1) ? segment->length : 0,
592
0
                                         ENC_NA);
593
0
        segment_tree = proto_item_add_subtree(segment_ti, ett_rlc_lte_reassembly_source_segment);
594
0
        proto_item_append_text(segment_ti, " (SN=%u frame=%u length=%u)",
595
0
                               segment->SN, segment->frameNum, segment->length);
596
0
        proto_item_set_generated(segment_ti);
597
598
        /* Add details to segment tree */
599
0
        ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_sn,
600
0
                                 tvb, 0, 0, segment->SN);
601
0
        proto_item_set_generated(ti);
602
0
        ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_framenum,
603
0
                                 tvb, 0, 0, segment->frameNum);
604
0
        proto_item_set_generated(ti);
605
0
        ti = proto_tree_add_uint(segment_tree, hf_rlc_lte_reassembly_source_segment_length,
606
0
                                 tvb, 0, 0, segment->length);
607
0
        proto_item_set_generated(ti);
608
0
    }
609
0
}
610
611
612
613
614
/******************************************************************/
615
/* Conversation-type status for repeated NACK checking on channel */
616
typedef struct
617
{
618
    uint16_t        noOfNACKs;
619
    uint16_t        NACKs[MAX_NACKs];
620
    uint32_t        frameNum;
621
} channel_repeated_nack_status;
622
623
static wmem_map_t *repeated_nack_channel_hash;
624
625
typedef struct {
626
    uint16_t        noOfNACKsRepeated;
627
    uint16_t        repeatedNACKs[MAX_NACKs];
628
    uint32_t        previousFrameNum;
629
} channel_repeated_nack_report;
630
631
static wmem_map_t *repeated_nack_report_hash;
632
633
634
635
/********************************************************/
636
/* Forward declarations & functions                     */
637
static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool is_udp_framing);
638
639
640
/* Write the given formatted text to:
641
   - the info column
642
   - the top-level RLC PDU item
643
   - another subtree item (if supplied) */
644
static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
645
                                     packet_info *pinfo, const char *format, ...) G_GNUC_PRINTF(4, 5);
646
static void write_pdu_label_and_info(proto_item *pdu_ti, proto_item *sub_ti,
647
                                     packet_info *pinfo, const char *format, ...)
648
61
{
649
61
    #define MAX_INFO_BUFFER 256
650
61
    static char info_buffer[MAX_INFO_BUFFER];
651
652
61
    va_list ap;
653
654
61
    va_start(ap, format);
655
61
    vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
656
61
    va_end(ap);
657
658
    /* Add to indicated places */
659
61
    col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
660
61
    proto_item_append_text(pdu_ti, "%s", info_buffer);
661
61
    if (sub_ti != NULL) {
662
17
        proto_item_append_text(sub_ti, "%s", info_buffer);
663
17
    }
664
61
}
665
666
/* Version of function above, where no vsnprintf() call needed
667
   - the info column
668
   - the top-level RLC PDU item
669
   - another subtree item (if supplied) */
670
static void write_pdu_label_and_info_literal(proto_item *pdu_ti, proto_item *sub_ti,
671
                                             packet_info *pinfo, const char *info_buffer)
672
21
{
673
    /* Add to indicated places */
674
21
    col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
675
21
    proto_item_append_text(pdu_ti, "%s", info_buffer);
676
21
    if (sub_ti != NULL) {
677
0
        proto_item_append_text(sub_ti, "%s", info_buffer);
678
0
    }
679
21
}
680
681
682
683
/* Dissect extension headers (common to both UM and AM) */
684
static int dissect_rlc_lte_extension_header(tvbuff_t *tvb, packet_info *pinfo _U_,
685
                                            proto_tree *tree,
686
                                            unsigned offset,
687
                                            rlc_lte_info *p_rlc_lte_info)
688
3
{
689
3
    uint8_t isOdd;
690
3
    uint64_t extension = 1;
691
3
    uint64_t length;
692
693
    /* Reset this count */
694
3
    s_number_of_extensions = 0;
695
696
6
    while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
697
3
        proto_tree *extension_part_tree;
698
3
        proto_item *extension_part_ti;
699
700
        /* Extension part subtree */
701
3
        extension_part_ti = proto_tree_add_string_format(tree,
702
3
                                                         hf_rlc_lte_extension_part,
703
3
                                                         tvb, offset, 2,
704
3
                                                         "",
705
3
                                                         "Extension Part");
706
3
        extension_part_tree = proto_item_add_subtree(extension_part_ti,
707
3
                                                     ett_rlc_lte_extension_part);
708
709
3
        if (p_rlc_lte_info->extendedLiField == false) {
710
3
            isOdd = (s_number_of_extensions % 2);
711
712
            /* Read next extension */
713
3
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
714
3
                                        (offset*8) + ((isOdd) ? 4 : 0),
715
3
                                        1,
716
3
                                        &extension, ENC_BIG_ENDIAN);
717
718
            /* Read length field */
719
3
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
720
3
                                        (offset*8) + ((isOdd) ? 5 : 1),
721
3
                                        11,
722
3
                                        &length, ENC_BIG_ENDIAN);
723
724
            /* Move on to byte of next extension */
725
3
            if (isOdd) {
726
0
                offset += 2;
727
3
            } else {
728
3
                offset++;
729
3
            }
730
3
        } else {
731
            /* Read next extension */
732
0
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
733
0
                                        (offset*8),
734
0
                                        1,
735
0
                                        &extension, ENC_BIG_ENDIAN);
736
737
            /* Read length field */
738
0
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
739
0
                                        (offset*8) + 1,
740
0
                                        15,
741
0
                                        &length, ENC_BIG_ENDIAN);
742
743
            /* Move on to byte of next extension */
744
0
            offset += 2;
745
0
        }
746
747
3
        proto_item_append_text(extension_part_tree, " (length=%u)", (uint16_t)length);
748
749
3
        s_lengths[s_number_of_extensions++] = (uint16_t)length;
750
3
    }
751
752
    /* May need to skip padding after last extension part */
753
3
    isOdd = (s_number_of_extensions % 2);
754
3
    if (isOdd && (p_rlc_lte_info->extendedLiField == false)) {
755
3
        proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
756
3
                            tvb, offset++, 1, ENC_BIG_ENDIAN);
757
3
    }
758
759
3
    return offset;
760
3
}
761
762
763
/* Show in the info column how many bytes are in the UM/AM PDU, and indicate
764
   whether or not the beginning and end are included in this packet */
765
static void show_PDU_in_info(packet_info *pinfo,
766
                             proto_item *top_ti,
767
                             int32_t length,
768
                             bool first_includes_start,
769
                             bool last_includes_end)
770
8
{
771
    /* Reflect this PDU in the info column */
772
8
    if (length > 0) {
773
5
        write_pdu_label_and_info(top_ti, NULL, pinfo,
774
5
                                 "  %s%u-byte%s%s",
775
5
                                 (first_includes_start) ? "[" : "..",
776
5
                                 length,
777
5
                                 (length > 1) ? "s" : "",
778
5
                                 (last_includes_end) ? "]" : "..");
779
5
    }
780
3
    else {
781
3
        write_pdu_label_and_info(top_ti, NULL, pinfo,
782
3
                                 "  %sunknown-bytes%s",
783
3
                                 (first_includes_start) ? "[" : "..",
784
3
                                 (last_includes_end) ? "]" : "..");
785
3
    }
786
8
}
787
788
789
/* Show an SDU. If configured, pass to PDCP/RRC/IP dissector */
790
static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, unsigned offset, int length,
791
                             rlc_lte_info *rlc_info, bool whole_pdu, rlc_channel_reassembly_info *reassembly_info,
792
                             sequence_analysis_state state)
793
8
{
794
8
    wmem_tree_key_t key[3];
795
8
    uint32_t id;
796
8
    rlc_ue_parameters *params;
797
798
    /* Add raw data (according to mode) */
799
8
    proto_item *data_ti = proto_tree_add_item(tree,
800
8
                                              (rlc_info->rlcMode == RLC_AM_MODE) ?
801
8
                                                    hf_rlc_lte_am_data :
802
8
                                                    hf_rlc_lte_um_data,
803
8
                                              tvb, offset, length, ENC_NA);
804
805
8
    if (whole_pdu || (reassembly_info != NULL)) {
806
0
        if (((global_rlc_lte_call_pdcp_for_srb) && (rlc_info->channelType == CHANNEL_TYPE_SRB)) ||
807
0
            ((global_rlc_lte_call_pdcp_for_drb != PDCP_drb_off) && (rlc_info->channelType == CHANNEL_TYPE_DRB))) {
808
            /* Send whole PDU to PDCP */
809
810
            /* TODO: made static to avoid compiler warning... */
811
0
            static tvbuff_t *pdcp_tvb = NULL;
812
0
            struct pdcp_lte_info *p_pdcp_lte_info;
813
814
            /* Get tvb for passing to LTE PDCP dissector */
815
0
            if (reassembly_info == NULL) {
816
0
                pdcp_tvb = tvb_new_subset_length(tvb, offset, length);
817
0
            }
818
0
            else {
819
                /* Get combined tvb. */
820
0
                pdcp_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
821
0
                reassembly_show_source(reassembly_info, tree, tvb, offset);
822
0
            }
823
824
            /* Reuse or allocate struct */
825
0
            p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
826
0
            if (p_pdcp_lte_info == NULL) {
827
0
                p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
828
                /* Store info in packet */
829
0
                p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0, p_pdcp_lte_info);
830
0
            }
831
832
0
            p_pdcp_lte_info->ueid = rlc_info->ueid;
833
0
            if (rlc_info->nbMode == rlc_nb_mode) {
834
0
                p_pdcp_lte_info->channelType = Channel_DCCH_NB;
835
0
            } else {
836
0
                p_pdcp_lte_info->channelType = Channel_DCCH;
837
0
            }
838
0
            p_pdcp_lte_info->channelId = rlc_info->channelId;
839
0
            p_pdcp_lte_info->direction = rlc_info->direction;
840
0
            p_pdcp_lte_info->is_retx = (state != SN_OK);
841
842
            /* Set plane and sequence number length */
843
0
            p_pdcp_lte_info->no_header_pdu = false;
844
0
            if (rlc_info->channelType == CHANNEL_TYPE_SRB) {
845
0
                p_pdcp_lte_info->plane = SIGNALING_PLANE;
846
0
                if ((rlc_info->nbMode == rlc_nb_mode) && (rlc_info->channelId == 3)) {
847
0
                    p_pdcp_lte_info->no_header_pdu = true;
848
0
                    p_pdcp_lte_info->seqnum_length = 0;
849
0
                } else {
850
0
                    p_pdcp_lte_info->seqnum_length = 5;
851
0
                }
852
0
            }
853
0
            else {
854
0
                p_pdcp_lte_info->plane = USER_PLANE;
855
0
                switch (global_rlc_lte_call_pdcp_for_drb) {
856
0
                    case PDCP_drb_SN_7:
857
0
                        p_pdcp_lte_info->seqnum_length = 7;
858
0
                        break;
859
0
                    case PDCP_drb_SN_12:
860
0
                        p_pdcp_lte_info->seqnum_length = 12;
861
0
                        break;
862
0
                    case PDCP_drb_SN_15:
863
0
                        p_pdcp_lte_info->seqnum_length = 15;
864
0
                        break;
865
0
                    case PDCP_drb_SN_18:
866
0
                        p_pdcp_lte_info->seqnum_length = 18;
867
0
                        break;
868
0
                    case PDCP_drb_SN_signalled:
869
                        /* Use whatever was signalled (e.g. in RRC) */
870
0
                        id = (rlc_info->channelId << 16) | rlc_info->ueid;
871
0
                        key[0].length = 1;
872
0
                        key[0].key = &id;
873
0
                        key[1].length = 1;
874
0
                        key[1].key = &pinfo->num;
875
0
                        key[2].length = 0;
876
0
                        key[2].key = NULL;
877
878
0
                        params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
879
0
                        if (params && (params->id != id)) {
880
0
                            params = NULL;
881
0
                        }
882
0
                        if (params) {
883
0
                            p_pdcp_lte_info->seqnum_length = params->pdcp_sn_bits;
884
0
                        } else if (rlc_info->nbMode == rlc_nb_mode) {
885
0
                            p_pdcp_lte_info->seqnum_length = 7;
886
0
                        } else {
887
0
                            p_pdcp_lte_info->seqnum_length = 12;
888
0
                        }
889
0
                        break;
890
891
0
                    default:
892
0
                        DISSECTOR_ASSERT(false);
893
0
                        break;
894
0
                }
895
0
            }
896
897
0
            TRY {
898
0
                call_dissector_only(pdcp_lte_handle, pdcp_tvb, pinfo, tree, NULL);
899
0
            }
900
0
            CATCH_ALL {
901
0
            }
902
0
            ENDTRY
903
904
0
            proto_item_set_hidden(data_ti);
905
0
        }
906
0
        else if (global_rlc_lte_call_rrc_for_mcch && (rlc_info->channelType == CHANNEL_TYPE_MCCH)) {
907
            /* Send whole PDU to RRC */
908
0
            static tvbuff_t *rrc_tvb = NULL;
909
910
            /* Get tvb for passing to LTE RRC dissector */
911
0
            if (reassembly_info == NULL) {
912
0
                rrc_tvb = tvb_new_subset_length(tvb, offset, length);
913
0
            }
914
0
            else {
915
                /* Get combined tvb. */
916
0
                rrc_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
917
0
                reassembly_show_source(reassembly_info, tree, tvb, offset);
918
0
            }
919
920
0
            TRY {
921
0
                call_dissector_only(lte_rrc_mcch, rrc_tvb, pinfo, tree, NULL);
922
0
            }
923
0
            CATCH_ALL {
924
0
            }
925
0
            ENDTRY
926
927
0
            proto_item_set_hidden(data_ti);
928
0
        }
929
0
        else if (global_rlc_lte_call_ip_for_mtch && (rlc_info->channelType == CHANNEL_TYPE_MTCH)) {
930
            /* Send whole PDU to IP */
931
0
            static tvbuff_t *ip_tvb = NULL;
932
933
            /* Get tvb for passing to IP dissector */
934
0
            if (reassembly_info == NULL) {
935
0
                ip_tvb = tvb_new_subset_length(tvb, offset, length);
936
0
            }
937
0
            else {
938
                /* Get combined tvb. */
939
0
                ip_tvb = reassembly_get_reassembled_tvb(reassembly_info, tvb, pinfo);
940
0
                reassembly_show_source(reassembly_info, tree, tvb, offset);
941
0
            }
942
943
0
            TRY {
944
0
                call_dissector_only(ip_handle, ip_tvb, pinfo, tree, NULL);
945
0
            }
946
0
            CATCH_ALL {
947
0
            }
948
0
            ENDTRY
949
950
0
            proto_item_set_hidden(data_ti);
951
0
        }
952
0
    }
953
8
}
954
955
/* Hash table functions for RLC channels */
956
957
/* Equal keys */
958
static int rlc_channel_equal(const void *v, const void *v2)
959
16
{
960
16
    const channel_hash_key* val1 = (const channel_hash_key *)v;
961
16
    const channel_hash_key* val2 = (const channel_hash_key *)v2;
962
963
    /* All fields must match */
964
    /* N.B. Currently fits into one word, so could return (*v == *v2)
965
       if we're sure they're initialised to 0... */
966
16
    return ((val1->ueId        == val2->ueId) &&
967
16
            (val1->channelType == val2->channelType) &&
968
16
            (val1->channelId   == val2->channelId) &&
969
16
            (val1->direction   == val2->direction));
970
16
}
971
972
/* Compute a hash value for a given key. */
973
static unsigned rlc_channel_hash_func(const void *v)
974
18
{
975
18
    const channel_hash_key* val1 = (const channel_hash_key *)v;
976
977
    /* TODO: check/reduce multipliers */
978
18
    return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
979
18
}
980
981
982
/*************************************************************************/
983
/* Result hash                                                           */
984
985
typedef struct {
986
    uint32_t          frameNumber;
987
    uint32_t          SN :             10;
988
    uint32_t          channelType :    2;
989
    uint32_t          channelId:       5;
990
    uint32_t          direction:       1;
991
} rlc_result_hash_key;
992
993
/* Compare 2 rlc_result_hash_key structs */
994
static int rlc_result_hash_equal(const void *v, const void *v2)
995
5
{
996
5
    const rlc_result_hash_key *val1 = (const rlc_result_hash_key *)v;
997
5
    const rlc_result_hash_key *val2 = (const rlc_result_hash_key *)v2;
998
999
    /* All fields (and any padding...) must match */
1000
5
    return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
1001
5
}
1002
1003
/* Compute a hash value for a given key. */
1004
static unsigned rlc_result_hash_func(const void *v)
1005
10
{
1006
10
    const rlc_result_hash_key* val1 = (const rlc_result_hash_key *)v;
1007
1008
    /* Got rid of multipliers - no evidence that they reduced collisions */
1009
10
    return val1->frameNumber + val1->SN +
1010
10
                               val1->channelType +
1011
10
                               val1->channelId +
1012
10
                               val1->direction;
1013
10
}
1014
1015
/* Convenience function to get a pointer for the hash_func to work with */
1016
static void *get_report_hash_key(uint16_t SN, uint32_t frameNumber,
1017
                                    rlc_lte_info *p_rlc_lte_info,
1018
                                    bool do_persist)
1019
15
{
1020
15
    static rlc_result_hash_key key;
1021
15
    rlc_result_hash_key *p_key;
1022
1023
    /* Only allocate a struct when will be adding entry */
1024
15
    if (do_persist) {
1025
10
        p_key = wmem_new0(wmem_file_scope(), rlc_result_hash_key);
1026
10
    }
1027
5
    else {
1028
5
        memset(&key, 0, sizeof(rlc_result_hash_key));
1029
5
        p_key = &key;
1030
5
    }
1031
1032
    /* Fill in details, and return pointer */
1033
15
    p_key->frameNumber = frameNumber;
1034
15
    p_key->SN = SN;
1035
15
    p_key->channelType = p_rlc_lte_info->channelType;
1036
15
    p_key->channelId = p_rlc_lte_info->channelId;
1037
15
    p_key->direction = p_rlc_lte_info->direction;
1038
1039
15
    return p_key;
1040
15
}
1041
1042
static void checkFIconsistency(sequence_analysis_report *p,
1043
                               rlc_lte_info *p_rlc_lte_info,
1044
                               bool      newSegmentStarted,
1045
                               proto_tree *seqnum_tree,
1046
                               packet_info *pinfo, tvbuff_t *tvb)
1047
0
{
1048
0
    proto_item *ti;
1049
1050
0
    if (p->previousSegmentIncomplete) {
1051
        /* Previous segment was incomplete, so this PDU should continue it */
1052
0
        if (newSegmentStarted) {
1053
0
            ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1054
0
                                         tvb, 0, 0, false);
1055
0
            expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_not_continued,
1056
0
                                   "Last segment of previous PDU was not continued for UE %u (%s-%u)",
1057
0
                                   p_rlc_lte_info->ueid,
1058
0
                                   val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1059
0
                                   p_rlc_lte_info->channelId);
1060
0
        }
1061
0
        else {
1062
0
           ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1063
0
                                       tvb, 0, 0, true);
1064
0
           proto_item_set_hidden(ti);
1065
0
        }
1066
0
    }
1067
0
    else {
1068
        /* Previous segment was complete, so this PDU should start a new one */
1069
0
        if (!newSegmentStarted) {
1070
0
            ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1071
0
                                        tvb, 0, 0, false);
1072
0
            expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_last_segment_complete,
1073
0
                                   "Last segment of previous PDU was complete, but new segment was not started on UE %u (%s-%u)",
1074
0
                                   p_rlc_lte_info->ueid,
1075
0
                                   val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1076
0
                                   p_rlc_lte_info->channelId);
1077
0
        }
1078
0
        else {
1079
0
           ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_framing_info_correct,
1080
0
                                       tvb, 0, 0, true);
1081
0
           proto_item_set_hidden(ti);
1082
0
        }
1083
0
    }
1084
0
    proto_item_set_generated(ti);
1085
0
}
1086
1087
/* Add to the tree values associated with sequence analysis for this frame */
1088
static void addChannelSequenceInfo(sequence_analysis_report *p,
1089
                                   bool isControlFrame,
1090
                                   rlc_lte_info *p_rlc_lte_info,
1091
                                   uint16_t  sequenceNumber,
1092
                                   bool      newSegmentStarted,
1093
                                   rlc_3gpp_tap_info *tap_info,
1094
                                   packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
1095
10
{
1096
10
    proto_tree *seqnum_tree;
1097
10
    proto_item *seqnum_ti;
1098
10
    proto_item *ti;
1099
1100
    /* Create subtree */
1101
10
    seqnum_ti = proto_tree_add_string_format(tree,
1102
10
                                             hf_rlc_lte_sequence_analysis,
1103
10
                                             tvb, 0, 0,
1104
10
                                             "", "Sequence Analysis");
1105
10
    seqnum_tree = proto_item_add_subtree(seqnum_ti,
1106
10
                                         ett_rlc_lte_sequence_analysis);
1107
10
    proto_item_set_generated(seqnum_ti);
1108
1109
10
    if (p->previousFrameNum != 0) {
1110
5
        ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1111
5
                                 tvb, 0, 0, p->previousFrameNum);
1112
5
        proto_item_set_generated(ti);
1113
5
    }
1114
1115
10
    switch (p_rlc_lte_info->rlcMode) {
1116
10
        case RLC_AM_MODE:
1117
1118
            /********************************************/
1119
            /* AM                                       */
1120
            /********************************************/
1121
1122
10
            switch (p->state) {
1123
1
                case SN_OK:
1124
1
                    if (isControlFrame) {
1125
0
                        return;
1126
0
                    }
1127
1128
1
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1129
1
                                                tvb, 0, 0, true);
1130
1
                    proto_item_set_generated(ti);
1131
1
                    proto_item_append_text(seqnum_ti, " - OK");
1132
1133
                    /* Link to next SN in channel (if known) */
1134
1
                    if (p->nextFrameNum != 0) {
1135
0
                        proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1136
0
                                            tvb, 0, 0, p->nextFrameNum);
1137
0
                    }
1138
                    /* Correct sequence number, so check frame indication bits consistent */
1139
                    /* Deactivated for now as it gets confused by resegmentation */
1140
                    /* checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb); */
1141
1
                    break;
1142
1143
0
                case SN_MAC_Retx:
1144
0
                    if (isControlFrame) {
1145
0
                        return;
1146
0
                    }
1147
1148
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1149
0
                                                tvb, 0, 0, false);
1150
0
                    proto_item_set_generated(ti);
1151
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1152
0
                                                tvb, 0, 0, true);
1153
0
                    proto_item_set_generated(ti);
1154
0
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1155
0
                                           "AM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1156
0
                                           val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1157
0
                                           p_rlc_lte_info->ueid,
1158
0
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1159
0
                                           p_rlc_lte_info->channelId);
1160
0
                    proto_item_append_text(seqnum_ti, " - MAC retx of SN %u", p->firstSN);
1161
0
                    break;
1162
1163
3
                case SN_Retx:
1164
3
                    if (isControlFrame) {
1165
0
                        return;
1166
0
                    }
1167
1168
3
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1169
3
                                                tvb, 0, 0, false);
1170
3
                    proto_item_set_generated(ti);
1171
3
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
1172
3
                                                tvb, 0, 0, true);
1173
3
                    proto_item_set_generated(ti);
1174
3
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_retx,
1175
3
                                           "AM Frame retransmitted for %s on UE %u - most likely in response to NACK (%s-%u)",
1176
3
                                           val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1177
3
                                           p_rlc_lte_info->ueid,
1178
3
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1179
3
                                           p_rlc_lte_info->channelId);
1180
3
                    proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
1181
3
                    break;
1182
1183
0
                case SN_Repeated:
1184
0
                    if (isControlFrame) {
1185
0
                        return;
1186
0
                    }
1187
1188
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1189
0
                                                tvb, 0, 0, false);
1190
0
                    proto_item_set_generated(ti);
1191
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1192
0
                                                tvb, 0, 0, true);
1193
0
                    proto_item_set_generated(ti);
1194
0
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated,
1195
0
                                           "AM SN Repeated for %s for UE %u - probably because didn't receive Status PDU? (%s-%u)",
1196
0
                                           val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1197
0
                                           p_rlc_lte_info->ueid,
1198
0
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1199
0
                                           p_rlc_lte_info->channelId);
1200
0
                    proto_item_append_text(seqnum_ti, "- SN %u Repeated", p->firstSN);
1201
0
                    break;
1202
1203
1
                case SN_Missing:
1204
1
                    if (isControlFrame) {
1205
0
                        return;
1206
0
                    }
1207
1208
1
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1209
1
                                                tvb, 0, 0, false);
1210
1
                    proto_item_set_generated(ti);
1211
1
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1212
1
                                                tvb, 0, 0, true);
1213
1
                    proto_item_set_generated(ti);
1214
1
                    if (p->lastSN != p->firstSN) {
1215
1
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1216
1
                                               "AM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1217
1
                                               p->firstSN, p->lastSN,
1218
1
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1219
1
                                               p_rlc_lte_info->ueid,
1220
1
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1221
1
                                               p_rlc_lte_info->channelId);
1222
1
                        proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1223
1
                                               p->firstSN, p->lastSN);
1224
1
                        if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1225
0
                            tap_info->missingSNs = ((65536 + (uint32_t)p->lastSN - (uint32_t)p->firstSN) % 65536) + 1;
1226
1
                        } else {
1227
1
                            tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1228
1
                        }
1229
1
                    }
1230
0
                    else {
1231
0
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1232
0
                                               "AM SN (%u) missing for %s on UE %u (%s-%u)",
1233
0
                                               p->firstSN,
1234
0
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1235
0
                                               p_rlc_lte_info->ueid,
1236
0
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1237
0
                                               p_rlc_lte_info->channelId);
1238
0
                        proto_item_append_text(seqnum_ti, " - SN missing (%u)", p->firstSN);
1239
0
                        tap_info->missingSNs = 1;
1240
0
                    }
1241
1
                    break;
1242
1243
5
                case ACK_Out_of_Window:
1244
5
                    if (!isControlFrame) {
1245
0
                        return;
1246
0
                    }
1247
1248
1249
                    /* Not OK */
1250
5
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1251
5
                                                tvb, 0, 0, false);
1252
                    /* Out of range */
1253
5
                    proto_item_set_generated(ti);
1254
5
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1255
5
                                                tvb, 0, 0, true);
1256
5
                    proto_item_set_generated(ti);
1257
1258
                    /* Link back to last seen SN in other direction */
1259
5
                    ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1260
5
                                             tvb, 0, 0, p->previousFrameNum);
1261
5
                    proto_item_set_generated(ti);
1262
1263
                    /* Expert error */
1264
5
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1265
5
                                           "AM ACK for SN %u - but last received SN in other direction is %u for UE %u (%s-%u)",
1266
5
                                           p->firstSN, p->sequenceExpected,
1267
5
                                           p_rlc_lte_info->ueid,
1268
5
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1269
5
                                           p_rlc_lte_info->channelId);
1270
5
                    proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1271
5
                                           p->firstSN, p->sequenceExpected);
1272
1273
5
                    break;
1274
1275
0
                default:
1276
0
                    return;
1277
10
            }
1278
10
            break;
1279
1280
10
        case RLC_UM_MODE:
1281
1282
            /********************************************/
1283
            /* UM                                       */
1284
            /********************************************/
1285
1286
            /* Expected sequence number */
1287
0
            ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_expected_sn,
1288
0
                                    tvb, 0, 0, p->sequenceExpected);
1289
0
            proto_item_set_generated(ti);
1290
0
            if (p->sequenceExpectedCorrect) {
1291
0
                proto_item_set_hidden(ti);
1292
0
            }
1293
1294
0
            if (!p->sequenceExpectedCorrect) {
1295
                /* Work out SN wrap (in case needed below) */
1296
0
                uint16_t snLimit;
1297
0
                if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1298
0
                    snLimit = 32;
1299
0
                }
1300
0
                else {
1301
0
                    snLimit = 1024;
1302
0
                }
1303
1304
0
                switch (p->state) {
1305
0
                    case SN_Missing:
1306
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1307
0
                                                    tvb, 0, 0, false);
1308
0
                        proto_item_set_generated(ti);
1309
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1310
0
                                                    tvb, 0, 0, true);
1311
0
                        proto_item_set_generated(ti);
1312
0
                        if (p->lastSN != p->firstSN) {
1313
0
                            expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1314
0
                                                   "UM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1315
0
                                                   p->firstSN, p->lastSN,
1316
0
                                                   val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1317
0
                                                   p_rlc_lte_info->ueid,
1318
0
                                                   val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1319
0
                                                   p_rlc_lte_info->channelId);
1320
0
                            proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1321
0
                                                   p->firstSN, p->lastSN);
1322
0
                            tap_info->missingSNs = ((snLimit + p->lastSN - p->firstSN) % snLimit) + 1;
1323
0
                        }
1324
0
                        else {
1325
0
                            expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_missing,
1326
0
                                                   "UM SN (%u) missing for %s on UE %u (%s-%u)",
1327
0
                                                   p->firstSN,
1328
0
                                                   val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1329
0
                                                   p_rlc_lte_info->ueid,
1330
0
                                                   val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1331
0
                                                   p_rlc_lte_info->channelId);
1332
0
                            proto_item_append_text(seqnum_ti, " - SN missing (%u)",
1333
0
                                                   p->firstSN);
1334
0
                            tap_info->missingSNs = 1;
1335
0
                        }
1336
0
                        break;
1337
1338
0
                    case SN_Repeated:
1339
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1340
0
                                                    tvb, 0, 0, false);
1341
0
                        proto_item_set_generated(ti);
1342
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated,
1343
0
                                                    tvb, 0, 0, true);
1344
0
                        proto_item_set_generated(ti);
1345
0
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_um_sn_repeated,
1346
0
                                               "UM SN (%u) repeated for %s for UE %u (%s-%u)",
1347
0
                                               p->firstSN,
1348
0
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1349
0
                                               p_rlc_lte_info->ueid,
1350
0
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1351
0
                                               p_rlc_lte_info->channelId);
1352
0
                        proto_item_append_text(seqnum_ti, "- SN %u Repeated",
1353
0
                                               p->firstSN);
1354
0
                        break;
1355
1356
0
                    case SN_MAC_Retx:
1357
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1358
0
                                                    tvb, 0, 0, false);
1359
0
                        proto_item_set_generated(ti);
1360
0
                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_mac_retx,
1361
0
                                                    tvb, 0, 0, true);
1362
0
                        proto_item_set_generated(ti);
1363
0
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_mac_retx,
1364
0
                                               "UM Frame retransmitted for %s on UE %u - due to MAC retx! (%s-%u)",
1365
0
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1366
0
                                               p_rlc_lte_info->ueid,
1367
0
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1368
0
                                               p_rlc_lte_info->channelId);
1369
0
                        break;
1370
1371
0
                    default:
1372
                        /* Incorrect sequence number */
1373
0
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_wrong_sequence_number,
1374
0
                                               "Wrong Sequence Number for %s on UE %u - got %u, expected %u (%s-%u)",
1375
0
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1376
0
                                               p_rlc_lte_info->ueid, sequenceNumber, p->sequenceExpected,
1377
0
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1378
0
                                               p_rlc_lte_info->channelId);
1379
1380
0
                        break;
1381
0
                }
1382
1383
0
            }
1384
0
            else {
1385
                /* Correct sequence number, so check frame indication bits consistent */
1386
0
                checkFIconsistency(p, p_rlc_lte_info, newSegmentStarted, seqnum_tree, pinfo, tvb);
1387
1388
                /* Set OK here! */
1389
0
                ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1390
0
                                            tvb, 0, 0, true);
1391
0
                proto_item_set_generated(ti);
1392
0
                proto_item_append_text(seqnum_ti, " - OK");
1393
0
            }
1394
1395
            /* Next channel frame */
1396
0
            if (p->nextFrameNum != 0) {
1397
0
                ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_next_frame,
1398
0
                                         tvb, 0, 0, p->nextFrameNum);
1399
0
                proto_item_set_generated(ti);
1400
0
            }
1401
10
    }
1402
10
}
1403
1404
/* Update the channel status and set report for this frame */
1405
static sequence_analysis_state checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
1406
                                                        rlc_lte_info *p_rlc_lte_info,
1407
                                                        bool isControlFrame,
1408
                                                        uint8_t number_of_segments,
1409
                                                        uint16_t firstSegmentOffset,
1410
                                                        uint16_t firstSegmentLength,
1411
                                                        uint16_t lastSegmentOffset,
1412
                                                        uint16_t sequenceNumber,
1413
                                                        bool first_includes_start, bool last_includes_end,
1414
                                                        bool is_resegmented _U_,
1415
                                                        rlc_3gpp_tap_info *tap_info,
1416
                                                        proto_tree *tree)
1417
5
{
1418
5
    channel_hash_key   channel_key;
1419
5
    channel_hash_key   *p_channel_key;
1420
5
    channel_sequence_analysis_status     *p_channel_status;
1421
5
    sequence_analysis_report *p_report_in_frame = NULL;
1422
5
    bool                   createdChannel = false;
1423
5
    uint16_t               expectedSequenceNumber = 0;
1424
5
    uint32_t               snLimit = 0;
1425
1426
    /* If find stat_report_in_frame already, use that and get out */
1427
5
    if (pinfo->fd->visited) {
1428
0
        p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1429
0
                                                                           get_report_hash_key(sequenceNumber,
1430
0
                                                                                               pinfo->num,
1431
0
                                                                                               p_rlc_lte_info,
1432
0
                                                                                               false));
1433
0
        if (p_report_in_frame != NULL) {
1434
0
            addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
1435
0
                                   sequenceNumber, first_includes_start,
1436
0
                                   tap_info, pinfo, tree, tvb);
1437
0
            return p_report_in_frame->state;
1438
0
        }
1439
1440
        /* Don't just give up here... */
1441
0
    }
1442
1443
1444
    /**************************************************/
1445
    /* Create or find an entry for this channel state */
1446
5
    channel_key.ueId = p_rlc_lte_info->ueid;
1447
5
    channel_key.channelType = p_rlc_lte_info->channelType;
1448
5
    channel_key.channelId = p_rlc_lte_info->channelId;
1449
5
    channel_key.direction = p_rlc_lte_info->direction;
1450
1451
    /* Do the table lookup */
1452
5
    p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1453
1454
    /* Create table entry if necessary */
1455
5
    if (p_channel_status == NULL) {
1456
1
        createdChannel = true;
1457
1458
        /* Allocate a new value and duplicate key contents */
1459
1
        p_channel_status = wmem_new0(wmem_file_scope(), channel_sequence_analysis_status);
1460
1
        p_channel_key = (channel_hash_key *)wmem_memdup(wmem_file_scope(), &channel_key, sizeof(channel_hash_key));
1461
1462
        /* Set mode */
1463
1
        p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1464
1465
        /* Add entry */
1466
1
        wmem_map_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1467
1
    }
1468
1469
    /* Create space for frame state_report */
1470
5
    p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1471
1472
1473
    /* Deal with according to channel mode */
1474
5
    switch (p_channel_status->rlcMode) {
1475
0
        case RLC_UM_MODE:
1476
1477
0
            if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1478
0
                snLimit = 32;
1479
0
            }
1480
0
            else {
1481
0
                snLimit = 1024;
1482
0
            }
1483
1484
            /* Work out expected sequence number */
1485
0
            if (!createdChannel) {
1486
0
                expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1487
0
            }
1488
0
            else {
1489
                /* Whatever we got is fine.. */
1490
0
                expectedSequenceNumber = sequenceNumber;
1491
0
            }
1492
1493
0
            if ((sequenceNumber == 0) &&
1494
0
                ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH))) {
1495
                /* With eMBMS, SN restarts to 0 at each MCH Scheduling Period so we cannot deduce easily whether
1496
                   there was a PDU loss or not without analysing the Frame Indicator; assume no loss when seeing 0 */
1497
0
                expectedSequenceNumber = 0;
1498
0
            }
1499
1500
            /* Set report for this frame */
1501
            /* For UM, sequence number is always expectedSequence number */
1502
0
            p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
1503
1504
            /* For wrong sequence number... */
1505
0
            if (!p_report_in_frame->sequenceExpectedCorrect) {
1506
1507
                /* Don't get confused by MAC (HARQ) retx */
1508
0
                if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1509
0
                    p_report_in_frame->state = SN_MAC_Retx;
1510
0
                    p_report_in_frame->firstSN = sequenceNumber;
1511
1512
                    /* No channel state to update */
1513
0
                    break;
1514
0
                }
1515
1516
                /* Frames are not missing if we get an earlier sequence number again */
1517
                /* TODO: taking time into account would give better idea of whether missing or repeated... */
1518
0
                else if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH) ||
1519
0
                         (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10)) {
1520
0
                    reassembly_destroy(p_channel_status);
1521
1522
0
                    p_report_in_frame->state = SN_Missing;
1523
0
                    tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
1524
0
                    p_report_in_frame->firstSN = expectedSequenceNumber;
1525
0
                    p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
1526
1527
0
                    p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1528
0
                    p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1529
0
                    p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1530
1531
                    /* Update channel status to remember *this* frame */
1532
0
                    p_channel_status->previousFrameNum = pinfo->num;
1533
0
                    p_channel_status->previousSequenceNumber = sequenceNumber;
1534
0
                    p_channel_status->previousSegmentIncomplete = !last_includes_end;
1535
0
                }
1536
0
                else {
1537
                    /* An SN has been repeated */
1538
0
                    p_report_in_frame->state = SN_Repeated;
1539
0
                    p_report_in_frame->firstSN = sequenceNumber;
1540
1541
0
                    p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1542
0
                    p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1543
0
                }
1544
0
            }
1545
0
            else {
1546
                /* SN was OK */
1547
0
                p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1548
0
                p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1549
0
                p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1550
1551
                /* Update channel status to remember *this* frame */
1552
0
                p_channel_status->previousFrameNum = pinfo->num;
1553
0
                p_channel_status->previousSequenceNumber = sequenceNumber;
1554
0
                p_channel_status->previousSegmentIncomplete = !last_includes_end;
1555
1556
0
                if (p_channel_status->reassembly_info) {
1557
                    /* Add next segment to reassembly info */
1558
0
                    reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1559
0
                                           tvb, firstSegmentOffset, firstSegmentLength);
1560
1561
                    /* The end of existing reassembly? */
1562
0
                    if (!first_includes_start &&
1563
0
                        ((number_of_segments > 1) || last_includes_end)) {
1564
1565
0
                        reassembly_record(p_channel_status, pinfo, sequenceNumber, p_rlc_lte_info);
1566
0
                        reassembly_destroy(p_channel_status);
1567
0
                    }
1568
0
                }
1569
1570
                /* The start of a new reassembly? */
1571
0
                if (!last_includes_end &&
1572
0
                    ((number_of_segments > 1) || first_includes_start)) {
1573
1574
0
                    uint16_t lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1575
1576
0
                    if (global_rlc_lte_reassembly) {
1577
0
                        reassembly_reset(p_channel_status);
1578
0
                        reassembly_add_segment(p_channel_status, sequenceNumber,
1579
0
                                               pinfo->num,
1580
0
                                               tvb, lastSegmentOffset, lastSegmentLength);
1581
0
                    }
1582
0
                }
1583
1584
0
                if (p_report_in_frame->previousFrameNum != 0) {
1585
                    /* Get report for previous frame */
1586
0
                    sequence_analysis_report *p_previous_report;
1587
0
                    if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
1588
0
                        snLimit = 32;
1589
0
                    }
1590
0
                    else {
1591
0
                        snLimit = 1024;
1592
0
                    }
1593
1594
                    /* Look up report for previous SN */
1595
0
                    p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1596
0
                                                                                       get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1597
0
                                                                                                           p_report_in_frame->previousFrameNum,
1598
0
                                                                                                           p_rlc_lte_info,
1599
0
                                                                                                           false));
1600
                    /* It really shouldn't be NULL... */
1601
0
                    if (p_previous_report != NULL) {
1602
                        /* Point it forward to this one */
1603
0
                        p_previous_report->nextFrameNum = pinfo->num;
1604
0
                    }
1605
0
                }
1606
0
            }
1607
1608
0
            break;
1609
1610
5
        case RLC_AM_MODE:
1611
1612
5
            if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1613
0
                snLimit = 65536;
1614
5
            } else {
1615
5
                snLimit = 1024;
1616
5
            }
1617
1618
            /* Work out expected sequence number */
1619
5
            if (!createdChannel) {
1620
4
                expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1621
4
            }
1622
1
            else {
1623
                /* Whatever we got is fine.. */
1624
1
                expectedSequenceNumber = sequenceNumber;
1625
1
            }
1626
1627
            /* For AM, may be:
1628
               - expected Sequence number OR
1629
               - previous frame repeated
1630
               - old SN being sent (in response to NACK)
1631
               - new SN, but with frames missed out
1632
               Assume window whose front is at expectedSequenceNumber */
1633
1634
            /* First of all, check to see whether frame is judged to be MAC Retx */
1635
5
            if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
1636
                /* Just report that this is a MAC Retx */
1637
0
                p_report_in_frame->state = SN_MAC_Retx;
1638
0
                p_report_in_frame->firstSN = sequenceNumber;
1639
1640
                /* No channel state to update */
1641
0
                break;
1642
0
            }
1643
1644
5
            if (sequenceNumber != expectedSequenceNumber) {
1645
                /* Don't trash reassembly info if this looks like a close  retx... */
1646
4
                if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 50) {
1647
1
                    reassembly_destroy(p_channel_status);
1648
1
                }
1649
4
            }
1650
1651
            /* Expected? */
1652
5
            if (sequenceNumber == expectedSequenceNumber) {
1653
                /* Set report for this frame */
1654
1
                p_report_in_frame->sequenceExpectedCorrect = true;
1655
1
                p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1656
1
                p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1657
1
                p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1658
1
                p_report_in_frame->state = SN_OK;
1659
1660
                /* Update channel status */
1661
1
                p_channel_status->previousSequenceNumber = sequenceNumber;
1662
1
                p_channel_status->previousFrameNum = pinfo->num;
1663
1
                p_channel_status->previousSegmentIncomplete = !last_includes_end;
1664
1665
1666
1
                if (p_channel_status->reassembly_info) {
1667
1668
                    /* Add next segment to reassembly info */
1669
0
                    reassembly_add_segment(p_channel_status, sequenceNumber, pinfo->num,
1670
0
                                           tvb, firstSegmentOffset, firstSegmentLength);
1671
1672
                    /* The end of existing reassembly? */
1673
0
                    if (!first_includes_start &&
1674
0
                        ((number_of_segments > 1) || last_includes_end)) {
1675
1676
0
                        reassembly_record(p_channel_status, pinfo,
1677
0
                                          sequenceNumber, p_rlc_lte_info);
1678
0
                        reassembly_destroy(p_channel_status);
1679
0
                    }
1680
0
                }
1681
1682
                /* The start of a new reassembly? */
1683
1
                if (!last_includes_end &&
1684
1
                    ((number_of_segments > 1) || first_includes_start)) {
1685
1686
1
                    uint16_t lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1687
1
                    if (global_rlc_lte_reassembly) {
1688
1
                        reassembly_reset(p_channel_status);
1689
1
                        reassembly_add_segment(p_channel_status, sequenceNumber,
1690
1
                                               pinfo->num,
1691
1
                                               tvb, lastSegmentOffset, lastSegmentLength);
1692
1
                    }
1693
1
                }
1694
1695
1
                if (p_report_in_frame->previousFrameNum != 0) {
1696
                    /* Get report for previous frame */
1697
0
                    sequence_analysis_report *p_previous_report;
1698
0
                    p_previous_report = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1699
0
                                                                                       get_report_hash_key((sequenceNumber+snLimit-1) % snLimit,
1700
0
                                                                                                           p_report_in_frame->previousFrameNum,
1701
0
                                                                                                           p_rlc_lte_info,
1702
0
                                                                                                           false));
1703
                    /* It really shouldn't be NULL... */
1704
0
                    if (p_previous_report != NULL) {
1705
                        /* Point it forward to this one */
1706
0
                        p_previous_report->nextFrameNum = pinfo->num;
1707
0
                    }
1708
0
                }
1709
1710
1
            }
1711
1712
            /* Previous subframe repeated? */
1713
4
            else if (((sequenceNumber+1) % snLimit) == expectedSequenceNumber) {
1714
0
                p_report_in_frame->state = SN_Repeated;
1715
1716
                /* Set report for this frame */
1717
0
                p_report_in_frame->sequenceExpectedCorrect = false;
1718
0
                p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1719
0
                p_report_in_frame->firstSN = sequenceNumber;
1720
0
                p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1721
0
                p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1722
1723
1724
                /* Really should be nothing to update... */
1725
0
                p_channel_status->previousSequenceNumber = sequenceNumber;
1726
0
                p_channel_status->previousFrameNum = pinfo->num;
1727
0
                p_channel_status->previousSegmentIncomplete = !last_includes_end;
1728
0
            }
1729
1730
4
            else {
1731
                /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1732
4
                int delta  = (snLimit + expectedSequenceNumber - sequenceNumber) % snLimit;
1733
1734
                /* Rx window is 512/32768, so check to see if this is a retx */
1735
4
                if (delta < (int)(snLimit>>1)) {
1736
                    /* Probably a retx due to receiving NACK */
1737
3
                    p_report_in_frame->state = SN_Retx;
1738
1739
3
                    p_report_in_frame->firstSN = sequenceNumber;
1740
                    /* Don't update anything in channel state */
1741
3
                }
1742
1743
1
                else {
1744
                    /* Ahead of expected SN. Assume frames have been missed */
1745
1
                    p_report_in_frame->state = SN_Missing;
1746
1747
1
                    p_report_in_frame->firstSN = expectedSequenceNumber;
1748
1
                    p_report_in_frame->lastSN = (snLimit + sequenceNumber-1) % snLimit;
1749
1750
                    /* Update channel state - forget about missed SNs */
1751
1
                    p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1752
1
                    p_channel_status->previousSequenceNumber = sequenceNumber;
1753
1
                    p_channel_status->previousFrameNum = pinfo->num;
1754
1
                    p_channel_status->previousSegmentIncomplete = !last_includes_end;
1755
1
                }
1756
4
            }
1757
5
            break;
1758
1759
0
        default:
1760
            /* Shouldn't get here! */
1761
0
            return SN_Error;
1762
5
    }
1763
1764
    /* Associate with this frame number */
1765
5
    wmem_map_insert(sequence_analysis_report_hash,
1766
5
                        get_report_hash_key(sequenceNumber, pinfo->num, p_rlc_lte_info, true),
1767
5
                        p_report_in_frame);
1768
1769
    /* Add state report for this frame into tree */
1770
5
    addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1771
5
                           first_includes_start, tap_info, pinfo, tree, tvb);
1772
1773
5
    return p_report_in_frame->state;
1774
5
}
1775
1776
1777
/* Add to the tree values associated with sequence analysis for this frame */
1778
static void addChannelRepeatedNACKInfo(channel_repeated_nack_report *p,
1779
                                       rlc_lte_info *p_rlc_lte_info,
1780
                                       packet_info *pinfo, proto_tree *tree,
1781
                                       tvbuff_t *tvb)
1782
0
{
1783
0
    proto_tree *seqnum_tree;
1784
0
    proto_item *seqnum_ti;
1785
0
    proto_item *ti;
1786
0
    int        n;
1787
1788
    /* Create subtree */
1789
0
    seqnum_ti = proto_tree_add_string_format(tree,
1790
0
                                             hf_rlc_lte_sequence_analysis,
1791
0
                                             tvb, 0, 0,
1792
0
                                             "", "Sequence Analysis");
1793
0
    seqnum_tree = proto_item_add_subtree(seqnum_ti,
1794
0
                                         ett_rlc_lte_sequence_analysis);
1795
0
    proto_item_set_generated(seqnum_ti);
1796
1797
    /* OK = false */
1798
0
    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1799
0
                                tvb, 0, 0, false);
1800
0
    proto_item_set_generated(ti);
1801
1802
    /* Add each repeated NACK as item & expert info */
1803
0
    for (n=0; n < p->noOfNACKsRepeated; n++) {
1804
1805
0
        ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
1806
0
                                 tvb, 0, 0, p->repeatedNACKs[n]);
1807
0
        proto_item_set_generated(ti);
1808
1809
0
        expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_repeated_nack,
1810
0
                               "Same SN  (%u) NACKd for %s on UE %u in successive Status PDUs",
1811
0
                               p->repeatedNACKs[n],
1812
0
                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1813
0
                               p_rlc_lte_info->ueid);
1814
0
    }
1815
1816
    /* Link back to previous status report */
1817
0
    ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
1818
0
                             tvb, 0, 0, p->previousFrameNum);
1819
0
    proto_item_set_generated(ti);
1820
1821
    /* Append count to sequence analysis root */
1822
0
    proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
1823
0
                           p->noOfNACKsRepeated);
1824
0
}
1825
1826
1827
/* Update the channel repeated NACK status and set report for this frame */
1828
static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
1829
                                         rlc_lte_info *p_rlc_lte_info,
1830
                                         rlc_3gpp_tap_info *tap_info,
1831
                                         proto_tree *tree,
1832
                                         tvbuff_t *tvb)
1833
7
{
1834
7
    channel_hash_key   channel_key;
1835
7
    channel_hash_key   *p_channel_key;
1836
7
    channel_repeated_nack_status     *p_channel_status;
1837
7
    channel_repeated_nack_report  *p_report_in_frame = NULL;
1838
1839
7
    uint16_t        noOfNACKsRepeated = 0;
1840
7
    uint16_t        repeatedNACKs[MAX_NACKs];
1841
7
    int             n, i, j;
1842
1843
    /* If find state_report_in_frame already, use that and get out */
1844
7
    if (pinfo->fd->visited) {
1845
0
        p_report_in_frame = (channel_repeated_nack_report*)wmem_map_lookup(repeated_nack_report_hash,
1846
0
                                                                               get_report_hash_key(0, pinfo->num,
1847
0
                                                                                                   p_rlc_lte_info, false));
1848
0
        if (p_report_in_frame != NULL) {
1849
0
            addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1850
0
                                       pinfo, tree, tvb);
1851
0
            return;
1852
0
        }
1853
0
        else {
1854
            /* Give up - we must have tried already... */
1855
0
            return;
1856
0
        }
1857
0
    }
1858
1859
1860
    /**************************************************/
1861
    /* Create or find an entry for this channel state */
1862
7
    channel_key.ueId = p_rlc_lte_info->ueid;
1863
7
    channel_key.channelType = p_rlc_lte_info->channelType;
1864
7
    channel_key.channelId = p_rlc_lte_info->channelId;
1865
7
    channel_key.direction = p_rlc_lte_info->direction;
1866
7
    memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1867
1868
    /* Do the table lookup */
1869
7
    p_channel_status = (channel_repeated_nack_status*)wmem_map_lookup(repeated_nack_channel_hash, &channel_key);
1870
1871
    /* Create table entry if necessary */
1872
7
    if (p_channel_status == NULL) {
1873
1874
        /* Allocate a new key and value */
1875
1
        p_channel_key = wmem_new(wmem_file_scope(), channel_hash_key);
1876
1
        p_channel_status = wmem_new0(wmem_file_scope(), channel_repeated_nack_status);
1877
1878
        /* Copy key contents */
1879
1
        memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1880
1881
        /* Add entry to table */
1882
1
        wmem_map_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1883
1
    }
1884
1885
    /* Compare NACKs in channel status with NACKs in tap_info.
1886
       Note any that are repeated */
1887
7
    for (i=0; i < p_channel_status->noOfNACKs; i++) {
1888
0
        for (j=0; j < MIN(tap_info->noOfNACKs, MAX_NACKs); j++) {
1889
0
            if (tap_info->NACKs[j] == p_channel_status->NACKs[i]) {
1890
                /* Don't add the same repeated NACK twice! */
1891
0
                if ((noOfNACKsRepeated == 0) ||
1892
0
                    (repeatedNACKs[noOfNACKsRepeated-1] != p_channel_status->NACKs[i])) {
1893
1894
0
                    repeatedNACKs[noOfNACKsRepeated++] = p_channel_status->NACKs[i];
1895
0
                }
1896
0
            }
1897
0
        }
1898
0
    }
1899
1900
    /* Copy NACKs from tap_info into channel status for next time! */
1901
7
    p_channel_status->noOfNACKs = 0;
1902
7
    for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1903
0
        p_channel_status->NACKs[p_channel_status->noOfNACKs++] = tap_info->NACKs[n];
1904
0
    }
1905
1906
7
    if (noOfNACKsRepeated >= 1) {
1907
        /* Create space for frame state_report */
1908
0
        p_report_in_frame = wmem_new(wmem_file_scope(), channel_repeated_nack_report);
1909
1910
        /* Copy in found duplicates */
1911
0
        for (n=0; n < MIN(tap_info->noOfNACKs, MAX_NACKs); n++) {
1912
0
            p_report_in_frame->repeatedNACKs[n] = repeatedNACKs[n];
1913
0
        }
1914
0
        p_report_in_frame->noOfNACKsRepeated = noOfNACKsRepeated;
1915
1916
0
        p_report_in_frame->previousFrameNum = p_channel_status->frameNum;
1917
1918
        /* Associate with this frame number */
1919
0
        wmem_map_insert(repeated_nack_report_hash,
1920
0
                            get_report_hash_key(0, pinfo->num,
1921
0
                                                p_rlc_lte_info, true),
1922
0
                            p_report_in_frame);
1923
1924
        /* Add state report for this frame into tree */
1925
0
        addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
1926
0
                                   pinfo, tree, tvb);
1927
0
    }
1928
1929
    /* Save frame number for next comparison */
1930
7
    p_channel_status->frameNum = pinfo->num;
1931
7
}
1932
1933
/* Check that the ACK is consistent with data the expected sequence number
1934
   in the other direction */
1935
static void checkChannelACKWindow(uint16_t ack_sn,
1936
                                  packet_info *pinfo,
1937
                                  rlc_lte_info *p_rlc_lte_info,
1938
                                  rlc_3gpp_tap_info *tap_info,
1939
                                  proto_tree *tree,
1940
                                  tvbuff_t *tvb)
1941
7
{
1942
7
    channel_hash_key   channel_key;
1943
7
    channel_sequence_analysis_status  *p_channel_status;
1944
7
    sequence_analysis_report  *p_report_in_frame = NULL;
1945
7
    uint32_t snLimit;
1946
1947
    /* If find stat_report_in_frame already, use that and get out */
1948
7
    if (pinfo->fd->visited) {
1949
0
        p_report_in_frame = (sequence_analysis_report*)wmem_map_lookup(sequence_analysis_report_hash,
1950
0
                                                                           get_report_hash_key(0, pinfo->num,
1951
0
                                                                                               p_rlc_lte_info,
1952
0
                                                                                               false));
1953
0
        if (p_report_in_frame != NULL) {
1954
            /* Add any info to tree */
1955
0
            addChannelSequenceInfo(p_report_in_frame, true, p_rlc_lte_info,
1956
0
                                   0, false,
1957
0
                                   tap_info, pinfo, tree, tvb);
1958
0
            return;
1959
0
        }
1960
0
        else {
1961
            /* Give up - we must have tried already... */
1962
0
            return;
1963
0
        }
1964
0
    }
1965
1966
    /*******************************************************************/
1967
    /* Find an entry for this channel state (in the opposite direction */
1968
7
    channel_key.ueId = p_rlc_lte_info->ueid;
1969
7
    channel_key.channelType = p_rlc_lte_info->channelType;
1970
7
    channel_key.channelId = p_rlc_lte_info->channelId;
1971
7
    channel_key.direction =
1972
7
        (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1973
1974
    /* Do the table lookup */
1975
7
    p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1976
1977
    /* Create table entry if necessary */
1978
7
    if (p_channel_status == NULL) {
1979
1
        return;
1980
1
    }
1981
1982
    /* Is it in the rx window? This test will catch if it's ahead, but we don't
1983
       really know what the back of the tx window is... */
1984
6
    snLimit = (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) ? 65536 : 1024;
1985
6
    if (((snLimit + (uint32_t)p_channel_status->previousSequenceNumber+1 - ack_sn) % snLimit) > (snLimit>>1)) {
1986
1987
        /* Set result */
1988
5
        p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1989
5
        p_report_in_frame->state = ACK_Out_of_Window;
1990
5
        p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1991
5
        p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1992
5
        p_report_in_frame->firstSN = ack_sn;
1993
1994
        /* Associate with this frame number */
1995
5
        wmem_map_insert(sequence_analysis_report_hash,
1996
5
                            get_report_hash_key(0, pinfo->num,
1997
5
                                                p_rlc_lte_info, true),
1998
5
                            p_report_in_frame);
1999
2000
        /* Add state report for this frame into tree */
2001
5
        addChannelSequenceInfo(p_report_in_frame, true, p_rlc_lte_info, 0,
2002
5
                               false, tap_info, pinfo, tree, tvb);
2003
5
    }
2004
6
}
2005
2006
2007
2008
2009
/***************************************************/
2010
/* Transparent mode PDU. Call RRC if configured to */
2011
static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
2012
                               proto_tree *tree,
2013
                               unsigned offset,
2014
                               rlc_lte_info *p_rlc_lte_info,
2015
                               proto_item *top_ti)
2016
0
{
2017
0
    proto_item *raw_tm_ti;
2018
0
    proto_item *tm_ti;
2019
2020
    /* Create hidden TM root */
2021
0
    tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
2022
0
                                         tvb, offset, 0, "", "TM");
2023
0
    proto_item_set_hidden(tm_ti);
2024
2025
    /* Remaining bytes are all data */
2026
0
    raw_tm_ti = proto_tree_add_item(tree, hf_rlc_lte_tm_data, tvb, offset, -1, ENC_NA);
2027
0
    if (!global_rlc_lte_call_rrc_for_ccch) {
2028
0
        write_pdu_label_and_info(top_ti, NULL, pinfo,
2029
0
                                 "                     [%u-bytes]", tvb_reported_length_remaining(tvb, offset));
2030
0
    }
2031
2032
0
    if (global_rlc_lte_call_rrc_for_ccch) {
2033
0
        tvbuff_t *rrc_tvb = tvb_new_subset_remaining(tvb, offset);
2034
0
        volatile dissector_handle_t protocol_handle;
2035
2036
0
        switch (p_rlc_lte_info->channelType) {
2037
0
            case CHANNEL_TYPE_CCCH:
2038
0
                if (p_rlc_lte_info->direction == DIRECTION_UPLINK) {
2039
0
                    protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2040
0
                                        lte_rrc_ul_ccch_nb : lte_rrc_ul_ccch;
2041
0
                }
2042
0
                else {
2043
0
                    protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2044
0
                                        lte_rrc_dl_ccch_nb : lte_rrc_dl_ccch;
2045
0
                }
2046
0
                break;
2047
2048
0
            case CHANNEL_TYPE_BCCH_BCH:
2049
0
                protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2050
0
                                    lte_rrc_bcch_bch_nb : lte_rrc_bcch_bch;
2051
0
                break;
2052
0
            case CHANNEL_TYPE_BCCH_DL_SCH:
2053
0
                protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2054
0
                                    lte_rrc_bcch_dl_sch_nb : lte_rrc_bcch_dl_sch;
2055
0
                break;
2056
0
            case CHANNEL_TYPE_PCCH:
2057
0
                protocol_handle = (p_rlc_lte_info->nbMode == rlc_nb_mode) ?
2058
0
                                    lte_rrc_pcch_nb : lte_rrc_pcch;
2059
0
                break;
2060
2061
0
            case CHANNEL_TYPE_SRB:
2062
0
            case CHANNEL_TYPE_DRB:
2063
0
            case CHANNEL_TYPE_MCCH:
2064
0
            case CHANNEL_TYPE_MTCH:
2065
2066
0
            default:
2067
                /* Shouldn't happen, just return... */
2068
0
                return;
2069
0
        }
2070
2071
        /* Hide raw view of bytes */
2072
0
        proto_item_set_hidden(raw_tm_ti);
2073
2074
        /* Call it (catch exceptions) */
2075
0
        TRY {
2076
0
            call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
2077
0
        }
2078
0
        CATCH_ALL {
2079
0
        }
2080
0
        ENDTRY
2081
0
    }
2082
0
}
2083
2084
2085
2086
/***************************************************/
2087
/* Unacknowledged mode PDU                         */
2088
static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
2089
                               proto_tree *tree,
2090
                               unsigned offset,
2091
                               rlc_lte_info *p_rlc_lte_info,
2092
                               proto_item *top_ti,
2093
                               rlc_3gpp_tap_info *tap_info)
2094
0
{
2095
0
    uint64_t framing_info;
2096
0
    bool first_includes_start;
2097
0
    bool last_includes_end;
2098
0
    uint64_t fixed_extension;
2099
0
    uint64_t sn;
2100
0
    unsigned start_offset = offset;
2101
0
    proto_item *um_ti;
2102
0
    proto_tree *um_header_tree;
2103
0
    proto_item *um_header_ti;
2104
0
    bool is_truncated = false;
2105
0
    proto_item *truncated_ti;
2106
0
    rlc_channel_reassembly_info *reassembly_info = NULL;
2107
0
    sequence_analysis_state seq_anal_state = SN_OK;
2108
2109
    /* Hidden UM root */
2110
0
    um_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um,
2111
0
                                         tvb, offset, 0, "", "UM");
2112
0
    proto_item_set_hidden(um_ti);
2113
2114
    /* Add UM header subtree */
2115
0
    um_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_um_header,
2116
0
                                                tvb, offset, 0,
2117
0
                                                "", "UM header");
2118
0
    um_header_tree = proto_item_add_subtree(um_header_ti,
2119
0
                                            ett_rlc_lte_um_header);
2120
2121
2122
    /*******************************/
2123
    /* Fixed UM header             */
2124
0
    if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_5_BITS) {
2125
        /* Framing info (2 bits) */
2126
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2127
0
                                    tvb, offset*8, 2,
2128
0
                                    &framing_info, ENC_BIG_ENDIAN);
2129
2130
        /* Extension (1 bit) */
2131
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2132
0
                                    (offset*8) + 2, 1,
2133
0
                                    &fixed_extension, ENC_BIG_ENDIAN);
2134
2135
        /* Sequence Number (5 bit) */
2136
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2137
0
                                    (offset*8) + 3, 5,
2138
0
                                    &sn, ENC_BIG_ENDIAN);
2139
0
        offset++;
2140
0
    }
2141
0
    else if (p_rlc_lte_info->sequenceNumberLength == UM_SN_LENGTH_10_BITS) {
2142
0
        uint32_t reserved;
2143
0
        proto_item *ti;
2144
2145
        /* Check 3 Reserved bits */
2146
0
        ti = proto_tree_add_item_ret_uint(um_header_tree, hf_rlc_lte_um_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2147
0
        if (reserved != 0) {
2148
0
            expert_add_info_format(pinfo, ti, &ei_rlc_lte_reserved_bits_not_zero,
2149
0
                      "RLC UM Fixed header Reserved bits not zero (found 0x%x)", reserved);
2150
0
        }
2151
2152
        /* Framing info (2 bits) */
2153
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fi,
2154
0
                                    tvb, (offset*8)+3, 2,
2155
0
                                    &framing_info, ENC_BIG_ENDIAN);
2156
2157
        /* Extension (1 bit) */
2158
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_fixed_e, tvb,
2159
0
                                    (offset*8) + 5, 1,
2160
0
                                    &fixed_extension, ENC_BIG_ENDIAN);
2161
2162
        /* Sequence Number (10 bits) */
2163
0
        proto_tree_add_bits_ret_val(um_header_tree, hf_rlc_lte_um_sn, tvb,
2164
0
                                    (offset*8) + 6, 10,
2165
0
                                    &sn, ENC_BIG_ENDIAN);
2166
0
        offset += 2;
2167
0
    }
2168
0
    else {
2169
        /* Invalid length of sequence number */
2170
0
        proto_tree_add_expert_format(um_header_tree, pinfo, &ei_rlc_lte_um_sn, tvb, 0, 0,
2171
0
                               "Invalid sequence number length (%u bits)",
2172
0
                               p_rlc_lte_info->sequenceNumberLength);
2173
0
        return;
2174
0
    }
2175
2176
0
    tap_info->sequenceNumberGiven = true;
2177
0
    tap_info->sequenceNumber = (uint16_t)sn;
2178
2179
    /* Show SN in info column */
2180
0
    if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_MCCH) || (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2181
0
        write_pdu_label_and_info(top_ti, um_header_ti, pinfo, "           sn=%-4u", (uint16_t)sn);
2182
0
    }
2183
0
    else {
2184
0
        write_pdu_label_and_info(top_ti, um_header_ti, pinfo, "            sn=%-4u", (uint16_t)sn);
2185
0
    }
2186
2187
0
    proto_item_set_len(um_header_ti, offset-start_offset);
2188
2189
2190
    /*************************************/
2191
    /* UM header extension               */
2192
0
    if (fixed_extension) {
2193
0
        offset = dissect_rlc_lte_extension_header(tvb, pinfo, um_header_tree, offset, p_rlc_lte_info);
2194
0
    }
2195
2196
    /* Extract these 2 flags from framing_info */
2197
0
    first_includes_start = ((uint8_t)framing_info & 0x02) == 0;
2198
0
    last_includes_end =    ((uint8_t)framing_info & 0x01) == 0;
2199
2200
0
    if (global_rlc_lte_headers_expected) {
2201
        /* There might not be any data, if only headers (plus control data) were logged */
2202
0
        is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2203
0
        truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2204
0
                                           is_truncated);
2205
0
        if (is_truncated) {
2206
0
            int n;
2207
0
            proto_item_set_generated(truncated_ti);
2208
0
            expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2209
2210
            /* Show in the info column how long the data would be */
2211
0
            for (n=0; n < s_number_of_extensions; n++) {
2212
0
                show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2213
0
                                 (n==0) ? first_includes_start : true,
2214
0
                                 true);
2215
0
                offset += s_lengths[n];
2216
0
            }
2217
            /* Last one */
2218
0
            show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2219
0
                             (s_number_of_extensions == 0) ? first_includes_start : true,
2220
0
                             last_includes_end);
2221
0
        }
2222
0
        else {
2223
0
            proto_item_set_hidden(truncated_ti);
2224
0
        }
2225
0
    }
2226
2227
    /* Show number of extensions in header root */
2228
0
    if (s_number_of_extensions > 0) {
2229
0
        proto_item_append_text(um_header_ti, " (%u extensions)", s_number_of_extensions);
2230
0
    }
2231
2232
    /* Call sequence analysis function now */
2233
0
    if (((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2234
0
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2235
0
        ((global_rlc_lte_um_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2236
0
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2237
2238
0
        uint16_t lastSegmentOffset = offset;
2239
0
        if (s_number_of_extensions >= 1) {
2240
0
            int n;
2241
0
            lastSegmentOffset = offset;
2242
0
            for (n=0; n < s_number_of_extensions; n++) {
2243
0
                lastSegmentOffset += s_lengths[n];
2244
0
            }
2245
0
        }
2246
2247
0
        seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
2248
0
                                                  false,
2249
0
                                                  s_number_of_extensions+1,
2250
0
                                                  offset,
2251
0
                                                  s_number_of_extensions ?
2252
0
                                                      s_lengths[0] :
2253
0
                                                      p_rlc_lte_info->pduLength - offset,
2254
0
                                                  lastSegmentOffset,
2255
0
                                                  (uint16_t)sn, first_includes_start, last_includes_end,
2256
0
                                                  false, /* UM doesn't re-segment */
2257
0
                                                  tap_info, um_header_tree);
2258
0
    }
2259
2260
0
    if (is_truncated) {
2261
0
        return;
2262
0
    }
2263
2264
    /*************************************/
2265
    /* Data                              */
2266
2267
0
    reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2268
0
                                                                         get_report_hash_key((uint16_t)sn, pinfo->num,
2269
0
                                                                                             p_rlc_lte_info, false));
2270
2271
0
    if (s_number_of_extensions > 0) {
2272
        /* Show each data segment separately */
2273
0
        int n;
2274
0
        for (n=0; n < s_number_of_extensions; n++) {
2275
0
            show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2276
0
                             (n==0) ? first_includes_start : true,
2277
0
                             (n==0) ? reassembly_info : NULL,
2278
0
                             seq_anal_state);
2279
0
            show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2280
0
                             (n==0) ? first_includes_start : true,
2281
0
                             true);
2282
            /* Make sure we don't lose the summary of this SDU */
2283
0
            col_append_str(pinfo->cinfo, COL_INFO, "  | ");
2284
0
            col_set_fence(pinfo->cinfo, COL_INFO);
2285
2286
0
            tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2287
0
            offset += s_lengths[n];
2288
0
        }
2289
0
    }
2290
2291
    /* Final data element */
2292
0
    show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2293
0
                     ((s_number_of_extensions == 0) ? first_includes_start : true) && last_includes_end,
2294
0
                     (s_number_of_extensions == 0) ? reassembly_info : NULL,
2295
0
                     seq_anal_state);
2296
0
    show_PDU_in_info(pinfo, top_ti, (uint16_t)tvb_reported_length_remaining(tvb, offset),
2297
0
                     (s_number_of_extensions == 0) ? first_includes_start : true,
2298
0
                     last_includes_end);
2299
0
}
2300
2301
2302
2303
/* Dissect an AM STATUS PDU */
2304
static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
2305
                                          packet_info *pinfo,
2306
                                          proto_tree *tree,
2307
                                          proto_item *status_ti,
2308
                                          unsigned offset,
2309
                                          proto_item *top_ti,
2310
                                          rlc_lte_info *p_rlc_lte_info,
2311
                                          rlc_3gpp_tap_info *tap_info)
2312
11
{
2313
11
    uint32_t   cpt;
2314
11
    uint8_t    sn_size, so_size;
2315
11
    uint32_t   sn_limit;
2316
11
    uint64_t   ack_sn, nack_sn;
2317
11
    uint16_t   nack_count = 0, so_end_of_pdu;
2318
11
    uint64_t   e1 = 0, e2 = 0;
2319
11
    uint64_t   so_start, so_end;
2320
11
    int        bit_offset = offset * 8;
2321
11
    proto_item *ti;
2322
2323
    /****************************************************************/
2324
    /* Part of RLC control PDU header                               */
2325
2326
    /* Control PDU Type (CPT) */
2327
11
    ti = proto_tree_add_item_ret_uint(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN, &cpt);
2328
11
    if (cpt != 0) {
2329
        /* Protest and stop - only know about STATUS PDUs */
2330
4
        expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_cpt,
2331
4
                               "RLC Control frame type %u not handled", cpt);
2332
4
        return;
2333
4
    }
2334
2335
7
    if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2336
0
        sn_size = 16;
2337
0
        sn_limit = 65536;
2338
0
        so_size = 16;
2339
0
        so_end_of_pdu = 0xffff;
2340
7
    } else {
2341
7
        sn_size = 10;
2342
7
        sn_limit = 1024;
2343
7
        so_size = 15;
2344
7
        so_end_of_pdu = 0x7fff;
2345
7
    }
2346
2347
    /* The Status PDU itself starts 4 bits into the byte */
2348
7
    bit_offset += 4;
2349
2350
    /* ACK SN */
2351
7
    proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2352
7
                                bit_offset, sn_size, &ack_sn, ENC_BIG_ENDIAN);
2353
7
    bit_offset += sn_size;
2354
7
    write_pdu_label_and_info(top_ti, status_ti, pinfo, "  ACK_SN=%-4u", (uint16_t)ack_sn);
2355
2356
7
    tap_info->ACKNo = (uint16_t)ack_sn;
2357
2358
    /* E1 */
2359
7
    proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2360
7
                                bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2361
2362
    /* Skip another bit to byte-align the next bit... */
2363
7
    bit_offset++;
2364
2365
    /* Optional, extra fields */
2366
7
    do {
2367
7
        if (e1) {
2368
0
            proto_item *nack_ti;
2369
2370
            /****************************/
2371
            /* Read NACK_SN, E1, E2     */
2372
2373
            /* NACK_SN */
2374
0
            nack_ti = proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_nack_sn, tvb,
2375
0
                                                  bit_offset, sn_size, &nack_sn, ENC_BIG_ENDIAN);
2376
0
            bit_offset += sn_size;
2377
0
            write_pdu_label_and_info(top_ti, NULL, pinfo, "  NACK_SN=%-4u", (uint16_t)nack_sn);
2378
2379
            /* We shouldn't NACK the ACK_SN! */
2380
0
            if (nack_sn == ack_sn) {
2381
0
                expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ack_same,
2382
0
                                       "Status PDU shouldn't ACK and NACK the same sequence number (%" PRIu64 ")",
2383
0
                                       ack_sn);
2384
0
            }
2385
2386
            /* NACK should always be 'behind' the ACK */
2387
0
            if ((sn_limit + ack_sn - nack_sn) % sn_limit > (sn_limit>>1)) {
2388
0
                expert_add_info(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_ahead_ack);
2389
0
            }
2390
2391
            /* Copy into struct, but don't exceed buffer */
2392
0
            if (nack_count < MAX_NACKs) {
2393
0
                tap_info->NACKs[nack_count++] = (uint16_t)nack_sn;
2394
0
            }
2395
0
            else {
2396
                /* Let it get bigger than the array for accurate stats... */
2397
0
                nack_count++;
2398
0
            }
2399
2400
            /* E1 */
2401
0
            proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2402
0
                                        bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2403
0
            bit_offset++;
2404
2405
            /* E2 */
2406
0
            proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e2, tvb,
2407
0
                                        bit_offset, 1, &e2, ENC_BIG_ENDIAN);
2408
2409
            /* Report as expert info */
2410
0
            if (e2) {
2411
0
                expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn_partial,
2412
0
                                       "Status PDU reports NACK (partial) on %s for UE %u",
2413
0
                                       val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2414
0
                                       p_rlc_lte_info->ueid);
2415
0
            }
2416
0
            else {
2417
0
                expert_add_info_format(pinfo, nack_ti, &ei_rlc_lte_am_nack_sn,
2418
0
                                       "Status PDU reports NACK on %s for UE %u",
2419
0
                                       val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
2420
0
                                       p_rlc_lte_info->ueid);
2421
0
            }
2422
2423
0
            bit_offset++;
2424
0
        }
2425
2426
7
        if (e2) {
2427
            /* Read SOstart, SOend */
2428
0
            proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_start, tvb,
2429
0
                                        bit_offset, so_size, &so_start, ENC_BIG_ENDIAN);
2430
0
            bit_offset += so_size;
2431
2432
0
            proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_so_end, tvb,
2433
0
                                        bit_offset, so_size, &so_end, ENC_BIG_ENDIAN);
2434
0
            bit_offset += so_size;
2435
2436
2437
0
            if ((uint16_t)so_end == so_end_of_pdu) {
2438
0
                write_pdu_label_and_info(top_ti, NULL, pinfo,
2439
0
                                         " (SOstart=%u SOend=<END-OF_PDU>)",
2440
0
                                         (uint16_t)so_start);
2441
0
            }
2442
0
            else {
2443
0
                write_pdu_label_and_info(top_ti, NULL, pinfo,
2444
0
                                         " (SOstart=%u SOend=%u)",
2445
0
                                         (uint16_t)so_start, (uint16_t)so_end);
2446
0
            }
2447
2448
            /* Reset this flag here */
2449
0
            e2 = 0;
2450
0
        }
2451
7
    } while (e1);
2452
2453
7
    if (nack_count > 0) {
2454
0
        proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
2455
0
        proto_item_set_generated(count_ti);
2456
0
        proto_item_append_text(status_ti, "  (%u NACKs)", nack_count);
2457
0
        tap_info->noOfNACKs = nack_count;
2458
0
    }
2459
2460
    /* Check that we've reached the end of the PDU. If not, show malformed */
2461
7
    offset = (bit_offset+7) / 8;
2462
7
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
2463
7
        expert_add_info_format(pinfo, status_ti, &ei_rlc_lte_bytes_after_status_pdu_complete,
2464
7
                               "%cL %u bytes remaining after Status PDU complete",
2465
7
                               (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2466
7
                               tvb_reported_length_remaining(tvb, offset));
2467
7
    }
2468
2469
    /* Set selected length of control tree */
2470
7
    proto_item_set_len(status_ti, offset);
2471
2472
    /* Repeated NACK analysis & check ACK-SN is in range */
2473
7
    if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2474
7
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2475
0
        ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2476
7
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2477
2478
7
        if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2479
7
            checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2480
7
            checkChannelACKWindow((uint16_t)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2481
7
        }
2482
7
     }
2483
7
}
2484
2485
2486
/***************************************************/
2487
/* Acknowledged mode PDU                           */
2488
static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
2489
                               proto_tree *tree,
2490
                               unsigned offset,
2491
                               rlc_lte_info *p_rlc_lte_info,
2492
                               proto_item *top_ti,
2493
                               rlc_3gpp_tap_info *tap_info)
2494
18
{
2495
18
    bool is_data;
2496
18
    uint32_t is_resegmented;
2497
18
    uint32_t polling;
2498
18
    uint32_t fixed_extension;
2499
18
    uint32_t framing_info;
2500
18
    bool first_includes_start;
2501
18
    bool last_includes_end;
2502
18
    proto_item *am_ti;
2503
18
    proto_tree *am_header_tree;
2504
18
    proto_item *am_header_ti;
2505
18
    int    start_offset = offset;
2506
18
    uint32_t   sn;
2507
18
    bool is_truncated = false;
2508
18
    proto_item *truncated_ti;
2509
18
    rlc_channel_reassembly_info *reassembly_info = NULL;
2510
18
    sequence_analysis_state seq_anal_state = SN_OK;
2511
18
    uint32_t id;
2512
18
    wmem_tree_key_t key[3];
2513
18
    rlc_ue_parameters *params;
2514
2515
    /* Hidden AM root */
2516
18
    am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2517
18
                                         tvb, offset, 0, "", "AM");
2518
18
    proto_item_set_hidden(am_ti);
2519
2520
    /* Add AM header subtree */
2521
18
    am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2522
18
                                                tvb, offset, 0,
2523
18
                                                "", "AM Header ");
2524
18
    am_header_tree = proto_item_add_subtree(am_header_ti,
2525
18
                                            ett_rlc_lte_am_header);
2526
2527
    /* First bit is Data/Control flag           */
2528
18
    proto_tree_add_item_ret_boolean(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN, &is_data);
2529
18
    tap_info->isControlPDU = !is_data;
2530
2531
18
    if (!is_data) {
2532
        /**********************/
2533
        /* Status PDU         */
2534
11
        write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
2535
2536
        /* Control PDUs are a completely separate format  */
2537
11
        dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2538
11
                                      offset, top_ti,
2539
11
                                      p_rlc_lte_info, tap_info);
2540
11
        return;
2541
11
    }
2542
2543
    /******************************/
2544
    /* Data PDU fixed header      */
2545
2546
    /* Re-segmentation Flag (RF) field */
2547
7
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1,
2548
7
                                 ENC_BIG_ENDIAN, &is_resegmented);
2549
7
    tap_info->isResegmented = is_resegmented;
2550
2551
7
    write_pdu_label_and_info_literal(top_ti, NULL, pinfo,
2552
7
                                     (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2553
2554
    /* Polling bit */
2555
7
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1,
2556
7
                                 ENC_BIG_ENDIAN, &polling);
2557
2558
7
    write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : "     ");
2559
7
    if (polling) {
2560
3
        proto_item_append_text(am_header_ti, " (P) ");
2561
3
    }
2562
2563
    /* Framing Info */
2564
7
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1,
2565
7
                                 ENC_BIG_ENDIAN, &framing_info);
2566
2567
    /* Extension bit */
2568
7
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1,
2569
7
                                 ENC_BIG_ENDIAN, &fixed_extension);
2570
2571
    /* Sequence Number */
2572
7
    if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2573
0
        uint32_t reserved;
2574
2575
0
        if (is_resegmented) {
2576
            /* Last Segment Field (LSF) */
2577
0
            proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf16, tvb, offset, 1, ENC_BIG_ENDIAN);
2578
            /* Reserved (R1) */
2579
0
            am_ti = proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2580
0
        } else {
2581
            /* Reserved (R1) */
2582
0
            am_ti = proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2583
0
        }
2584
0
        if (reserved != 0) {
2585
0
            expert_add_info_format(pinfo, am_ti, &ei_rlc_lte_reserved_bits_not_zero,
2586
0
                    "RLC AM Fixed header Reserved bits not zero (found 0x02%x)", reserved);
2587
0
        }
2588
0
        offset += 1;
2589
0
        proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_sn16, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
2590
0
        offset += 2;
2591
7
    } else {
2592
7
        proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
2593
7
        offset += 2;
2594
7
    }
2595
7
    tap_info->sequenceNumberGiven = true;
2596
7
    tap_info->sequenceNumber = sn;
2597
2598
7
    write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2599
2600
    /***************************************/
2601
    /* Dissect extra segment header fields */
2602
7
    if (is_resegmented) {
2603
5
        uint32_t segmentOffset;
2604
2605
5
        if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
2606
            /* SO */
2607
0
            proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_segment_so16, tvb, offset, 2, ENC_BIG_ENDIAN, &segmentOffset);
2608
5
        } else {
2609
            /* Last Segment Field (LSF) */
2610
5
            proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2611
2612
            /* SO */
2613
5
            proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN, &segmentOffset);
2614
5
        }
2615
5
        write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2616
5
        offset += 2;
2617
5
    }
2618
2619
    /*************************************/
2620
    /* AM header extension               */
2621
7
    if (fixed_extension) {
2622
3
        if (!PINFO_FD_VISITED(pinfo)) {
2623
3
            id = (p_rlc_lte_info->channelId << 16) | p_rlc_lte_info->ueid;
2624
3
            key[0].length = 1;
2625
3
            key[0].key = &id;
2626
3
            key[1].length = 1;
2627
3
            key[1].key = &pinfo->num;
2628
3
            key[2].length = 0;
2629
3
            key[2].key = NULL;
2630
3
            params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
2631
3
            if (params && (params->id == id)) {
2632
0
                p_rlc_lte_info->extendedLiField = (p_rlc_lte_info->direction == DIRECTION_UPLINK) ?
2633
0
                                                   (params->ext_li_field & UL_EXT_LI): (params->ext_li_field & DL_EXT_LI);
2634
0
            }
2635
3
        }
2636
3
        offset = dissect_rlc_lte_extension_header(tvb, pinfo, am_header_tree, offset, p_rlc_lte_info);
2637
3
    }
2638
2639
    /* Header is now complete */
2640
7
    proto_item_set_len(am_header_ti, offset-start_offset);
2641
2642
    /* Show number of extensions in header root */
2643
7
    if (s_number_of_extensions > 0) {
2644
3
        proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2645
3
    }
2646
2647
    /* Extract these 2 flags from framing_info */
2648
7
    first_includes_start = (framing_info & 0x02) == 0;
2649
7
    last_includes_end =    (framing_info & 0x01) == 0;
2650
2651
    /* There might not be any data, if only headers (plus control data) were logged */
2652
7
    if (global_rlc_lte_headers_expected) {
2653
0
        is_truncated = (tvb_captured_length_remaining(tvb, offset) == 0);
2654
0
        truncated_ti = proto_tree_add_uint(tree, hf_rlc_lte_header_only, tvb, 0, 0,
2655
0
                                           is_truncated);
2656
0
        if (is_truncated) {
2657
0
            int n;
2658
0
            proto_item_set_generated(truncated_ti);
2659
0
            expert_add_info(pinfo, truncated_ti, &ei_rlc_lte_header_only);
2660
            /* Show in the info column how long the data would be */
2661
0
            for (n=0; n < s_number_of_extensions; n++) {
2662
0
                show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2663
0
                                 (n==0) ? first_includes_start : true,
2664
0
                                 true);
2665
0
                offset += s_lengths[n];
2666
0
            }
2667
            /* Last one */
2668
0
            show_PDU_in_info(pinfo, top_ti, p_rlc_lte_info->pduLength - offset,
2669
0
                             (s_number_of_extensions == 0) ? first_includes_start : true,
2670
0
                             last_includes_end);
2671
0
        }
2672
0
        else {
2673
0
            proto_item_set_hidden(truncated_ti);
2674
0
        }
2675
0
    }
2676
2677
    /* Call sequence analysis function now */
2678
7
    if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2679
5
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL)) ||
2680
0
        ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
2681
5
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2682
2683
5
        uint16_t firstSegmentLength;
2684
5
        uint16_t lastSegmentOffset = offset;
2685
5
        if (s_number_of_extensions >= 1) {
2686
3
            int n;
2687
6
            for (n=0; n < s_number_of_extensions; n++) {
2688
3
                lastSegmentOffset += s_lengths[n];
2689
3
            }
2690
2691
3
            firstSegmentLength = s_lengths[0];
2692
3
        }
2693
2
        else {
2694
2
            firstSegmentLength = tvb_reported_length_remaining(tvb, offset);
2695
2
        }
2696
2697
5
        seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, false,
2698
5
                                                  s_number_of_extensions+1,
2699
5
                                                  offset, firstSegmentLength,
2700
5
                                                  lastSegmentOffset,
2701
5
                                                  (uint16_t)sn,
2702
5
                                                  first_includes_start, last_includes_end,
2703
5
                                                  is_resegmented, tap_info, tree);
2704
5
    }
2705
2706
7
    if (is_truncated) {
2707
0
        return;
2708
0
    }
2709
2710
    /*************************************/
2711
    /* Data                              */
2712
2713
7
    if (!first_includes_start) {
2714
5
        reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2715
5
                                                                             get_report_hash_key((uint16_t)sn,
2716
5
                                                                                                 pinfo->num,
2717
5
                                                                                                 p_rlc_lte_info,
2718
5
                                                                                                 false));
2719
5
    }
2720
2721
7
    if (s_number_of_extensions > 0) {
2722
        /* Show each data segment separately */
2723
3
        int n;
2724
6
        for (n=0; n < s_number_of_extensions; n++) {
2725
3
            show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2726
3
                             (n==0) ? first_includes_start : true,
2727
3
                             (n==0) ? reassembly_info : NULL,
2728
3
                             seq_anal_state);
2729
3
            show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2730
3
                             (n==0) ? first_includes_start : true,
2731
3
                             true);
2732
            /* Make sure we don't lose the summary of this SDU */
2733
3
            col_append_str(pinfo->cinfo, COL_INFO, "  | ");
2734
3
            col_set_fence(pinfo->cinfo, COL_INFO);
2735
2736
3
            tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2737
3
            offset += s_lengths[n];
2738
3
        }
2739
3
    }
2740
2741
    /* Final data element */
2742
7
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
2743
5
        show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2744
5
                         ((s_number_of_extensions == 0) ? first_includes_start : true) && last_includes_end,
2745
5
                         (s_number_of_extensions == 0) ? reassembly_info : NULL,
2746
5
                         seq_anal_state);
2747
5
        show_PDU_in_info(pinfo, top_ti, (uint16_t)tvb_reported_length_remaining(tvb, offset),
2748
5
                         (s_number_of_extensions == 0) ? first_includes_start : true,
2749
5
                         last_includes_end);
2750
5
    }
2751
2
    else {
2752
        /* Report that expected data was missing (unless we know it might happen) */
2753
2
        if (!global_rlc_lte_headers_expected) {
2754
0
            if (s_number_of_extensions > 0) {
2755
0
                expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data_beyond_extensions);
2756
0
            }
2757
0
            else {
2758
0
                expert_add_info(pinfo, am_header_ti, &ei_rlc_lte_am_data_no_data);
2759
0
            }
2760
0
        }
2761
2
    }
2762
7
}
2763
2764
static void report_heur_error(proto_tree *tree, packet_info *pinfo, expert_field *eiindex,
2765
                              tvbuff_t *tvb, int start, int length)
2766
0
{
2767
0
    proto_item *ti;
2768
0
    proto_tree *subtree;
2769
2770
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2771
0
    col_clear(pinfo->cinfo, COL_INFO);
2772
0
    ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, 0, -1, ENC_NA);
2773
0
    subtree = proto_item_add_subtree(ti, ett_rlc_lte);
2774
0
    proto_tree_add_expert(subtree, pinfo, eiindex, tvb, start, length);
2775
0
}
2776
2777
/* Heuristic dissector looks for supported framing protocol (see wiki page)  */
2778
static bool dissect_rlc_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
2779
                                     proto_tree *tree, void *data _U_)
2780
0
{
2781
0
    int                  offset = 0;
2782
0
    struct rlc_lte_info  *p_rlc_lte_info;
2783
0
    tvbuff_t             *rlc_tvb;
2784
0
    uint8_t              tag = 0;
2785
0
    bool                 seqNumLengthTagPresent = false;
2786
2787
    /* Needs to be at least as long as:
2788
       - the signature string
2789
       - fixed header bytes
2790
       - tag for data
2791
       - at least one byte of RLC PDU payload */
2792
0
    if (tvb_captured_length_remaining(tvb, offset) < (int)(strlen(RLC_LTE_START_STRING)+1+2)) {
2793
0
        return false;
2794
0
    }
2795
2796
    /* OK, compare with signature string */
2797
0
    if (tvb_strneql(tvb, offset, RLC_LTE_START_STRING, (int)strlen(RLC_LTE_START_STRING)) != 0) {
2798
0
        return false;
2799
0
    }
2800
0
    offset += (int)strlen(RLC_LTE_START_STRING);
2801
2802
2803
    /* If redissecting, use previous info struct (if available) */
2804
0
    p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2805
0
    if (p_rlc_lte_info == NULL) {
2806
        /* Allocate new info struct for this frame */
2807
0
        p_rlc_lte_info = wmem_new0(wmem_file_scope(), struct rlc_lte_info);
2808
2809
        /* Read fixed fields */
2810
0
        p_rlc_lte_info->rlcMode = tvb_get_uint8(tvb, offset++);
2811
0
        if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2812
0
            p_rlc_lte_info->sequenceNumberLength = AM_SN_LENGTH_10_BITS;
2813
0
        }
2814
2815
        /* Read optional fields */
2816
0
        while (tag != RLC_LTE_PAYLOAD_TAG) {
2817
            /* Process next tag */
2818
0
            tag = tvb_get_uint8(tvb, offset++);
2819
0
            switch (tag) {
2820
0
                case RLC_LTE_SN_LENGTH_TAG:
2821
0
                    p_rlc_lte_info->sequenceNumberLength = tvb_get_uint8(tvb, offset);
2822
0
                    offset++;
2823
0
                    seqNumLengthTagPresent = true;
2824
0
                    break;
2825
0
                case RLC_LTE_DIRECTION_TAG:
2826
0
                    p_rlc_lte_info->direction = tvb_get_uint8(tvb, offset);
2827
0
                    offset++;
2828
0
                    break;
2829
0
                case RLC_LTE_PRIORITY_TAG:
2830
0
                    p_rlc_lte_info->priority = tvb_get_uint8(tvb, offset);
2831
0
                    offset++;
2832
0
                    break;
2833
0
                case RLC_LTE_UEID_TAG:
2834
0
                    p_rlc_lte_info->ueid = tvb_get_ntohs(tvb, offset);
2835
0
                    offset += 2;
2836
0
                    break;
2837
0
                case RLC_LTE_CHANNEL_TYPE_TAG:
2838
0
                    p_rlc_lte_info->channelType = tvb_get_ntohs(tvb, offset);
2839
0
                    offset += 2;
2840
0
                    break;
2841
0
                case RLC_LTE_CHANNEL_ID_TAG:
2842
0
                    p_rlc_lte_info->channelId = tvb_get_ntohs(tvb, offset);
2843
0
                    offset += 2;
2844
0
                    break;
2845
0
                case RLC_LTE_EXT_LI_FIELD_TAG:
2846
0
                    p_rlc_lte_info->extendedLiField = true;
2847
0
                    break;
2848
0
                case RLC_LTE_NB_MODE_TAG:
2849
0
                    p_rlc_lte_info->nbMode =
2850
0
                        (rlc_lte_nb_mode)tvb_get_uint8(tvb, offset);
2851
0
                    offset++;
2852
0
                    break;
2853
2854
0
                case RLC_LTE_PAYLOAD_TAG:
2855
                    /* Have reached data, so set payload length and get out of loop */
2856
0
                    p_rlc_lte_info->pduLength = tvb_reported_length_remaining(tvb, offset);
2857
0
                    continue;
2858
2859
0
                default:
2860
                    /* It must be a recognised tag */
2861
0
                    report_heur_error(tree, pinfo, &ei_rlc_lte_unknown_udp_framing_tag, tvb, offset-1, 1);
2862
0
                    wmem_free(wmem_file_scope(), p_rlc_lte_info);
2863
0
                    return true;
2864
0
            }
2865
0
        }
2866
2867
0
        if ((p_rlc_lte_info->rlcMode == RLC_UM_MODE) && (seqNumLengthTagPresent == false)) {
2868
            /* Conditional field is not present */
2869
0
            report_heur_error(tree, pinfo, &ei_rlc_lte_missing_udp_framing_tag, tvb, 0, offset);
2870
0
            wmem_free(wmem_file_scope(), p_rlc_lte_info);
2871
0
            return true;
2872
0
        }
2873
2874
        /* Store info in packet */
2875
0
        p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0, p_rlc_lte_info);
2876
0
    }
2877
0
    else {
2878
0
        offset = tvb_reported_length(tvb) - p_rlc_lte_info->pduLength;
2879
0
    }
2880
2881
    /**************************************/
2882
    /* OK, now dissect as RLC LTE         */
2883
2884
    /* Create tvb that starts at actual RLC PDU */
2885
0
    rlc_tvb = tvb_new_subset_remaining(tvb, offset);
2886
0
    dissect_rlc_lte_common(rlc_tvb, pinfo, tree, true);
2887
0
    return true;
2888
0
}
2889
2890
2891
2892
/*****************************/
2893
/* Main dissection function. */
2894
/*****************************/
2895
2896
static int dissect_rlc_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2897
18
{
2898
18
    dissect_rlc_lte_common(tvb, pinfo, tree, false);
2899
18
    return tvb_captured_length(tvb);
2900
18
}
2901
2902
static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool is_udp_framing)
2903
18
{
2904
18
    proto_tree             *rlc_lte_tree;
2905
18
    proto_tree             *context_tree;
2906
18
    proto_item             *top_ti;
2907
18
    proto_item             *context_ti;
2908
18
    proto_item             *ti;
2909
18
    proto_item             *mode_ti;
2910
18
    int                    offset = 0;
2911
18
    struct rlc_lte_info    *p_rlc_lte_info;
2912
2913
    /* Allocate and Zero tap struct */
2914
18
    rlc_3gpp_tap_info *tap_info = wmem_new0(pinfo->pool, rlc_3gpp_tap_info);
2915
18
    tap_info->rat = RLC_RAT_LTE;
2916
2917
    /* Set protocol name */
2918
18
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2919
2920
    /* Create protocol tree. */
2921
18
    top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2922
18
    rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2923
2924
2925
    /* Look for packet info! */
2926
18
    p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
2927
2928
    /* Can't dissect anything without it... */
2929
18
    if (p_rlc_lte_info == NULL) {
2930
0
        proto_tree_add_expert_remaining(rlc_lte_tree, pinfo, &ei_rlc_lte_no_per_frame_info, tvb, offset);
2931
0
        return;
2932
0
    }
2933
2934
    /* Clear info column when using UDP framing */
2935
18
    if (is_udp_framing) {
2936
0
        col_clear(pinfo->cinfo, COL_INFO);
2937
0
    }
2938
2939
    /*****************************************/
2940
    /* Show context information              */
2941
2942
    /* Create context root */
2943
18
    context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2944
18
                                              tvb, offset, 0, "", "Context");
2945
18
    context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2946
18
    proto_item_set_generated(context_ti);
2947
2948
18
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2949
18
                             tvb, 0, 0, p_rlc_lte_info->direction);
2950
18
    proto_item_set_generated(ti);
2951
2952
18
    mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2953
18
                                  tvb, 0, 0, p_rlc_lte_info->rlcMode);
2954
18
    proto_item_set_generated(mode_ti);
2955
2956
18
    if (p_rlc_lte_info->ueid != 0) {
2957
0
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_ueid,
2958
0
                                 tvb, 0, 0, p_rlc_lte_info->ueid);
2959
0
        proto_item_set_generated(ti);
2960
0
    }
2961
2962
18
    if ((p_rlc_lte_info->priority >= 1) && (p_rlc_lte_info->priority <=16)) {
2963
0
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_priority,
2964
0
                                 tvb, 0, 0, p_rlc_lte_info->priority);
2965
0
        proto_item_set_generated(ti);
2966
0
    }
2967
2968
18
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2969
18
                             tvb, 0, 0, p_rlc_lte_info->channelType);
2970
18
    proto_item_set_generated(ti);
2971
2972
18
    if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2973
0
        (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB) ||
2974
18
        (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2975
18
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2976
18
                                 tvb, 0, 0, p_rlc_lte_info->channelId);
2977
18
        proto_item_set_generated(ti);
2978
18
    }
2979
2980
18
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2981
18
                             tvb, 0, 0, p_rlc_lte_info->pduLength);
2982
18
    proto_item_set_generated(ti);
2983
2984
18
    if (p_rlc_lte_info->rlcMode == RLC_UM_MODE) {
2985
0
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_um_sn_length,
2986
0
                                 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2987
0
        proto_item_set_generated(ti);
2988
0
    }
2989
2990
18
    if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2991
18
        if (!p_rlc_lte_info->sequenceNumberLength) {
2992
18
            p_rlc_lte_info->sequenceNumberLength = 10;
2993
18
        }
2994
18
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_am_sn_length,
2995
18
                                 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2996
18
        proto_item_set_generated(ti);
2997
18
    }
2998
2999
    /* Append highlights to top-level item */
3000
18
    if (p_rlc_lte_info->ueid != 0) {
3001
0
        proto_item_append_text(top_ti, "   UEId=%u", p_rlc_lte_info->ueid);
3002
0
        col_append_fstr(pinfo->cinfo, COL_INFO, "UEId=%-4u ", p_rlc_lte_info->ueid);
3003
0
    }
3004
3005
    /* Append context highlights to info column */
3006
18
    write_pdu_label_and_info(top_ti, NULL, pinfo,
3007
18
                             " [%s] [%s] ",
3008
18
                             (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
3009
18
                             val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
3010
3011
18
    if (p_rlc_lte_info->channelId == 0) {
3012
0
        write_pdu_label_and_info(top_ti, NULL, pinfo, "%s   ",
3013
0
                                 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"));
3014
0
    }
3015
18
    else {
3016
18
        write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
3017
18
                                 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
3018
18
                                 p_rlc_lte_info->channelId);
3019
18
    }
3020
3021
    /* Set context-info parts of tap struct */
3022
18
    tap_info->rlcMode = p_rlc_lte_info->rlcMode;
3023
18
    tap_info->direction = p_rlc_lte_info->direction;
3024
18
    tap_info->priority = p_rlc_lte_info->priority;
3025
18
    tap_info->ueid = p_rlc_lte_info->ueid;
3026
18
    tap_info->channelType = p_rlc_lte_info->channelType;
3027
18
    tap_info->channelId = p_rlc_lte_info->channelId;
3028
18
    tap_info->pduLength = p_rlc_lte_info->pduLength;
3029
18
    tap_info->sequenceNumberLength = p_rlc_lte_info->sequenceNumberLength;
3030
18
    tap_info->loggedInMACFrame = (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL);
3031
3032
18
    tap_info->rlc_time = pinfo->abs_ts;
3033
3034
    /* Reset this count */
3035
18
    s_number_of_extensions = 0;
3036
3037
    /* Dissect the RLC PDU itself. Format depends upon mode... */
3038
18
    switch (p_rlc_lte_info->rlcMode) {
3039
3040
0
        case RLC_TM_MODE:
3041
0
            dissect_rlc_lte_tm(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti);
3042
0
            break;
3043
3044
0
        case RLC_UM_MODE:
3045
0
            dissect_rlc_lte_um(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3046
0
                               tap_info);
3047
0
            break;
3048
3049
18
        case RLC_AM_MODE:
3050
18
            dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3051
18
                               tap_info);
3052
18
            break;
3053
3054
0
        case RLC_PREDEF:
3055
            /* Predefined data (i.e. not containing a valid RLC header */
3056
0
            proto_tree_add_item(rlc_lte_tree, hf_rlc_lte_predefined_pdu, tvb, offset, -1, ENC_NA);
3057
0
            write_pdu_label_and_info(top_ti, NULL, pinfo, "   [%u-bytes]",
3058
0
                                     tvb_reported_length_remaining(tvb, offset));
3059
0
            break;
3060
3061
0
        default:
3062
            /* Error - unrecognised mode */
3063
0
            expert_add_info_format(pinfo, mode_ti, &ei_rlc_lte_context_mode,
3064
0
                                   "Unrecognised RLC Mode set (%u)", p_rlc_lte_info->rlcMode);
3065
0
            break;
3066
18
    }
3067
3068
    /* Queue tap info */
3069
16
    tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
3070
16
}
3071
3072
3073
3074
/* Configure number of PDCP SN bits to use for DRB channels */
3075
void set_rlc_lte_drb_pdcp_seqnum_length(packet_info *pinfo, uint16_t ueid, uint8_t drbid,
3076
                                        uint8_t userplane_seqnum_length)
3077
1
{
3078
1
    wmem_tree_key_t key[3];
3079
1
    uint32_t id;
3080
1
    rlc_ue_parameters *params;
3081
3082
1
    if (PINFO_FD_VISITED(pinfo)) {
3083
0
        return;
3084
0
    }
3085
3086
1
    id = (drbid << 16) | ueid;
3087
1
    key[0].length = 1;
3088
1
    key[0].key = &id;
3089
1
    key[1].length = 1;
3090
1
    key[1].key = &pinfo->num;
3091
1
    key[2].length = 0;
3092
1
    key[2].key = NULL;
3093
3094
1
    params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3095
1
    if (params && (params->id != id)) {
3096
0
        params = NULL;
3097
0
    }
3098
1
    if (params == NULL) {
3099
1
        params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3100
1
        params->id = id;
3101
1
        params->ext_li_field = NO_EXT_LI;
3102
1
        wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3103
1
    }
3104
1
    params->pdcp_sn_bits = userplane_seqnum_length;
3105
1
}
3106
3107
/*Configure LI field for AM DRB channels */
3108
void set_rlc_lte_drb_li_field(packet_info *pinfo, uint16_t ueid, uint8_t drbid,
3109
                              bool ul_ext_li_field, bool dl_ext_li_field)
3110
1
{
3111
1
    wmem_tree_key_t key[3];
3112
1
    uint32_t id;
3113
1
    rlc_ue_parameters *params;
3114
3115
1
    if (PINFO_FD_VISITED(pinfo)) {
3116
0
        return;
3117
0
    }
3118
3119
1
    id = (drbid << 16) | ueid;
3120
1
    key[0].length = 1;
3121
1
    key[0].key = &id;
3122
1
    key[1].length = 1;
3123
1
    key[1].key = &pinfo->num;
3124
1
    key[2].length = 0;
3125
1
    key[2].key = NULL;
3126
3127
1
    params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3128
1
    if (params && (params->id != id)) {
3129
0
        params = NULL;
3130
0
    }
3131
1
    if (params == NULL) {
3132
0
        params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3133
0
        params->id = id;
3134
0
        params->pdcp_sn_bits = 12;
3135
0
        wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3136
0
    }
3137
1
    params->ext_li_field = ul_ext_li_field ? UL_EXT_LI : NO_EXT_LI;
3138
1
    params->ext_li_field |= dl_ext_li_field ? DL_EXT_LI : NO_EXT_LI;
3139
1
}
3140
3141
void rlc_lte_reset_ue_bearers(packet_info *pinfo, uint16_t ueid)
3142
0
{
3143
0
    if (PINFO_FD_VISITED(pinfo)) {
3144
0
        return;
3145
0
    }
3146
3147
    /* Need to reset current state of any entries in sequence_analysis_channel_hash */
3148
0
    channel_hash_key   channel_key;
3149
0
    channel_sequence_analysis_status     *p_channel_status;
3150
3151
0
    channel_key.ueId = ueid;
3152
3153
    /* SRBs (1-2, both directions) */
3154
0
    channel_key.channelType = CHANNEL_TYPE_SRB;
3155
0
    for (uint32_t channelId=1; channelId <= 2; ++channelId) {
3156
0
        for (uint32_t direction=0; direction <=1; ++direction) {
3157
            /* Update key */
3158
0
            channel_key.channelId = channelId;
3159
0
            channel_key.direction = direction;
3160
3161
            /* Lookup existing channel status */
3162
0
            p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
3163
0
            if (p_channel_status) {
3164
                /* Reset if already exists */
3165
0
                p_channel_status->previousSequenceNumber = -1;
3166
0
                p_channel_status->previousFrameNum = 0;
3167
0
                p_channel_status->previousSegmentIncomplete = 0;
3168
0
            }
3169
0
        }
3170
0
    }
3171
3172
    /* DRBs (1-32, both directions) */
3173
0
    channel_key.channelType = CHANNEL_TYPE_DRB;
3174
0
    for (uint32_t channelId=1; channelId <= 32; ++channelId) {
3175
0
        for (uint32_t direction=0; direction <=1; ++direction) {
3176
            /* Update key */
3177
0
            channel_key.channelId = channelId;
3178
0
            channel_key.direction = direction;
3179
3180
            /* Lookup existing channel status */
3181
0
            p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
3182
0
            if (p_channel_status) {
3183
                /* Reset if already exists */
3184
0
                p_channel_status->previousSequenceNumber = -1;
3185
0
                p_channel_status->previousFrameNum = 0;
3186
0
                p_channel_status->previousSegmentIncomplete = 0;
3187
0
            }
3188
0
        }
3189
0
    }
3190
0
}
3191
3192
3193
3194
void proto_register_rlc_lte(void)
3195
16
{
3196
16
    static hf_register_info hf[] =
3197
16
    {
3198
        /**********************************/
3199
        /* Items for decoding context     */
3200
16
        { &hf_rlc_lte_context,
3201
16
            { "Context",
3202
16
              "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
3203
16
              NULL, HFILL
3204
16
            }
3205
16
        },
3206
16
        { &hf_rlc_lte_context_mode,
3207
16
            { "RLC Mode",
3208
16
              "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
3209
16
              NULL, HFILL
3210
16
            }
3211
16
        },
3212
16
        { &hf_rlc_lte_context_direction,
3213
16
            { "Direction",
3214
16
              "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
3215
16
              "Direction of message", HFILL
3216
16
            }
3217
16
        },
3218
16
        { &hf_rlc_lte_context_priority,
3219
16
            { "Priority",
3220
16
              "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
3221
16
              NULL, HFILL
3222
16
            }
3223
16
        },
3224
16
        { &hf_rlc_lte_context_ueid,
3225
16
            { "UEId",
3226
16
              "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
3227
16
              "User Equipment Identifier associated with message", HFILL
3228
16
            }
3229
16
        },
3230
16
        { &hf_rlc_lte_context_channel_type,
3231
16
            { "Channel Type",
3232
16
              "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
3233
16
              "Channel Type associated with message", HFILL
3234
16
            }
3235
16
        },
3236
16
        { &hf_rlc_lte_context_channel_id,
3237
16
            { "Channel ID",
3238
16
              "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
3239
16
              "Channel ID associated with message", HFILL
3240
16
            }
3241
16
        },
3242
16
        { &hf_rlc_lte_context_pdu_length,
3243
16
            { "PDU Length",
3244
16
              "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
3245
16
              "Length of PDU (in bytes)", HFILL
3246
16
            }
3247
16
        },
3248
16
        { &hf_rlc_lte_context_um_sn_length,
3249
16
            { "UM Sequence number length",
3250
16
              "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3251
16
              "Length of UM sequence number in bits", HFILL
3252
16
            }
3253
16
        },
3254
16
        { &hf_rlc_lte_context_am_sn_length,
3255
16
            { "AM Sequence number length",
3256
16
              "rlc-lte.am-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3257
16
              "Length of AM sequence number in bits", HFILL
3258
16
            }
3259
16
        },
3260
3261
        /* Transparent mode fields */
3262
16
        { &hf_rlc_lte_tm,
3263
16
            { "TM",
3264
16
              "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
3265
16
              "Transparent Mode", HFILL
3266
16
            }
3267
16
        },
3268
16
        { &hf_rlc_lte_tm_data,
3269
16
            { "TM Data",
3270
16
              "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
3271
16
              "Transparent Mode Data", HFILL
3272
16
            }
3273
16
        },
3274
3275
        /* Unacknowledged mode fields */
3276
16
        { &hf_rlc_lte_um,
3277
16
            { "UM",
3278
16
              "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
3279
16
              "Unacknowledged Mode", HFILL
3280
16
            }
3281
16
        },
3282
16
        { &hf_rlc_lte_um_header,
3283
16
            { "UM Header",
3284
16
              "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
3285
16
              "Unacknowledged Mode Header", HFILL
3286
16
            }
3287
16
        },
3288
16
        { &hf_rlc_lte_um_fi,
3289
16
            { "Framing Info",
3290
16
              "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
3291
16
              NULL, HFILL
3292
16
            }
3293
16
        },
3294
16
        { &hf_rlc_lte_um_fixed_e,
3295
16
            { "Extension",
3296
16
              "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
3297
16
              "Extension in fixed part of UM header", HFILL
3298
16
            }
3299
16
        },
3300
16
        { &hf_rlc_lte_um_sn,
3301
16
            { "Sequence number",
3302
16
              "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
3303
16
              "Unacknowledged Mode Sequence Number", HFILL
3304
16
            }
3305
16
        },
3306
16
        { &hf_rlc_lte_um_fixed_reserved,
3307
16
            { "Reserved",
3308
16
              "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
3309
16
              "Unacknowledged Mode Fixed header reserved bits", HFILL
3310
16
            }
3311
16
        },
3312
16
        { &hf_rlc_lte_um_data,
3313
16
            { "UM Data",
3314
16
              "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
3315
16
              "Unacknowledged Mode Data", HFILL
3316
16
            }
3317
16
        },
3318
16
        { &hf_rlc_lte_extension_part,
3319
16
            { "Extension Part",
3320
16
              "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
3321
16
              NULL, HFILL
3322
16
            }
3323
16
        },
3324
16
        { &hf_rlc_lte_extension_e,
3325
16
            { "Extension",
3326
16
              "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
3327
16
              "Extension in extended part of the header", HFILL
3328
16
            }
3329
16
        },
3330
16
        { &hf_rlc_lte_extension_li,
3331
16
            { "Length Indicator",
3332
16
              "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
3333
16
              NULL, HFILL
3334
16
            }
3335
16
        },
3336
16
        { &hf_rlc_lte_extension_padding,
3337
16
            { "Padding",
3338
16
              "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
3339
16
              "Extension header padding", HFILL
3340
16
            }
3341
16
        },
3342
3343
        /* Acknowledged mode fields */
3344
16
        { &hf_rlc_lte_am,
3345
16
            { "AM",
3346
16
              "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
3347
16
              "Acknowledged Mode", HFILL
3348
16
            }
3349
16
        },
3350
16
        { &hf_rlc_lte_am_header,
3351
16
            { "AM Header",
3352
16
              "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
3353
16
              "Acknowledged Mode Header", HFILL
3354
16
            }
3355
16
        },
3356
16
        { &hf_rlc_lte_am_data_control,
3357
16
            { "Frame type",
3358
16
              "rlc-lte.am.frame-type", FT_BOOLEAN, 8, TFS(&tfs_data_pdu_control_pdu), 0x80,
3359
16
              "AM Frame Type (Control or Data)", HFILL
3360
16
            }
3361
16
        },
3362
16
        { &hf_rlc_lte_am_rf,
3363
16
            { "Re-segmentation Flag",
3364
16
              "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
3365
16
              "AM Re-segmentation Flag", HFILL
3366
16
            }
3367
16
        },
3368
16
        { &hf_rlc_lte_am_p,
3369
16
            { "Polling Bit",
3370
16
              "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
3371
16
              NULL, HFILL
3372
16
            }
3373
16
        },
3374
16
        { &hf_rlc_lte_am_fi,
3375
16
            { "Framing Info",
3376
16
              "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
3377
16
              "AM Framing Info", HFILL
3378
16
            }
3379
16
        },
3380
16
        { &hf_rlc_lte_am_fixed_e,
3381
16
            { "Extension",
3382
16
              "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
3383
16
              "Fixed Extension Bit", HFILL
3384
16
            }
3385
16
        },
3386
16
        { &hf_rlc_lte_am_fixed_sn,
3387
16
            { "Sequence Number",
3388
16
              "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
3389
16
              "AM Fixed Sequence Number", HFILL
3390
16
            }
3391
16
        },
3392
16
        { &hf_rlc_lte_am_fixed_reserved,
3393
16
            { "Reserved",
3394
16
              "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x03,
3395
16
              "Acknowledged Mode Fixed header reserved bits", HFILL
3396
16
            }
3397
16
        },
3398
16
        { &hf_rlc_lte_am_segment_lsf16,
3399
16
            { "Last Segment Flag",
3400
16
              "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x02,
3401
16
              NULL, HFILL
3402
16
            }
3403
16
        },
3404
16
        { &hf_rlc_lte_am_fixed_reserved2,
3405
16
            { "Reserved",
3406
16
              "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x01,
3407
16
              "Acknowledged Mode Fixed header reserved bit", HFILL
3408
16
            }
3409
16
        },
3410
16
        { &hf_rlc_lte_am_fixed_sn16,
3411
16
            { "Sequence Number",
3412
16
              "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3413
16
              "AM Fixed Sequence Number", HFILL
3414
16
            }
3415
16
        },
3416
16
        { &hf_rlc_lte_am_segment_lsf,
3417
16
            { "Last Segment Flag",
3418
16
              "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3419
16
              NULL, HFILL
3420
16
            }
3421
16
        },
3422
16
        { &hf_rlc_lte_am_segment_so,
3423
16
            { "Segment Offset",
3424
16
              "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3425
16
              NULL, HFILL
3426
16
            }
3427
16
        },
3428
16
        { &hf_rlc_lte_am_segment_so16,
3429
16
            { "Segment Offset",
3430
16
              "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x0,
3431
16
              NULL, HFILL
3432
16
            }
3433
16
        },
3434
16
        { &hf_rlc_lte_am_data,
3435
16
            { "AM Data",
3436
16
              "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3437
16
              "Acknowledged Mode Data", HFILL
3438
16
            }
3439
16
        },
3440
3441
16
        { &hf_rlc_lte_am_cpt,
3442
16
            { "Control PDU Type",
3443
16
              "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3444
16
              "AM Control PDU Type", HFILL
3445
16
            }
3446
16
        },
3447
16
        { &hf_rlc_lte_am_ack_sn,
3448
16
            { "ACK Sequence Number",
3449
16
              "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3450
16
              "Sequence Number we expect to receive next", HFILL
3451
16
            }
3452
16
        },
3453
16
        { &hf_rlc_lte_am_e1,
3454
16
            { "Extension bit 1",
3455
16
              "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3456
16
              NULL, HFILL
3457
16
            }
3458
16
        },
3459
16
        { &hf_rlc_lte_am_e2,
3460
16
            { "Extension bit 2",
3461
16
              "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3462
16
              NULL, HFILL
3463
16
            }
3464
16
        },
3465
16
        { &hf_rlc_lte_am_nacks,
3466
16
            { "Number of NACKs",
3467
16
              "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3468
16
              "Number of NACKs in this status PDU", HFILL
3469
16
            }
3470
16
        },
3471
16
        { &hf_rlc_lte_am_nack_sn,
3472
16
            { "NACK Sequence Number",
3473
16
              "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3474
16
              "Negative Acknowledgement Sequence Number", HFILL
3475
16
            }
3476
16
        },
3477
16
        { &hf_rlc_lte_am_so_start,
3478
16
            { "SO Start",
3479
16
              "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3480
16
              "Segment Offset Start byte index", HFILL
3481
16
            }
3482
16
        },
3483
16
        { &hf_rlc_lte_am_so_end,
3484
16
            { "SO End",
3485
16
              "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3486
16
              "Segment Offset End byte index", HFILL
3487
16
            }
3488
16
        },
3489
3490
16
        { &hf_rlc_lte_predefined_pdu,
3491
16
            { "Predefined data",
3492
16
              "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3493
16
              "Predefined test data", HFILL
3494
16
            }
3495
16
        },
3496
3497
        /* Sequence analysis fields */
3498
16
        { &hf_rlc_lte_sequence_analysis,
3499
16
            { "Sequence Analysis",
3500
16
              "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3501
16
              NULL, HFILL
3502
16
            }
3503
16
        },
3504
16
        { &hf_rlc_lte_sequence_analysis_ok,
3505
16
            { "OK",
3506
16
              "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3507
16
              NULL, HFILL
3508
16
            }
3509
16
        },
3510
16
        { &hf_rlc_lte_sequence_analysis_previous_frame,
3511
16
            { "Previous frame for channel",
3512
16
              "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3513
16
              NULL, HFILL
3514
16
            }
3515
16
        },
3516
16
        { &hf_rlc_lte_sequence_analysis_next_frame,
3517
16
            { "Next frame for channel",
3518
16
              "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3519
16
              NULL, HFILL
3520
16
            }
3521
16
        },
3522
16
        { &hf_rlc_lte_sequence_analysis_expected_sn,
3523
16
            { "Expected SN",
3524
16
              "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3525
16
              NULL, HFILL
3526
16
            }
3527
16
        },
3528
16
        { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3529
16
            { "Frame info continued correctly",
3530
16
              "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3531
16
              NULL, HFILL
3532
16
            }
3533
16
        },
3534
16
        { &hf_rlc_lte_sequence_analysis_mac_retx,
3535
16
            { "Frame retransmitted by MAC",
3536
16
              "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3537
16
              NULL, HFILL
3538
16
            }
3539
16
        },
3540
16
        { &hf_rlc_lte_sequence_analysis_retx,
3541
16
            { "Retransmitted frame",
3542
16
              "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3543
16
              NULL, HFILL
3544
16
            }
3545
16
        },
3546
16
        { &hf_rlc_lte_sequence_analysis_skipped,
3547
16
            { "Skipped frames",
3548
16
              "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3549
16
              NULL, HFILL
3550
16
            }
3551
16
        },
3552
16
        { &hf_rlc_lte_sequence_analysis_repeated,
3553
16
            { "Repeated frame",
3554
16
              "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3555
16
              NULL, HFILL
3556
16
            }
3557
16
        },
3558
16
        { &hf_rlc_lte_sequence_analysis_repeated_nack,
3559
16
            { "Repeated NACK",
3560
16
              "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3561
16
              NULL, HFILL
3562
16
            }
3563
16
        },
3564
16
        { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3565
16
            { "Frame with previous status PDU",
3566
16
              "rlc-lte.sequence-analysis.repeated-nack.original-frame",  FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_DUP_ACK), 0x0,
3567
16
              NULL, HFILL
3568
16
            }
3569
16
        },
3570
3571
16
        { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3572
16
            { "Out of range ACK",
3573
16
              "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3574
16
              NULL, HFILL
3575
16
            }
3576
16
        },
3577
16
        { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3578
16
            { "Frame with most recent SN",
3579
16
              "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame",  FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3580
16
              NULL, HFILL
3581
16
            }
3582
16
        },
3583
3584
        /* Reassembly fields */
3585
16
        { &hf_rlc_lte_reassembly_source,
3586
16
            { "Reassembly Source",
3587
16
              "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3588
16
              NULL, HFILL
3589
16
            }
3590
16
        },
3591
16
        { &hf_rlc_lte_reassembly_source_number_of_segments,
3592
16
            { "Number of segments",
3593
16
              "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3594
16
              NULL, HFILL
3595
16
            }
3596
16
        },
3597
16
        { &hf_rlc_lte_reassembly_source_total_length,
3598
16
            { "Total length",
3599
16
              "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3600
16
              NULL, HFILL
3601
16
            }
3602
16
        },
3603
16
        { &hf_rlc_lte_reassembly_source_segment,
3604
16
            { "Segment",
3605
16
              "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3606
16
              NULL, HFILL
3607
16
            }
3608
16
        },
3609
16
        { &hf_rlc_lte_reassembly_source_segment_sn,
3610
16
            { "SN",
3611
16
              "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3612
16
              NULL, HFILL
3613
16
            }
3614
16
        },
3615
16
        { &hf_rlc_lte_reassembly_source_segment_framenum,
3616
16
            { "Frame",
3617
16
              "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3618
16
              NULL, HFILL
3619
16
            }
3620
16
        },
3621
16
        { &hf_rlc_lte_reassembly_source_segment_length,
3622
16
            { "Length",
3623
16
              "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3624
16
              NULL, HFILL
3625
16
            }
3626
16
        },
3627
3628
16
        { &hf_rlc_lte_header_only,
3629
16
            { "RLC PDU Header only",
3630
16
              "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3631
16
              NULL, HFILL
3632
16
            }
3633
16
        },
3634
16
    };
3635
3636
16
    static int *ett[] =
3637
16
    {
3638
16
        &ett_rlc_lte,
3639
16
        &ett_rlc_lte_context,
3640
16
        &ett_rlc_lte_um_header,
3641
16
        &ett_rlc_lte_am_header,
3642
16
        &ett_rlc_lte_extension_part,
3643
16
        &ett_rlc_lte_sequence_analysis,
3644
16
        &ett_rlc_lte_reassembly_source,
3645
16
        &ett_rlc_lte_reassembly_source_segment
3646
16
    };
3647
3648
16
    static ei_register_info ei[] = {
3649
16
        { &ei_rlc_lte_sequence_analysis_last_segment_not_continued, { "rlc-lte.sequence-analysis.last-segment-not-continued", PI_SEQUENCE, PI_WARN, "Last segment of previous PDU was not continued for UE", EXPFILL }},
3650
16
        { &ei_rlc_lte_sequence_analysis_last_segment_complete, { "rlc-lte.sequence-analysis.last-segment-complete", PI_SEQUENCE, PI_WARN, "Last segment of previous PDU was complete, but new segment was not started on UE", EXPFILL }},
3651
16
        { &ei_rlc_lte_sequence_analysis_mac_retx, { "rlc-lte.sequence-analysis.mac-retx.expert", PI_SEQUENCE, PI_WARN, "AM Frame retransmitted due to MAC retx!", EXPFILL }},
3652
16
        { &ei_rlc_lte_sequence_analysis_retx, { "rlc-lte.sequence-analysis.retx.expert", PI_SEQUENCE, PI_WARN, "AM Frame retransmitted most likely in response to NACK", EXPFILL }},
3653
16
        { &ei_rlc_lte_sequence_analysis_repeated, { "rlc-lte.sequence-analysis.repeated-frame.expert", PI_SEQUENCE, PI_WARN, "AM SN Repeated - probably because didn't receive Status PDU?", EXPFILL }},
3654
16
        { &ei_rlc_lte_am_sn_missing, { "rlc-lte.sequence-analysis.am-sn.missing", PI_SEQUENCE, PI_WARN, "AM SNs missing", EXPFILL }},
3655
16
        { &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame, { "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame.expert", PI_SEQUENCE, PI_ERROR, "AM ACK for SN - but last received SN in other direction is X", EXPFILL }},
3656
16
        { &ei_rlc_lte_um_sn_missing, { "rlc-lte.sequence-analysis.um-sn.missing", PI_SEQUENCE, PI_WARN, "UM SNs missing", EXPFILL }},
3657
16
        { &ei_rlc_lte_um_sn_repeated, { "rlc-lte.sequence-analysis.um-sn.repeated", PI_SEQUENCE, PI_WARN, "UM SN repeated", EXPFILL }},
3658
16
        { &ei_rlc_lte_wrong_sequence_number, { "rlc-lte.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
3659
16
        { &ei_rlc_lte_sequence_analysis_repeated_nack, { "rlc-lte.sequence-analysis.repeated-nack.expert", PI_SEQUENCE, PI_ERROR, "Same SN NACKd on successive Status PDUs", EXPFILL }},
3660
16
        { &ei_rlc_lte_reserved_bits_not_zero, { "rlc-lte.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
3661
16
        { &ei_rlc_lte_um_sn, { "rlc-lte.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
3662
16
        { &ei_rlc_lte_header_only, { "rlc-lte.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3663
16
        { &ei_rlc_lte_am_cpt, { "rlc-lte.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
3664
16
        { &ei_rlc_lte_am_nack_sn_ack_same, { "rlc-lte.am.nack-sn.ack-same", PI_MALFORMED, PI_ERROR, "Status PDU shouldn't ACK and NACK the same sequence number", EXPFILL }},
3665
16
        { &ei_rlc_lte_am_nack_sn_ahead_ack, { "rlc-lte.am.nack-sn.ahead-ack", PI_MALFORMED, PI_ERROR, "NACK must not be ahead of ACK in status PDU", EXPFILL }},
3666
16
        { &ei_rlc_lte_am_nack_sn_partial, { "rlc-lte.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
3667
16
        { &ei_rlc_lte_am_nack_sn, { "rlc-lte.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
3668
16
        { &ei_rlc_lte_bytes_after_status_pdu_complete, { "rlc-lte.bytes-after-status-pdu-complete", PI_MALFORMED, PI_ERROR, "bytes remaining after Status PDU complete", EXPFILL }},
3669
16
        { &ei_rlc_lte_am_data_no_data_beyond_extensions, { "rlc-lte.am-data.no-data-beyond-extensions", PI_MALFORMED, PI_ERROR, "AM data PDU doesn't contain any data beyond extensions", EXPFILL }},
3670
16
        { &ei_rlc_lte_am_data_no_data, { "rlc-lte.am-data.no-data", PI_MALFORMED, PI_ERROR, "AM data PDU doesn't contain any data", EXPFILL }},
3671
16
        { &ei_rlc_lte_context_mode, { "rlc-lte.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
3672
16
        { &ei_rlc_lte_no_per_frame_info, { "rlc-lte.no_per_frame_info", PI_UNDECODED, PI_ERROR, "Can't dissect LTE RLC frame because no per-frame info was attached!", EXPFILL }},
3673
16
        { &ei_rlc_lte_unknown_udp_framing_tag, { "rlc-lte.unknown-udp-framing-tag", PI_UNDECODED, PI_WARN, "Unknown UDP framing tag, aborting dissection", EXPFILL }},
3674
16
        { &ei_rlc_lte_missing_udp_framing_tag, { "rlc-lte.missing-udp-framing-tag", PI_UNDECODED, PI_WARN, "Missing UDP framing conditional tag, aborting dissection", EXPFILL }}
3675
16
    };
3676
3677
16
    static const enum_val_t sequence_analysis_vals[] = {
3678
16
        {"no-analysis", "No-Analysis",     false},
3679
16
        {"mac-only",    "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3680
16
        {"rlc-only",    "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3681
16
        {NULL, NULL, -1}
3682
16
    };
3683
3684
16
    module_t *rlc_lte_module;
3685
16
    expert_module_t* expert_rlc_lte;
3686
3687
    /* Register protocol. */
3688
16
    proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3689
16
    proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3690
16
    proto_register_subtree_array(ett, array_length(ett));
3691
16
    expert_rlc_lte = expert_register_protocol(proto_rlc_lte);
3692
16
    expert_register_field_array(expert_rlc_lte, ei, array_length(ei));
3693
3694
    /* Allow other dissectors to find this one by name. */
3695
16
    register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3696
3697
    /* Register the tap name */
3698
16
    rlc_lte_tap = register_tap("rlc-3gpp");
3699
3700
    /* Preferences */
3701
16
    rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3702
3703
16
    prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3704
16
        "Do sequence analysis for AM channels",
3705
16
        "Attempt to keep track of PDUs for AM channels, and point out problems",
3706
16
        &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, false);
3707
3708
16
    prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3709
16
        "Do sequence analysis for UM channels",
3710
16
        "Attempt to keep track of PDUs for UM channels, and point out problems",
3711
16
        &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, false);
3712
3713
16
    prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3714
16
        "Call PDCP dissector for SRB PDUs",
3715
16
        "Call PDCP dissector for signalling PDUs.  Note that without reassembly, it can"
3716
16
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3717
16
        &global_rlc_lte_call_pdcp_for_srb);
3718
3719
16
    prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3720
16
        "Call PDCP dissector for DRB PDUs",
3721
16
        "Call PDCP dissector for user-plane PDUs.  Note that without reassembly, it can"
3722
16
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3723
16
        &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, false);
3724
3725
3726
16
    prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3727
16
        "Call RRC dissector for CCCH PDUs",
3728
16
        "Call RRC dissector for CCCH PDUs",
3729
16
        &global_rlc_lte_call_rrc_for_ccch);
3730
3731
16
    prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_mcch",
3732
16
        "Call RRC dissector for MCCH PDUs",
3733
16
        "Call RRC dissector for MCCH PDUs  Note that without reassembly, it can"
3734
16
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3735
16
        &global_rlc_lte_call_rrc_for_mcch);
3736
3737
16
    prefs_register_bool_preference(rlc_lte_module, "call_ip_for_mtch",
3738
16
        "Call IP dissector for MTCH PDUs",
3739
16
        "Call ip dissector for MTCH PDUs  Note that without reassembly, it can"
3740
16
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3741
16
        &global_rlc_lte_call_ip_for_mtch);
3742
3743
16
    prefs_register_obsolete_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp");
3744
3745
16
    prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3746
16
        "May see RLC headers only",
3747
16
        "When enabled, if data is not present, don't report as an error, but instead "
3748
16
        "add expert info to indicate that headers were omitted",
3749
16
        &global_rlc_lte_headers_expected);
3750
3751
16
    prefs_register_bool_preference(rlc_lte_module, "reassembly",
3752
16
        "Attempt SDU reassembly",
3753
16
        "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3754
16
        "more than one RLC PDU.  Note: does not currently support out-of-order or "
3755
16
        "re-segmentation. N.B. sequence analysis must also be turned on in order "
3756
16
        "for reassembly to work",
3757
16
        &global_rlc_lte_reassembly);
3758
3759
16
    ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3760
3761
16
    sequence_analysis_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3762
16
    sequence_analysis_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3763
16
    repeated_nack_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3764
16
    repeated_nack_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3765
16
    reassembly_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3766
16
}
3767
3768
void proto_reg_handoff_rlc_lte(void)
3769
16
{
3770
    /* Add as a heuristic UDP dissector */
3771
16
    heur_dissector_add("udp", dissect_rlc_lte_heur, "RLC-LTE over UDP", "rlc_lte_udp", proto_rlc_lte, HEURISTIC_DISABLE);
3772
3773
16
    pdcp_lte_handle        = find_dissector_add_dependency("pdcp-lte", proto_rlc_lte);
3774
16
    ip_handle              = find_dissector_add_dependency("ip", proto_rlc_lte);
3775
16
    lte_rrc_mcch           = find_dissector_add_dependency("lte_rrc.mcch", proto_rlc_lte);
3776
16
    lte_rrc_ul_ccch        = find_dissector_add_dependency("lte_rrc.ul_ccch", proto_rlc_lte);
3777
16
    lte_rrc_dl_ccch        = find_dissector_add_dependency("lte_rrc.dl_ccch", proto_rlc_lte);
3778
16
    lte_rrc_bcch_bch       = find_dissector_add_dependency("lte_rrc.bcch_bch", proto_rlc_lte);
3779
16
    lte_rrc_bcch_dl_sch    = find_dissector_add_dependency("lte_rrc.bcch_dl_sch", proto_rlc_lte);
3780
16
    lte_rrc_pcch           = find_dissector_add_dependency("lte_rrc.pcch", proto_rlc_lte);
3781
16
    lte_rrc_ul_ccch_nb     = find_dissector_add_dependency("lte_rrc.ul_ccch.nb", proto_rlc_lte);
3782
16
    lte_rrc_dl_ccch_nb     = find_dissector_add_dependency("lte_rrc.dl_ccch.nb", proto_rlc_lte);
3783
16
    lte_rrc_bcch_bch_nb    = find_dissector_add_dependency("lte_rrc.bcch_bch.nb", proto_rlc_lte);
3784
16
    lte_rrc_bcch_dl_sch_nb = find_dissector_add_dependency("lte_rrc.bcch_dl_sch.nb", proto_rlc_lte);
3785
16
    lte_rrc_pcch_nb        = find_dissector_add_dependency("lte_rrc.pcch.nb", proto_rlc_lte);
3786
3787
16
    proto_mac_lte = proto_get_id_by_filter_name("mac-lte");
3788
16
    proto_pdcp_lte = proto_get_id_by_filter_name("pdcp-lte");
3789
16
}
3790
3791
/*
3792
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
3793
 *
3794
 * Local variables:
3795
 * c-basic-offset: 4
3796
 * tab-width: 8
3797
 * indent-tabs-mode: nil
3798
 * End:
3799
 *
3800
 * vi: set shiftwidth=4 tabstop=8 expandtab:
3801
 * :indentSize=4:tabSize=8:noTabs=true:
3802
 */