Coverage Report

Created: 2026-06-30 07:22

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
14
#define SEQUENCE_ANALYSIS_MAC_ONLY 1
47
14
#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
0
#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
0
#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
0
    #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
0
{
465
0
    status->reassembly_info = wmem_new0(wmem_file_scope(), rlc_channel_reassembly_info);
466
0
}
467
468
/* Hide previous one */
469
static void reassembly_destroy(channel_sequence_analysis_status *status)
470
0
{
471
    /* Just "leak" it. There seems to be no way to free this memory... */
472
0
    status->reassembly_info = NULL;
473
0
}
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
0
{
480
0
    int segment_number =  status->reassembly_info->number_of_segments;
481
0
    uint8_t *segment_data;
482
483
    /* Give up if reach segment limit */
484
0
    if (segment_number >= (RLC_MAX_SEGMENTS-1)) {
485
0
        reassembly_destroy(status);
486
0
        return;
487
0
    }
488
489
0
    segment_data = (uint8_t *)tvb_memdup(wmem_file_scope(),tvb, offset, length);
490
491
    /* Add new segment */
492
0
    status->reassembly_info->segments[segment_number].frameNum = frame;
493
0
    status->reassembly_info->segments[segment_number].SN = SN;
494
0
    status->reassembly_info->segments[segment_number].data = segment_data;
495
0
    status->reassembly_info->segments[segment_number].length = length;
496
497
0
    status->reassembly_info->number_of_segments++;
498
0
}
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
0
{
649
0
    #define MAX_INFO_BUFFER 256
650
0
    static char info_buffer[MAX_INFO_BUFFER];
651
652
0
    va_list ap;
653
654
0
    va_start(ap, format);
655
0
    vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
656
0
    va_end(ap);
657
658
    /* Add to indicated places */
659
0
    col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
660
0
    proto_item_append_text(pdu_ti, "%s", info_buffer);
661
0
    if (sub_ti != NULL) {
662
0
        proto_item_append_text(sub_ti, "%s", info_buffer);
663
0
    }
664
0
}
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
0
{
673
    /* Add to indicated places */
674
0
    col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
675
0
    proto_item_append_text(pdu_ti, "%s", info_buffer);
676
0
    if (sub_ti != NULL) {
677
0
        proto_item_append_text(sub_ti, "%s", info_buffer);
678
0
    }
679
0
}
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
0
{
689
0
    uint8_t isOdd;
690
0
    uint64_t extension = 1;
691
0
    uint64_t length;
692
693
    /* Reset this count */
694
0
    s_number_of_extensions = 0;
695
696
0
    while (extension && (s_number_of_extensions < MAX_RLC_SDUS)) {
697
0
        proto_tree *extension_part_tree;
698
0
        proto_item *extension_part_ti;
699
700
        /* Extension part subtree */
701
0
        extension_part_ti = proto_tree_add_string_format(tree,
702
0
                                                         hf_rlc_lte_extension_part,
703
0
                                                         tvb, offset, 2,
704
0
                                                         "",
705
0
                                                         "Extension Part");
706
0
        extension_part_tree = proto_item_add_subtree(extension_part_ti,
707
0
                                                     ett_rlc_lte_extension_part);
708
709
0
        if (p_rlc_lte_info->extendedLiField == false) {
710
0
            isOdd = (s_number_of_extensions % 2);
711
712
            /* Read next extension */
713
0
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_e, tvb,
714
0
                                        (offset*8) + ((isOdd) ? 4 : 0),
715
0
                                        1,
716
0
                                        &extension, ENC_BIG_ENDIAN);
717
718
            /* Read length field */
719
0
            proto_tree_add_bits_ret_val(extension_part_tree, hf_rlc_lte_extension_li, tvb,
720
0
                                        (offset*8) + ((isOdd) ? 5 : 1),
721
0
                                        11,
722
0
                                        &length, ENC_BIG_ENDIAN);
723
724
            /* Move on to byte of next extension */
725
0
            if (isOdd) {
726
0
                offset += 2;
727
0
            } else {
728
0
                offset++;
729
0
            }
730
0
        } 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
0
        proto_item_append_text(extension_part_tree, " (length=%u)", (uint16_t)length);
748
749
0
        s_lengths[s_number_of_extensions++] = (uint16_t)length;
750
0
    }
751
752
    /* May need to skip padding after last extension part */
753
0
    isOdd = (s_number_of_extensions % 2);
754
0
    if (isOdd && (p_rlc_lte_info->extendedLiField == false)) {
755
0
        proto_tree_add_item(tree, hf_rlc_lte_extension_padding,
756
0
                            tvb, offset++, 1, ENC_BIG_ENDIAN);
757
0
    }
758
759
0
    return offset;
760
0
}
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
0
{
771
    /* Reflect this PDU in the info column */
772
0
    if (length > 0) {
773
0
        write_pdu_label_and_info(top_ti, NULL, pinfo,
774
0
                                 "  %s%u-byte%s%s",
775
0
                                 (first_includes_start) ? "[" : "..",
776
0
                                 length,
777
0
                                 (length > 1) ? "s" : "",
778
0
                                 (last_includes_end) ? "]" : "..");
779
0
    }
780
0
    else {
781
0
        write_pdu_label_and_info(top_ti, NULL, pinfo,
782
0
                                 "  %sunknown-bytes%s",
783
0
                                 (first_includes_start) ? "[" : "..",
784
0
                                 (last_includes_end) ? "]" : "..");
785
0
    }
786
0
}
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
0
{
794
0
    wmem_tree_key_t key[3];
795
0
    uint32_t id;
796
0
    rlc_ue_parameters *params;
797
798
    /* Add raw data (according to mode) */
799
0
    proto_item *data_ti = proto_tree_add_item(tree,
800
0
                                              (rlc_info->rlcMode == RLC_AM_MODE) ?
801
0
                                                    hf_rlc_lte_am_data :
802
0
                                                    hf_rlc_lte_um_data,
803
0
                                              tvb, offset, length, ENC_NA);
804
805
0
    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
0
}
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
0
{
960
0
    const channel_hash_key* val1 = (const channel_hash_key *)v;
961
0
    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
0
    return ((val1->ueId        == val2->ueId) &&
967
0
            (val1->channelType == val2->channelType) &&
968
0
            (val1->channelId   == val2->channelId) &&
969
0
            (val1->direction   == val2->direction));
970
0
}
971
972
/* Compute a hash value for a given key. */
973
static unsigned rlc_channel_hash_func(const void *v)
974
0
{
975
0
    const channel_hash_key* val1 = (const channel_hash_key *)v;
976
977
    /* TODO: check/reduce multipliers */
978
0
    return ((val1->ueId * 1024) + (val1->channelType*64) + (val1->channelId*2) + val1->direction);
979
0
}
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
0
{
996
0
    const rlc_result_hash_key *val1 = (const rlc_result_hash_key *)v;
997
0
    const rlc_result_hash_key *val2 = (const rlc_result_hash_key *)v2;
998
999
    /* All fields (and any padding...) must match */
1000
0
    return (memcmp(val1, val2, sizeof(rlc_result_hash_key)) == 0);
1001
0
}
1002
1003
/* Compute a hash value for a given key. */
1004
static unsigned rlc_result_hash_func(const void *v)
1005
0
{
1006
0
    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
0
    return val1->frameNumber + val1->SN +
1010
0
                               val1->channelType +
1011
0
                               val1->channelId +
1012
0
                               val1->direction;
1013
0
}
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
0
{
1020
0
    static rlc_result_hash_key key;
1021
0
    rlc_result_hash_key *p_key;
1022
1023
    /* Only allocate a struct when will be adding entry */
1024
0
    if (do_persist) {
1025
0
        p_key = wmem_new0(wmem_file_scope(), rlc_result_hash_key);
1026
0
    }
1027
0
    else {
1028
0
        memset(&key, 0, sizeof(rlc_result_hash_key));
1029
0
        p_key = &key;
1030
0
    }
1031
1032
    /* Fill in details, and return pointer */
1033
0
    p_key->frameNumber = frameNumber;
1034
0
    p_key->SN = SN;
1035
0
    p_key->channelType = p_rlc_lte_info->channelType;
1036
0
    p_key->channelId = p_rlc_lte_info->channelId;
1037
0
    p_key->direction = p_rlc_lte_info->direction;
1038
1039
0
    return p_key;
1040
0
}
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
0
{
1096
0
    proto_tree *seqnum_tree;
1097
0
    proto_item *seqnum_ti;
1098
0
    proto_item *ti;
1099
1100
    /* Create subtree */
1101
0
    seqnum_ti = proto_tree_add_string_format(tree,
1102
0
                                             hf_rlc_lte_sequence_analysis,
1103
0
                                             tvb, 0, 0,
1104
0
                                             "", "Sequence Analysis");
1105
0
    seqnum_tree = proto_item_add_subtree(seqnum_ti,
1106
0
                                         ett_rlc_lte_sequence_analysis);
1107
0
    proto_item_set_generated(seqnum_ti);
1108
1109
0
    if (p->previousFrameNum != 0) {
1110
0
        ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_previous_frame,
1111
0
                                 tvb, 0, 0, p->previousFrameNum);
1112
0
        proto_item_set_generated(ti);
1113
0
    }
1114
1115
0
    switch (p_rlc_lte_info->rlcMode) {
1116
0
        case RLC_AM_MODE:
1117
1118
            /********************************************/
1119
            /* AM                                       */
1120
            /********************************************/
1121
1122
0
            switch (p->state) {
1123
0
                case SN_OK:
1124
0
                    if (isControlFrame) {
1125
0
                        return;
1126
0
                    }
1127
1128
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1129
0
                                                tvb, 0, 0, true);
1130
0
                    proto_item_set_generated(ti);
1131
0
                    proto_item_append_text(seqnum_ti, " - OK");
1132
1133
                    /* Link to next SN in channel (if known) */
1134
0
                    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
0
                    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
0
                case SN_Retx:
1164
0
                    if (isControlFrame) {
1165
0
                        return;
1166
0
                    }
1167
1168
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1169
0
                                                tvb, 0, 0, false);
1170
0
                    proto_item_set_generated(ti);
1171
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_retx,
1172
0
                                                tvb, 0, 0, true);
1173
0
                    proto_item_set_generated(ti);
1174
0
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_retx,
1175
0
                                           "AM Frame retransmitted for %s on UE %u - most likely in response to NACK (%s-%u)",
1176
0
                                           val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1177
0
                                           p_rlc_lte_info->ueid,
1178
0
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1179
0
                                           p_rlc_lte_info->channelId);
1180
0
                    proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
1181
0
                    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
0
                case SN_Missing:
1204
0
                    if (isControlFrame) {
1205
0
                        return;
1206
0
                    }
1207
1208
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1209
0
                                                tvb, 0, 0, false);
1210
0
                    proto_item_set_generated(ti);
1211
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_skipped,
1212
0
                                                tvb, 0, 0, true);
1213
0
                    proto_item_set_generated(ti);
1214
0
                    if (p->lastSN != p->firstSN) {
1215
0
                        expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_sn_missing,
1216
0
                                               "AM SNs (%u to %u) missing for %s on UE %u (%s-%u)",
1217
0
                                               p->firstSN, p->lastSN,
1218
0
                                               val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
1219
0
                                               p_rlc_lte_info->ueid,
1220
0
                                               val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1221
0
                                               p_rlc_lte_info->channelId);
1222
0
                        proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
1223
0
                                               p->firstSN, p->lastSN);
1224
0
                        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
0
                        } else {
1227
0
                            tap_info->missingSNs = ((1024 + p->lastSN - p->firstSN) % 1024) + 1;
1228
0
                        }
1229
0
                    }
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
0
                    break;
1242
1243
0
                case ACK_Out_of_Window:
1244
0
                    if (!isControlFrame) {
1245
0
                        return;
1246
0
                    }
1247
1248
1249
                    /* Not OK */
1250
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
1251
0
                                                tvb, 0, 0, false);
1252
                    /* Out of range */
1253
0
                    proto_item_set_generated(ti);
1254
0
                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
1255
0
                                                tvb, 0, 0, true);
1256
0
                    proto_item_set_generated(ti);
1257
1258
                    /* Link back to last seen SN in other direction */
1259
0
                    ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1260
0
                                             tvb, 0, 0, p->previousFrameNum);
1261
0
                    proto_item_set_generated(ti);
1262
1263
                    /* Expert error */
1264
0
                    expert_add_info_format(pinfo, ti, &ei_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
1265
0
                                           "AM ACK for SN %u - but last received SN in other direction is %u for UE %u (%s-%u)",
1266
0
                                           p->firstSN, p->sequenceExpected,
1267
0
                                           p_rlc_lte_info->ueid,
1268
0
                                           val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
1269
0
                                           p_rlc_lte_info->channelId);
1270
0
                    proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
1271
0
                                           p->firstSN, p->sequenceExpected);
1272
1273
0
                    break;
1274
1275
0
                default:
1276
0
                    return;
1277
0
            }
1278
0
            break;
1279
1280
0
        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
0
    }
1402
0
}
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
0
{
1418
0
    channel_hash_key   channel_key;
1419
0
    channel_hash_key   *p_channel_key;
1420
0
    channel_sequence_analysis_status     *p_channel_status;
1421
0
    sequence_analysis_report *p_report_in_frame = NULL;
1422
0
    bool                   createdChannel = false;
1423
0
    uint16_t               expectedSequenceNumber = 0;
1424
0
    uint32_t               snLimit = 0;
1425
1426
    /* If find stat_report_in_frame already, use that and get out */
1427
0
    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
0
    channel_key.ueId = p_rlc_lte_info->ueid;
1447
0
    channel_key.channelType = p_rlc_lte_info->channelType;
1448
0
    channel_key.channelId = p_rlc_lte_info->channelId;
1449
0
    channel_key.direction = p_rlc_lte_info->direction;
1450
1451
    /* Do the table lookup */
1452
0
    p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1453
1454
    /* Create table entry if necessary */
1455
0
    if (p_channel_status == NULL) {
1456
0
        createdChannel = true;
1457
1458
        /* Allocate a new value and duplicate key contents */
1459
0
        p_channel_status = wmem_new0(wmem_file_scope(), channel_sequence_analysis_status);
1460
0
        p_channel_key = (channel_hash_key *)wmem_memdup(wmem_file_scope(), &channel_key, sizeof(channel_hash_key));
1461
1462
        /* Set mode */
1463
0
        p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
1464
1465
        /* Add entry */
1466
0
        wmem_map_insert(sequence_analysis_channel_hash, p_channel_key, p_channel_status);
1467
0
    }
1468
1469
    /* Create space for frame state_report */
1470
0
    p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1471
1472
1473
    /* Deal with according to channel mode */
1474
0
    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
0
        case RLC_AM_MODE:
1611
1612
0
            if (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) {
1613
0
                snLimit = 65536;
1614
0
            } else {
1615
0
                snLimit = 1024;
1616
0
            }
1617
1618
            /* Work out expected sequence number */
1619
0
            if (!createdChannel) {
1620
0
                expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
1621
0
            }
1622
0
            else {
1623
                /* Whatever we got is fine.. */
1624
0
                expectedSequenceNumber = sequenceNumber;
1625
0
            }
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
0
            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
0
            if (sequenceNumber != expectedSequenceNumber) {
1645
                /* Don't trash reassembly info if this looks like a close  retx... */
1646
0
                if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 50) {
1647
0
                    reassembly_destroy(p_channel_status);
1648
0
                }
1649
0
            }
1650
1651
            /* Expected? */
1652
0
            if (sequenceNumber == expectedSequenceNumber) {
1653
                /* Set report for this frame */
1654
0
                p_report_in_frame->sequenceExpectedCorrect = true;
1655
0
                p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1656
0
                p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1657
0
                p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
1658
0
                p_report_in_frame->state = SN_OK;
1659
1660
                /* Update channel status */
1661
0
                p_channel_status->previousSequenceNumber = sequenceNumber;
1662
0
                p_channel_status->previousFrameNum = pinfo->num;
1663
0
                p_channel_status->previousSegmentIncomplete = !last_includes_end;
1664
1665
1666
0
                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
0
                if (!last_includes_end &&
1684
0
                    ((number_of_segments > 1) || first_includes_start)) {
1685
1686
0
                    uint16_t lastSegmentLength = tvb_reported_length(tvb)-lastSegmentOffset;
1687
0
                    if (global_rlc_lte_reassembly) {
1688
0
                        reassembly_reset(p_channel_status);
1689
0
                        reassembly_add_segment(p_channel_status, sequenceNumber,
1690
0
                                               pinfo->num,
1691
0
                                               tvb, lastSegmentOffset, lastSegmentLength);
1692
0
                    }
1693
0
                }
1694
1695
0
                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
0
            }
1711
1712
            /* Previous subframe repeated? */
1713
0
            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
0
            else {
1731
                /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
1732
0
                int delta  = (snLimit + expectedSequenceNumber - sequenceNumber) % snLimit;
1733
1734
                /* Rx window is 512/32768, so check to see if this is a retx */
1735
0
                if (delta < (int)(snLimit>>1)) {
1736
                    /* Probably a retx due to receiving NACK */
1737
0
                    p_report_in_frame->state = SN_Retx;
1738
1739
0
                    p_report_in_frame->firstSN = sequenceNumber;
1740
                    /* Don't update anything in channel state */
1741
0
                }
1742
1743
0
                else {
1744
                    /* Ahead of expected SN. Assume frames have been missed */
1745
0
                    p_report_in_frame->state = SN_Missing;
1746
1747
0
                    p_report_in_frame->firstSN = expectedSequenceNumber;
1748
0
                    p_report_in_frame->lastSN = (snLimit + sequenceNumber-1) % snLimit;
1749
1750
                    /* Update channel state - forget about missed SNs */
1751
0
                    p_report_in_frame->sequenceExpected = expectedSequenceNumber;
1752
0
                    p_channel_status->previousSequenceNumber = sequenceNumber;
1753
0
                    p_channel_status->previousFrameNum = pinfo->num;
1754
0
                    p_channel_status->previousSegmentIncomplete = !last_includes_end;
1755
0
                }
1756
0
            }
1757
0
            break;
1758
1759
0
        default:
1760
            /* Shouldn't get here! */
1761
0
            return SN_Error;
1762
0
    }
1763
1764
    /* Associate with this frame number */
1765
0
    wmem_map_insert(sequence_analysis_report_hash,
1766
0
                        get_report_hash_key(sequenceNumber, pinfo->num, p_rlc_lte_info, true),
1767
0
                        p_report_in_frame);
1768
1769
    /* Add state report for this frame into tree */
1770
0
    addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
1771
0
                           first_includes_start, tap_info, pinfo, tree, tvb);
1772
1773
0
    return p_report_in_frame->state;
1774
0
}
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
0
{
1834
0
    channel_hash_key   channel_key;
1835
0
    channel_hash_key   *p_channel_key;
1836
0
    channel_repeated_nack_status     *p_channel_status;
1837
0
    channel_repeated_nack_report  *p_report_in_frame = NULL;
1838
1839
0
    uint16_t        noOfNACKsRepeated = 0;
1840
0
    uint16_t        repeatedNACKs[MAX_NACKs];
1841
0
    int             n, i, j;
1842
1843
    /* If find state_report_in_frame already, use that and get out */
1844
0
    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
0
    channel_key.ueId = p_rlc_lte_info->ueid;
1863
0
    channel_key.channelType = p_rlc_lte_info->channelType;
1864
0
    channel_key.channelId = p_rlc_lte_info->channelId;
1865
0
    channel_key.direction = p_rlc_lte_info->direction;
1866
0
    memset(repeatedNACKs, 0, sizeof(repeatedNACKs));
1867
1868
    /* Do the table lookup */
1869
0
    p_channel_status = (channel_repeated_nack_status*)wmem_map_lookup(repeated_nack_channel_hash, &channel_key);
1870
1871
    /* Create table entry if necessary */
1872
0
    if (p_channel_status == NULL) {
1873
1874
        /* Allocate a new key and value */
1875
0
        p_channel_key = wmem_new(wmem_file_scope(), channel_hash_key);
1876
0
        p_channel_status = wmem_new0(wmem_file_scope(), channel_repeated_nack_status);
1877
1878
        /* Copy key contents */
1879
0
        memcpy(p_channel_key, &channel_key, sizeof(channel_hash_key));
1880
1881
        /* Add entry to table */
1882
0
        wmem_map_insert(repeated_nack_channel_hash, p_channel_key, p_channel_status);
1883
0
    }
1884
1885
    /* Compare NACKs in channel status with NACKs in tap_info.
1886
       Note any that are repeated */
1887
0
    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
0
    p_channel_status->noOfNACKs = 0;
1902
0
    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
0
    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
0
    p_channel_status->frameNum = pinfo->num;
1931
0
}
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
0
{
1942
0
    channel_hash_key   channel_key;
1943
0
    channel_sequence_analysis_status  *p_channel_status;
1944
0
    sequence_analysis_report  *p_report_in_frame = NULL;
1945
0
    uint32_t snLimit;
1946
1947
    /* If find stat_report_in_frame already, use that and get out */
1948
0
    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
0
    channel_key.ueId = p_rlc_lte_info->ueid;
1969
0
    channel_key.channelType = p_rlc_lte_info->channelType;
1970
0
    channel_key.channelId = p_rlc_lte_info->channelId;
1971
0
    channel_key.direction =
1972
0
        (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
1973
1974
    /* Do the table lookup */
1975
0
    p_channel_status = (channel_sequence_analysis_status*)wmem_map_lookup(sequence_analysis_channel_hash, &channel_key);
1976
1977
    /* Create table entry if necessary */
1978
0
    if (p_channel_status == NULL) {
1979
0
        return;
1980
0
    }
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
0
    snLimit = (p_rlc_lte_info->sequenceNumberLength == AM_SN_LENGTH_16_BITS) ? 65536 : 1024;
1985
0
    if (((snLimit + (uint32_t)p_channel_status->previousSequenceNumber+1 - ack_sn) % snLimit) > (snLimit>>1)) {
1986
1987
        /* Set result */
1988
0
        p_report_in_frame = wmem_new0(wmem_file_scope(), sequence_analysis_report);
1989
0
        p_report_in_frame->state = ACK_Out_of_Window;
1990
0
        p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
1991
0
        p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
1992
0
        p_report_in_frame->firstSN = ack_sn;
1993
1994
        /* Associate with this frame number */
1995
0
        wmem_map_insert(sequence_analysis_report_hash,
1996
0
                            get_report_hash_key(0, pinfo->num,
1997
0
                                                p_rlc_lte_info, true),
1998
0
                            p_report_in_frame);
1999
2000
        /* Add state report for this frame into tree */
2001
0
        addChannelSequenceInfo(p_report_in_frame, true, p_rlc_lte_info, 0,
2002
0
                               false, tap_info, pinfo, tree, tvb);
2003
0
    }
2004
0
}
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
0
{
2313
0
    uint32_t   cpt;
2314
0
    uint8_t    sn_size, so_size;
2315
0
    uint32_t   sn_limit;
2316
0
    uint64_t   ack_sn, nack_sn;
2317
0
    uint16_t   nack_count = 0, so_end_of_pdu;
2318
0
    uint64_t   e1 = 0, e2 = 0;
2319
0
    uint64_t   so_start, so_end;
2320
0
    int        bit_offset = offset * 8;
2321
0
    proto_item *ti;
2322
2323
    /****************************************************************/
2324
    /* Part of RLC control PDU header                               */
2325
2326
    /* Control PDU Type (CPT) */
2327
0
    ti = proto_tree_add_item_ret_uint(tree, hf_rlc_lte_am_cpt, tvb, offset, 1, ENC_BIG_ENDIAN, &cpt);
2328
0
    if (cpt != 0) {
2329
        /* Protest and stop - only know about STATUS PDUs */
2330
0
        expert_add_info_format(pinfo, ti, &ei_rlc_lte_am_cpt,
2331
0
                               "RLC Control frame type %u not handled", cpt);
2332
0
        return;
2333
0
    }
2334
2335
0
    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
0
    } else {
2341
0
        sn_size = 10;
2342
0
        sn_limit = 1024;
2343
0
        so_size = 15;
2344
0
        so_end_of_pdu = 0x7fff;
2345
0
    }
2346
2347
    /* The Status PDU itself starts 4 bits into the byte */
2348
0
    bit_offset += 4;
2349
2350
    /* ACK SN */
2351
0
    proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_ack_sn, tvb,
2352
0
                                bit_offset, sn_size, &ack_sn, ENC_BIG_ENDIAN);
2353
0
    bit_offset += sn_size;
2354
0
    write_pdu_label_and_info(top_ti, status_ti, pinfo, "  ACK_SN=%-4u", (uint16_t)ack_sn);
2355
2356
0
    tap_info->ACKNo = (uint16_t)ack_sn;
2357
2358
    /* E1 */
2359
0
    proto_tree_add_bits_ret_val(tree, hf_rlc_lte_am_e1, tvb,
2360
0
                                bit_offset, 1, &e1, ENC_BIG_ENDIAN);
2361
2362
    /* Skip another bit to byte-align the next bit... */
2363
0
    bit_offset++;
2364
2365
    /* Optional, extra fields */
2366
0
    do {
2367
0
        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
0
        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
0
    } while (e1);
2452
2453
0
    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
0
    offset = (bit_offset+7) / 8;
2462
0
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
2463
0
        expert_add_info_format(pinfo, status_ti, &ei_rlc_lte_bytes_after_status_pdu_complete,
2464
0
                               "%cL %u bytes remaining after Status PDU complete",
2465
0
                               (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? 'U' : 'D',
2466
0
                               tvb_reported_length_remaining(tvb, offset));
2467
0
    }
2468
2469
    /* Set selected length of control tree */
2470
0
    proto_item_set_len(status_ti, offset);
2471
2472
    /* Repeated NACK analysis & check ACK-SN is in range */
2473
0
    if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2474
0
         (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
0
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2477
2478
0
        if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
2479
0
            checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2480
0
            checkChannelACKWindow((uint16_t)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
2481
0
        }
2482
0
     }
2483
0
}
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
0
{
2495
0
    bool is_data;
2496
0
    uint32_t is_resegmented;
2497
0
    uint32_t polling;
2498
0
    uint32_t fixed_extension;
2499
0
    uint32_t framing_info;
2500
0
    bool first_includes_start;
2501
0
    bool last_includes_end;
2502
0
    proto_item *am_ti;
2503
0
    proto_tree *am_header_tree;
2504
0
    proto_item *am_header_ti;
2505
0
    int    start_offset = offset;
2506
0
    uint32_t   sn;
2507
0
    bool is_truncated = false;
2508
0
    proto_item *truncated_ti;
2509
0
    rlc_channel_reassembly_info *reassembly_info = NULL;
2510
0
    sequence_analysis_state seq_anal_state = SN_OK;
2511
0
    uint32_t id;
2512
0
    wmem_tree_key_t key[3];
2513
0
    rlc_ue_parameters *params;
2514
2515
    /* Hidden AM root */
2516
0
    am_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am,
2517
0
                                         tvb, offset, 0, "", "AM");
2518
0
    proto_item_set_hidden(am_ti);
2519
2520
    /* Add AM header subtree */
2521
0
    am_header_ti = proto_tree_add_string_format(tree, hf_rlc_lte_am_header,
2522
0
                                                tvb, offset, 0,
2523
0
                                                "", "AM Header ");
2524
0
    am_header_tree = proto_item_add_subtree(am_header_ti,
2525
0
                                            ett_rlc_lte_am_header);
2526
2527
    /* First bit is Data/Control flag           */
2528
0
    proto_tree_add_item_ret_boolean(am_header_tree, hf_rlc_lte_am_data_control, tvb, offset, 1, ENC_BIG_ENDIAN, &is_data);
2529
0
    tap_info->isControlPDU = !is_data;
2530
2531
0
    if (!is_data) {
2532
        /**********************/
2533
        /* Status PDU         */
2534
0
        write_pdu_label_and_info_literal(top_ti, NULL, pinfo, " [CONTROL]");
2535
2536
        /* Control PDUs are a completely separate format  */
2537
0
        dissect_rlc_lte_am_status_pdu(tvb, pinfo, am_header_tree, am_header_ti,
2538
0
                                      offset, top_ti,
2539
0
                                      p_rlc_lte_info, tap_info);
2540
0
        return;
2541
0
    }
2542
2543
    /******************************/
2544
    /* Data PDU fixed header      */
2545
2546
    /* Re-segmentation Flag (RF) field */
2547
0
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_rf, tvb, offset, 1,
2548
0
                                 ENC_BIG_ENDIAN, &is_resegmented);
2549
0
    tap_info->isResegmented = is_resegmented;
2550
2551
0
    write_pdu_label_and_info_literal(top_ti, NULL, pinfo,
2552
0
                                     (is_resegmented) ? " [DATA-SEGMENT]" : " [DATA]");
2553
2554
    /* Polling bit */
2555
0
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_p, tvb, offset, 1,
2556
0
                                 ENC_BIG_ENDIAN, &polling);
2557
2558
0
    write_pdu_label_and_info_literal(top_ti, NULL, pinfo, (polling) ? " (P) " : "     ");
2559
0
    if (polling) {
2560
0
        proto_item_append_text(am_header_ti, " (P) ");
2561
0
    }
2562
2563
    /* Framing Info */
2564
0
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fi, tvb, offset, 1,
2565
0
                                 ENC_BIG_ENDIAN, &framing_info);
2566
2567
    /* Extension bit */
2568
0
    proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_e, tvb, offset, 1,
2569
0
                                 ENC_BIG_ENDIAN, &fixed_extension);
2570
2571
    /* Sequence Number */
2572
0
    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
0
    } else {
2592
0
        proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_fixed_sn, tvb, offset, 2, ENC_BIG_ENDIAN, &sn);
2593
0
        offset += 2;
2594
0
    }
2595
0
    tap_info->sequenceNumberGiven = true;
2596
0
    tap_info->sequenceNumber = sn;
2597
2598
0
    write_pdu_label_and_info(top_ti, am_header_ti, pinfo, "sn=%-4u", sn);
2599
2600
    /***************************************/
2601
    /* Dissect extra segment header fields */
2602
0
    if (is_resegmented) {
2603
0
        uint32_t segmentOffset;
2604
2605
0
        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
0
        } else {
2609
            /* Last Segment Field (LSF) */
2610
0
            proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_lsf, tvb, offset, 1, ENC_BIG_ENDIAN);
2611
2612
            /* SO */
2613
0
            proto_tree_add_item_ret_uint(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, ENC_BIG_ENDIAN, &segmentOffset);
2614
0
        }
2615
0
        write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
2616
0
        offset += 2;
2617
0
    }
2618
2619
    /*************************************/
2620
    /* AM header extension               */
2621
0
    if (fixed_extension) {
2622
0
        if (!PINFO_FD_VISITED(pinfo)) {
2623
0
            id = (p_rlc_lte_info->channelId << 16) | p_rlc_lte_info->ueid;
2624
0
            key[0].length = 1;
2625
0
            key[0].key = &id;
2626
0
            key[1].length = 1;
2627
0
            key[1].key = &pinfo->num;
2628
0
            key[2].length = 0;
2629
0
            key[2].key = NULL;
2630
0
            params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
2631
0
            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
0
        }
2636
0
        offset = dissect_rlc_lte_extension_header(tvb, pinfo, am_header_tree, offset, p_rlc_lte_info);
2637
0
    }
2638
2639
    /* Header is now complete */
2640
0
    proto_item_set_len(am_header_ti, offset-start_offset);
2641
2642
    /* Show number of extensions in header root */
2643
0
    if (s_number_of_extensions > 0) {
2644
0
        proto_item_append_text(am_header_ti, " (%u extensions)", s_number_of_extensions);
2645
0
    }
2646
2647
    /* Extract these 2 flags from framing_info */
2648
0
    first_includes_start = (framing_info & 0x02) == 0;
2649
0
    last_includes_end =    (framing_info & 0x01) == 0;
2650
2651
    /* There might not be any data, if only headers (plus control data) were logged */
2652
0
    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
0
    if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
2679
0
         (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
0
         (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) == NULL))) {
2682
2683
0
        uint16_t firstSegmentLength;
2684
0
        uint16_t lastSegmentOffset = offset;
2685
0
        if (s_number_of_extensions >= 1) {
2686
0
            int n;
2687
0
            for (n=0; n < s_number_of_extensions; n++) {
2688
0
                lastSegmentOffset += s_lengths[n];
2689
0
            }
2690
2691
0
            firstSegmentLength = s_lengths[0];
2692
0
        }
2693
0
        else {
2694
0
            firstSegmentLength = tvb_reported_length_remaining(tvb, offset);
2695
0
        }
2696
2697
0
        seq_anal_state = checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, false,
2698
0
                                                  s_number_of_extensions+1,
2699
0
                                                  offset, firstSegmentLength,
2700
0
                                                  lastSegmentOffset,
2701
0
                                                  (uint16_t)sn,
2702
0
                                                  first_includes_start, last_includes_end,
2703
0
                                                  is_resegmented, tap_info, tree);
2704
0
    }
2705
2706
0
    if (is_truncated) {
2707
0
        return;
2708
0
    }
2709
2710
    /*************************************/
2711
    /* Data                              */
2712
2713
0
    if (!first_includes_start) {
2714
0
        reassembly_info = (rlc_channel_reassembly_info *)wmem_map_lookup(reassembly_report_hash,
2715
0
                                                                             get_report_hash_key((uint16_t)sn,
2716
0
                                                                                                 pinfo->num,
2717
0
                                                                                                 p_rlc_lte_info,
2718
0
                                                                                                 false));
2719
0
    }
2720
2721
0
    if (s_number_of_extensions > 0) {
2722
        /* Show each data segment separately */
2723
0
        int n;
2724
0
        for (n=0; n < s_number_of_extensions; n++) {
2725
0
            show_PDU_in_tree(pinfo, tree, tvb, offset, s_lengths[n], p_rlc_lte_info,
2726
0
                             (n==0) ? first_includes_start : true,
2727
0
                             (n==0) ? reassembly_info : NULL,
2728
0
                             seq_anal_state);
2729
0
            show_PDU_in_info(pinfo, top_ti, s_lengths[n],
2730
0
                             (n==0) ? first_includes_start : true,
2731
0
                             true);
2732
            /* Make sure we don't lose the summary of this SDU */
2733
0
            col_append_str(pinfo->cinfo, COL_INFO, "  | ");
2734
0
            col_set_fence(pinfo->cinfo, COL_INFO);
2735
2736
0
            tvb_ensure_bytes_exist(tvb, offset, s_lengths[n]);
2737
0
            offset += s_lengths[n];
2738
0
        }
2739
0
    }
2740
2741
    /* Final data element */
2742
0
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
2743
0
        show_PDU_in_tree(pinfo, tree, tvb, offset, tvb_reported_length_remaining(tvb, offset), p_rlc_lte_info,
2744
0
                         ((s_number_of_extensions == 0) ? first_includes_start : true) && last_includes_end,
2745
0
                         (s_number_of_extensions == 0) ? reassembly_info : NULL,
2746
0
                         seq_anal_state);
2747
0
        show_PDU_in_info(pinfo, top_ti, (uint16_t)tvb_reported_length_remaining(tvb, offset),
2748
0
                         (s_number_of_extensions == 0) ? first_includes_start : true,
2749
0
                         last_includes_end);
2750
0
    }
2751
0
    else {
2752
        /* Report that expected data was missing (unless we know it might happen) */
2753
0
        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
0
    }
2762
0
}
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
0
{
2898
0
    dissect_rlc_lte_common(tvb, pinfo, tree, false);
2899
0
    return tvb_captured_length(tvb);
2900
0
}
2901
2902
static void dissect_rlc_lte_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool is_udp_framing)
2903
0
{
2904
0
    proto_tree             *rlc_lte_tree;
2905
0
    proto_tree             *context_tree;
2906
0
    proto_item             *top_ti;
2907
0
    proto_item             *context_ti;
2908
0
    proto_item             *ti;
2909
0
    proto_item             *mode_ti;
2910
0
    int                    offset = 0;
2911
0
    struct rlc_lte_info    *p_rlc_lte_info;
2912
2913
    /* Allocate and Zero tap struct */
2914
0
    rlc_3gpp_tap_info *tap_info = wmem_new0(pinfo->pool, rlc_3gpp_tap_info);
2915
0
    tap_info->rat = RLC_RAT_LTE;
2916
2917
    /* Set protocol name */
2918
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RLC-LTE");
2919
2920
    /* Create protocol tree. */
2921
0
    top_ti = proto_tree_add_item(tree, proto_rlc_lte, tvb, offset, -1, ENC_NA);
2922
0
    rlc_lte_tree = proto_item_add_subtree(top_ti, ett_rlc_lte);
2923
2924
2925
    /* Look for packet info! */
2926
0
    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
0
    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
0
    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
0
    context_ti = proto_tree_add_string_format(rlc_lte_tree, hf_rlc_lte_context,
2944
0
                                              tvb, offset, 0, "", "Context");
2945
0
    context_tree = proto_item_add_subtree(context_ti, ett_rlc_lte_context);
2946
0
    proto_item_set_generated(context_ti);
2947
2948
0
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_direction,
2949
0
                             tvb, 0, 0, p_rlc_lte_info->direction);
2950
0
    proto_item_set_generated(ti);
2951
2952
0
    mode_ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_mode,
2953
0
                                  tvb, 0, 0, p_rlc_lte_info->rlcMode);
2954
0
    proto_item_set_generated(mode_ti);
2955
2956
0
    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
0
    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
0
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_type,
2969
0
                             tvb, 0, 0, p_rlc_lte_info->channelType);
2970
0
    proto_item_set_generated(ti);
2971
2972
0
    if ((p_rlc_lte_info->channelType == CHANNEL_TYPE_SRB) ||
2973
0
        (p_rlc_lte_info->channelType == CHANNEL_TYPE_DRB) ||
2974
0
        (p_rlc_lte_info->channelType == CHANNEL_TYPE_MTCH)) {
2975
0
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_channel_id,
2976
0
                                 tvb, 0, 0, p_rlc_lte_info->channelId);
2977
0
        proto_item_set_generated(ti);
2978
0
    }
2979
2980
0
    ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_pdu_length,
2981
0
                             tvb, 0, 0, p_rlc_lte_info->pduLength);
2982
0
    proto_item_set_generated(ti);
2983
2984
0
    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
0
    if (p_rlc_lte_info->rlcMode == RLC_AM_MODE) {
2991
0
        if (!p_rlc_lte_info->sequenceNumberLength) {
2992
0
            p_rlc_lte_info->sequenceNumberLength = 10;
2993
0
        }
2994
0
        ti = proto_tree_add_uint(context_tree, hf_rlc_lte_context_am_sn_length,
2995
0
                                 tvb, 0, 0, p_rlc_lte_info->sequenceNumberLength);
2996
0
        proto_item_set_generated(ti);
2997
0
    }
2998
2999
    /* Append highlights to top-level item */
3000
0
    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
0
    write_pdu_label_and_info(top_ti, NULL, pinfo,
3007
0
                             " [%s] [%s] ",
3008
0
                             (p_rlc_lte_info->direction == 0) ? "UL" : "DL",
3009
0
                             val_to_str_const(p_rlc_lte_info->rlcMode, rlc_mode_short_vals, "Unknown"));
3010
3011
0
    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
0
    else {
3016
0
        write_pdu_label_and_info(top_ti, NULL, pinfo, "%s:%-2u",
3017
0
                                 val_to_str_const(p_rlc_lte_info->channelType, rlc_channel_type_vals, "Unknown"),
3018
0
                                 p_rlc_lte_info->channelId);
3019
0
    }
3020
3021
    /* Set context-info parts of tap struct */
3022
0
    tap_info->rlcMode = p_rlc_lte_info->rlcMode;
3023
0
    tap_info->direction = p_rlc_lte_info->direction;
3024
0
    tap_info->priority = p_rlc_lte_info->priority;
3025
0
    tap_info->ueid = p_rlc_lte_info->ueid;
3026
0
    tap_info->channelType = p_rlc_lte_info->channelType;
3027
0
    tap_info->channelId = p_rlc_lte_info->channelId;
3028
0
    tap_info->pduLength = p_rlc_lte_info->pduLength;
3029
0
    tap_info->sequenceNumberLength = p_rlc_lte_info->sequenceNumberLength;
3030
0
    tap_info->loggedInMACFrame = (p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0) != NULL);
3031
3032
0
    tap_info->rlc_time = pinfo->abs_ts;
3033
3034
    /* Reset this count */
3035
0
    s_number_of_extensions = 0;
3036
3037
    /* Dissect the RLC PDU itself. Format depends upon mode... */
3038
0
    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
0
        case RLC_AM_MODE:
3050
0
            dissect_rlc_lte_am(tvb, pinfo, rlc_lte_tree, offset, p_rlc_lte_info, top_ti,
3051
0
                               tap_info);
3052
0
            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
0
    }
3067
3068
    /* Queue tap info */
3069
0
    tap_queue_packet(rlc_lte_tap, pinfo, tap_info);
3070
0
}
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
0
{
3078
0
    wmem_tree_key_t key[3];
3079
0
    uint32_t id;
3080
0
    rlc_ue_parameters *params;
3081
3082
0
    if (PINFO_FD_VISITED(pinfo)) {
3083
0
        return;
3084
0
    }
3085
3086
0
    id = (drbid << 16) | ueid;
3087
0
    key[0].length = 1;
3088
0
    key[0].key = &id;
3089
0
    key[1].length = 1;
3090
0
    key[1].key = &pinfo->num;
3091
0
    key[2].length = 0;
3092
0
    key[2].key = NULL;
3093
3094
0
    params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3095
0
    if (params && (params->id != id)) {
3096
0
        params = NULL;
3097
0
    }
3098
0
    if (params == NULL) {
3099
0
        params = (rlc_ue_parameters *)wmem_new(wmem_file_scope(), rlc_ue_parameters);
3100
0
        params->id = id;
3101
0
        params->ext_li_field = NO_EXT_LI;
3102
0
        wmem_tree_insert32_array(ue_parameters_tree, key, (void *)params);
3103
0
    }
3104
0
    params->pdcp_sn_bits = userplane_seqnum_length;
3105
0
}
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
0
{
3111
0
    wmem_tree_key_t key[3];
3112
0
    uint32_t id;
3113
0
    rlc_ue_parameters *params;
3114
3115
0
    if (PINFO_FD_VISITED(pinfo)) {
3116
0
        return;
3117
0
    }
3118
3119
0
    id = (drbid << 16) | ueid;
3120
0
    key[0].length = 1;
3121
0
    key[0].key = &id;
3122
0
    key[1].length = 1;
3123
0
    key[1].key = &pinfo->num;
3124
0
    key[2].length = 0;
3125
0
    key[2].key = NULL;
3126
3127
0
    params = (rlc_ue_parameters *)wmem_tree_lookup32_array_le(ue_parameters_tree, key);
3128
0
    if (params && (params->id != id)) {
3129
0
        params = NULL;
3130
0
    }
3131
0
    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
0
    params->ext_li_field = ul_ext_li_field ? UL_EXT_LI : NO_EXT_LI;
3138
0
    params->ext_li_field |= dl_ext_li_field ? DL_EXT_LI : NO_EXT_LI;
3139
0
}
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
14
{
3196
14
    static hf_register_info hf[] =
3197
14
    {
3198
        /**********************************/
3199
        /* Items for decoding context     */
3200
14
        { &hf_rlc_lte_context,
3201
14
            { "Context",
3202
14
              "rlc-lte.context", FT_STRING, BASE_NONE, NULL, 0x0,
3203
14
              NULL, HFILL
3204
14
            }
3205
14
        },
3206
14
        { &hf_rlc_lte_context_mode,
3207
14
            { "RLC Mode",
3208
14
              "rlc-lte.mode", FT_UINT8, BASE_DEC, VALS(rlc_mode_vals), 0x0,
3209
14
              NULL, HFILL
3210
14
            }
3211
14
        },
3212
14
        { &hf_rlc_lte_context_direction,
3213
14
            { "Direction",
3214
14
              "rlc-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
3215
14
              "Direction of message", HFILL
3216
14
            }
3217
14
        },
3218
14
        { &hf_rlc_lte_context_priority,
3219
14
            { "Priority",
3220
14
              "rlc-lte.priority", FT_UINT8, BASE_DEC, 0, 0x0,
3221
14
              NULL, HFILL
3222
14
            }
3223
14
        },
3224
14
        { &hf_rlc_lte_context_ueid,
3225
14
            { "UEId",
3226
14
              "rlc-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
3227
14
              "User Equipment Identifier associated with message", HFILL
3228
14
            }
3229
14
        },
3230
14
        { &hf_rlc_lte_context_channel_type,
3231
14
            { "Channel Type",
3232
14
              "rlc-lte.channel-type", FT_UINT16, BASE_DEC, VALS(rlc_channel_type_vals), 0x0,
3233
14
              "Channel Type associated with message", HFILL
3234
14
            }
3235
14
        },
3236
14
        { &hf_rlc_lte_context_channel_id,
3237
14
            { "Channel ID",
3238
14
              "rlc-lte.channel-id", FT_UINT16, BASE_DEC, 0, 0x0,
3239
14
              "Channel ID associated with message", HFILL
3240
14
            }
3241
14
        },
3242
14
        { &hf_rlc_lte_context_pdu_length,
3243
14
            { "PDU Length",
3244
14
              "rlc-lte.pdu-length", FT_UINT16, BASE_DEC, 0, 0x0,
3245
14
              "Length of PDU (in bytes)", HFILL
3246
14
            }
3247
14
        },
3248
14
        { &hf_rlc_lte_context_um_sn_length,
3249
14
            { "UM Sequence number length",
3250
14
              "rlc-lte.um-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3251
14
              "Length of UM sequence number in bits", HFILL
3252
14
            }
3253
14
        },
3254
14
        { &hf_rlc_lte_context_am_sn_length,
3255
14
            { "AM Sequence number length",
3256
14
              "rlc-lte.am-seqnum-length", FT_UINT8, BASE_DEC, 0, 0x0,
3257
14
              "Length of AM sequence number in bits", HFILL
3258
14
            }
3259
14
        },
3260
3261
        /* Transparent mode fields */
3262
14
        { &hf_rlc_lte_tm,
3263
14
            { "TM",
3264
14
              "rlc-lte.tm", FT_STRING, BASE_NONE, NULL, 0x0,
3265
14
              "Transparent Mode", HFILL
3266
14
            }
3267
14
        },
3268
14
        { &hf_rlc_lte_tm_data,
3269
14
            { "TM Data",
3270
14
              "rlc-lte.tm.data", FT_BYTES, BASE_NONE, 0, 0x0,
3271
14
              "Transparent Mode Data", HFILL
3272
14
            }
3273
14
        },
3274
3275
        /* Unacknowledged mode fields */
3276
14
        { &hf_rlc_lte_um,
3277
14
            { "UM",
3278
14
              "rlc-lte.um", FT_STRING, BASE_NONE, NULL, 0x0,
3279
14
              "Unacknowledged Mode", HFILL
3280
14
            }
3281
14
        },
3282
14
        { &hf_rlc_lte_um_header,
3283
14
            { "UM Header",
3284
14
              "rlc-lte.um.header", FT_STRING, BASE_NONE, NULL, 0x0,
3285
14
              "Unacknowledged Mode Header", HFILL
3286
14
            }
3287
14
        },
3288
14
        { &hf_rlc_lte_um_fi,
3289
14
            { "Framing Info",
3290
14
              "rlc-lte.um.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x0,
3291
14
              NULL, HFILL
3292
14
            }
3293
14
        },
3294
14
        { &hf_rlc_lte_um_fixed_e,
3295
14
            { "Extension",
3296
14
              "rlc-lte.um.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x0,
3297
14
              "Extension in fixed part of UM header", HFILL
3298
14
            }
3299
14
        },
3300
14
        { &hf_rlc_lte_um_sn,
3301
14
            { "Sequence number",
3302
14
              "rlc-lte.um.sn", FT_UINT8, BASE_DEC, 0, 0x0,
3303
14
              "Unacknowledged Mode Sequence Number", HFILL
3304
14
            }
3305
14
        },
3306
14
        { &hf_rlc_lte_um_fixed_reserved,
3307
14
            { "Reserved",
3308
14
              "rlc-lte.um.reserved", FT_UINT8, BASE_DEC, 0, 0xe0,
3309
14
              "Unacknowledged Mode Fixed header reserved bits", HFILL
3310
14
            }
3311
14
        },
3312
14
        { &hf_rlc_lte_um_data,
3313
14
            { "UM Data",
3314
14
              "rlc-lte.um.data", FT_BYTES, BASE_NONE, 0, 0x0,
3315
14
              "Unacknowledged Mode Data", HFILL
3316
14
            }
3317
14
        },
3318
14
        { &hf_rlc_lte_extension_part,
3319
14
            { "Extension Part",
3320
14
              "rlc-lte.extension-part", FT_STRING, BASE_NONE, 0, 0x0,
3321
14
              NULL, HFILL
3322
14
            }
3323
14
        },
3324
14
        { &hf_rlc_lte_extension_e,
3325
14
            { "Extension",
3326
14
              "rlc-lte.extension.e", FT_UINT8, BASE_HEX, VALS(extension_extension_vals), 0x0,
3327
14
              "Extension in extended part of the header", HFILL
3328
14
            }
3329
14
        },
3330
14
        { &hf_rlc_lte_extension_li,
3331
14
            { "Length Indicator",
3332
14
              "rlc-lte.extension.li", FT_UINT16, BASE_DEC, 0, 0x0,
3333
14
              NULL, HFILL
3334
14
            }
3335
14
        },
3336
14
        { &hf_rlc_lte_extension_padding,
3337
14
            { "Padding",
3338
14
              "rlc-lte.extension.padding", FT_UINT8, BASE_HEX, 0, 0x0f,
3339
14
              "Extension header padding", HFILL
3340
14
            }
3341
14
        },
3342
3343
        /* Acknowledged mode fields */
3344
14
        { &hf_rlc_lte_am,
3345
14
            { "AM",
3346
14
              "rlc-lte.am", FT_STRING, BASE_NONE, NULL, 0x0,
3347
14
              "Acknowledged Mode", HFILL
3348
14
            }
3349
14
        },
3350
14
        { &hf_rlc_lte_am_header,
3351
14
            { "AM Header",
3352
14
              "rlc-lte.am.header", FT_STRING, BASE_NONE, NULL, 0x0,
3353
14
              "Acknowledged Mode Header", HFILL
3354
14
            }
3355
14
        },
3356
14
        { &hf_rlc_lte_am_data_control,
3357
14
            { "Frame type",
3358
14
              "rlc-lte.am.frame-type", FT_BOOLEAN, 8, TFS(&tfs_data_pdu_control_pdu), 0x80,
3359
14
              "AM Frame Type (Control or Data)", HFILL
3360
14
            }
3361
14
        },
3362
14
        { &hf_rlc_lte_am_rf,
3363
14
            { "Re-segmentation Flag",
3364
14
              "rlc-lte.am.rf", FT_UINT8, BASE_HEX, VALS(resegmentation_flag_vals), 0x40,
3365
14
              "AM Re-segmentation Flag", HFILL
3366
14
            }
3367
14
        },
3368
14
        { &hf_rlc_lte_am_p,
3369
14
            { "Polling Bit",
3370
14
              "rlc-lte.am.p", FT_UINT8, BASE_HEX, VALS(polling_bit_vals), 0x20,
3371
14
              NULL, HFILL
3372
14
            }
3373
14
        },
3374
14
        { &hf_rlc_lte_am_fi,
3375
14
            { "Framing Info",
3376
14
              "rlc-lte.am.fi", FT_UINT8, BASE_HEX, VALS(framing_info_vals), 0x18,
3377
14
              "AM Framing Info", HFILL
3378
14
            }
3379
14
        },
3380
14
        { &hf_rlc_lte_am_fixed_e,
3381
14
            { "Extension",
3382
14
              "rlc-lte.am.fixed.e", FT_UINT8, BASE_HEX, VALS(fixed_extension_vals), 0x04,
3383
14
              "Fixed Extension Bit", HFILL
3384
14
            }
3385
14
        },
3386
14
        { &hf_rlc_lte_am_fixed_sn,
3387
14
            { "Sequence Number",
3388
14
              "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x03ff,
3389
14
              "AM Fixed Sequence Number", HFILL
3390
14
            }
3391
14
        },
3392
14
        { &hf_rlc_lte_am_fixed_reserved,
3393
14
            { "Reserved",
3394
14
              "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x03,
3395
14
              "Acknowledged Mode Fixed header reserved bits", HFILL
3396
14
            }
3397
14
        },
3398
14
        { &hf_rlc_lte_am_segment_lsf16,
3399
14
            { "Last Segment Flag",
3400
14
              "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x02,
3401
14
              NULL, HFILL
3402
14
            }
3403
14
        },
3404
14
        { &hf_rlc_lte_am_fixed_reserved2,
3405
14
            { "Reserved",
3406
14
              "rlc-lte.am.reserved", FT_UINT8, BASE_DEC, 0, 0x01,
3407
14
              "Acknowledged Mode Fixed header reserved bit", HFILL
3408
14
            }
3409
14
        },
3410
14
        { &hf_rlc_lte_am_fixed_sn16,
3411
14
            { "Sequence Number",
3412
14
              "rlc-lte.am.fixed.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3413
14
              "AM Fixed Sequence Number", HFILL
3414
14
            }
3415
14
        },
3416
14
        { &hf_rlc_lte_am_segment_lsf,
3417
14
            { "Last Segment Flag",
3418
14
              "rlc-lte.am.segment.lsf", FT_UINT8, BASE_HEX, VALS(lsf_vals), 0x80,
3419
14
              NULL, HFILL
3420
14
            }
3421
14
        },
3422
14
        { &hf_rlc_lte_am_segment_so,
3423
14
            { "Segment Offset",
3424
14
              "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x7fff,
3425
14
              NULL, HFILL
3426
14
            }
3427
14
        },
3428
14
        { &hf_rlc_lte_am_segment_so16,
3429
14
            { "Segment Offset",
3430
14
              "rlc-lte.am.segment.offset", FT_UINT16, BASE_DEC, 0, 0x0,
3431
14
              NULL, HFILL
3432
14
            }
3433
14
        },
3434
14
        { &hf_rlc_lte_am_data,
3435
14
            { "AM Data",
3436
14
              "rlc-lte.am.data", FT_BYTES, BASE_NONE, 0, 0x0,
3437
14
              "Acknowledged Mode Data", HFILL
3438
14
            }
3439
14
        },
3440
3441
14
        { &hf_rlc_lte_am_cpt,
3442
14
            { "Control PDU Type",
3443
14
              "rlc-lte.am.cpt", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
3444
14
              "AM Control PDU Type", HFILL
3445
14
            }
3446
14
        },
3447
14
        { &hf_rlc_lte_am_ack_sn,
3448
14
            { "ACK Sequence Number",
3449
14
              "rlc-lte.am.ack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3450
14
              "Sequence Number we expect to receive next", HFILL
3451
14
            }
3452
14
        },
3453
14
        { &hf_rlc_lte_am_e1,
3454
14
            { "Extension bit 1",
3455
14
              "rlc-lte.am.e1", FT_UINT8, BASE_HEX, VALS(am_e1_vals), 0x0,
3456
14
              NULL, HFILL
3457
14
            }
3458
14
        },
3459
14
        { &hf_rlc_lte_am_e2,
3460
14
            { "Extension bit 2",
3461
14
              "rlc-lte.am.e2", FT_UINT8, BASE_HEX, VALS(am_e2_vals), 0x0,
3462
14
              NULL, HFILL
3463
14
            }
3464
14
        },
3465
14
        { &hf_rlc_lte_am_nacks,
3466
14
            { "Number of NACKs",
3467
14
              "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
3468
14
              "Number of NACKs in this status PDU", HFILL
3469
14
            }
3470
14
        },
3471
14
        { &hf_rlc_lte_am_nack_sn,
3472
14
            { "NACK Sequence Number",
3473
14
              "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3474
14
              "Negative Acknowledgement Sequence Number", HFILL
3475
14
            }
3476
14
        },
3477
14
        { &hf_rlc_lte_am_so_start,
3478
14
            { "SO Start",
3479
14
              "rlc-lte.am.so-start", FT_UINT16, BASE_DEC, 0, 0x0,
3480
14
              "Segment Offset Start byte index", HFILL
3481
14
            }
3482
14
        },
3483
14
        { &hf_rlc_lte_am_so_end,
3484
14
            { "SO End",
3485
14
              "rlc-lte.am.so-end", FT_UINT16, BASE_DEC, 0, 0x0,
3486
14
              "Segment Offset End byte index", HFILL
3487
14
            }
3488
14
        },
3489
3490
14
        { &hf_rlc_lte_predefined_pdu,
3491
14
            { "Predefined data",
3492
14
              "rlc-lte.predefined-data", FT_BYTES, BASE_NONE, 0, 0x0,
3493
14
              "Predefined test data", HFILL
3494
14
            }
3495
14
        },
3496
3497
        /* Sequence analysis fields */
3498
14
        { &hf_rlc_lte_sequence_analysis,
3499
14
            { "Sequence Analysis",
3500
14
              "rlc-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
3501
14
              NULL, HFILL
3502
14
            }
3503
14
        },
3504
14
        { &hf_rlc_lte_sequence_analysis_ok,
3505
14
            { "OK",
3506
14
              "rlc-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3507
14
              NULL, HFILL
3508
14
            }
3509
14
        },
3510
14
        { &hf_rlc_lte_sequence_analysis_previous_frame,
3511
14
            { "Previous frame for channel",
3512
14
              "rlc-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3513
14
              NULL, HFILL
3514
14
            }
3515
14
        },
3516
14
        { &hf_rlc_lte_sequence_analysis_next_frame,
3517
14
            { "Next frame for channel",
3518
14
              "rlc-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
3519
14
              NULL, HFILL
3520
14
            }
3521
14
        },
3522
14
        { &hf_rlc_lte_sequence_analysis_expected_sn,
3523
14
            { "Expected SN",
3524
14
              "rlc-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
3525
14
              NULL, HFILL
3526
14
            }
3527
14
        },
3528
14
        { &hf_rlc_lte_sequence_analysis_framing_info_correct,
3529
14
            { "Frame info continued correctly",
3530
14
              "rlc-lte.sequence-analysis.framing-info-correct", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3531
14
              NULL, HFILL
3532
14
            }
3533
14
        },
3534
14
        { &hf_rlc_lte_sequence_analysis_mac_retx,
3535
14
            { "Frame retransmitted by MAC",
3536
14
              "rlc-lte.sequence-analysis.mac-retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3537
14
              NULL, HFILL
3538
14
            }
3539
14
        },
3540
14
        { &hf_rlc_lte_sequence_analysis_retx,
3541
14
            { "Retransmitted frame",
3542
14
              "rlc-lte.sequence-analysis.retx", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3543
14
              NULL, HFILL
3544
14
            }
3545
14
        },
3546
14
        { &hf_rlc_lte_sequence_analysis_skipped,
3547
14
            { "Skipped frames",
3548
14
              "rlc-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3549
14
              NULL, HFILL
3550
14
            }
3551
14
        },
3552
14
        { &hf_rlc_lte_sequence_analysis_repeated,
3553
14
            { "Repeated frame",
3554
14
              "rlc-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3555
14
              NULL, HFILL
3556
14
            }
3557
14
        },
3558
14
        { &hf_rlc_lte_sequence_analysis_repeated_nack,
3559
14
            { "Repeated NACK",
3560
14
              "rlc-lte.sequence-analysis.repeated-nack", FT_UINT16, BASE_DEC, 0, 0x0,
3561
14
              NULL, HFILL
3562
14
            }
3563
14
        },
3564
14
        { &hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
3565
14
            { "Frame with previous status PDU",
3566
14
              "rlc-lte.sequence-analysis.repeated-nack.original-frame",  FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_DUP_ACK), 0x0,
3567
14
              NULL, HFILL
3568
14
            }
3569
14
        },
3570
3571
14
        { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
3572
14
            { "Out of range ACK",
3573
14
              "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
3574
14
              NULL, HFILL
3575
14
            }
3576
14
        },
3577
14
        { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
3578
14
            { "Frame with most recent SN",
3579
14
              "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame",  FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3580
14
              NULL, HFILL
3581
14
            }
3582
14
        },
3583
3584
        /* Reassembly fields */
3585
14
        { &hf_rlc_lte_reassembly_source,
3586
14
            { "Reassembly Source",
3587
14
              "rlc-lte.reassembly-info", FT_STRING, BASE_NONE, 0, 0x0,
3588
14
              NULL, HFILL
3589
14
            }
3590
14
        },
3591
14
        { &hf_rlc_lte_reassembly_source_number_of_segments,
3592
14
            { "Number of segments",
3593
14
              "rlc-lte.reassembly-info.number-of-segments", FT_UINT16, BASE_DEC, 0, 0x0,
3594
14
              NULL, HFILL
3595
14
            }
3596
14
        },
3597
14
        { &hf_rlc_lte_reassembly_source_total_length,
3598
14
            { "Total length",
3599
14
              "rlc-lte.reassembly-info.total-length", FT_UINT16, BASE_DEC, 0, 0x0,
3600
14
              NULL, HFILL
3601
14
            }
3602
14
        },
3603
14
        { &hf_rlc_lte_reassembly_source_segment,
3604
14
            { "Segment",
3605
14
              "rlc-lte.reassembly-info.segment", FT_NONE, BASE_NONE, 0, 0x0,
3606
14
              NULL, HFILL
3607
14
            }
3608
14
        },
3609
14
        { &hf_rlc_lte_reassembly_source_segment_sn,
3610
14
            { "SN",
3611
14
              "rlc-lte.reassembly-info.segment.sn", FT_UINT16, BASE_DEC, 0, 0x0,
3612
14
              NULL, HFILL
3613
14
            }
3614
14
        },
3615
14
        { &hf_rlc_lte_reassembly_source_segment_framenum,
3616
14
            { "Frame",
3617
14
              "rlc-lte.reassembly-info.segment.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
3618
14
              NULL, HFILL
3619
14
            }
3620
14
        },
3621
14
        { &hf_rlc_lte_reassembly_source_segment_length,
3622
14
            { "Length",
3623
14
              "rlc-lte.reassembly-info.segment.length", FT_UINT32, BASE_DEC, 0, 0x0,
3624
14
              NULL, HFILL
3625
14
            }
3626
14
        },
3627
3628
14
        { &hf_rlc_lte_header_only,
3629
14
            { "RLC PDU Header only",
3630
14
              "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,
3631
14
              NULL, HFILL
3632
14
            }
3633
14
        },
3634
14
    };
3635
3636
14
    static int *ett[] =
3637
14
    {
3638
14
        &ett_rlc_lte,
3639
14
        &ett_rlc_lte_context,
3640
14
        &ett_rlc_lte_um_header,
3641
14
        &ett_rlc_lte_am_header,
3642
14
        &ett_rlc_lte_extension_part,
3643
14
        &ett_rlc_lte_sequence_analysis,
3644
14
        &ett_rlc_lte_reassembly_source,
3645
14
        &ett_rlc_lte_reassembly_source_segment
3646
14
    };
3647
3648
14
    static ei_register_info ei[] = {
3649
14
        { &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
14
        { &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
14
        { &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
14
        { &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
14
        { &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
14
        { &ei_rlc_lte_am_sn_missing, { "rlc-lte.sequence-analysis.am-sn.missing", PI_SEQUENCE, PI_WARN, "AM SNs missing", EXPFILL }},
3655
14
        { &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
14
        { &ei_rlc_lte_um_sn_missing, { "rlc-lte.sequence-analysis.um-sn.missing", PI_SEQUENCE, PI_WARN, "UM SNs missing", EXPFILL }},
3657
14
        { &ei_rlc_lte_um_sn_repeated, { "rlc-lte.sequence-analysis.um-sn.repeated", PI_SEQUENCE, PI_WARN, "UM SN repeated", EXPFILL }},
3658
14
        { &ei_rlc_lte_wrong_sequence_number, { "rlc-lte.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
3659
14
        { &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
14
        { &ei_rlc_lte_reserved_bits_not_zero, { "rlc-lte.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
3661
14
        { &ei_rlc_lte_um_sn, { "rlc-lte.um.sn.invalid", PI_MALFORMED, PI_ERROR, "Invalid sequence number length", EXPFILL }},
3662
14
        { &ei_rlc_lte_header_only, { "rlc-lte.header-only.expert", PI_SEQUENCE, PI_NOTE, "RLC PDU SDUs have been omitted", EXPFILL }},
3663
14
        { &ei_rlc_lte_am_cpt, { "rlc-lte.am.cpt.invalid", PI_MALFORMED, PI_ERROR, "RLC Control frame type not handled", EXPFILL }},
3664
14
        { &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
14
        { &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
14
        { &ei_rlc_lte_am_nack_sn_partial, { "rlc-lte.am.nack-sn.partial", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK (partial)", EXPFILL }},
3667
14
        { &ei_rlc_lte_am_nack_sn, { "rlc-lte.am.nack-sn.expert", PI_SEQUENCE, PI_WARN, "Status PDU reports NACK", EXPFILL }},
3668
14
        { &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
14
        { &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
14
        { &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
14
        { &ei_rlc_lte_context_mode, { "rlc-lte.mode.invalid", PI_MALFORMED, PI_ERROR, "Unrecognised RLC Mode set", EXPFILL }},
3672
14
        { &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
14
        { &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
14
        { &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
14
    };
3676
3677
14
    static const enum_val_t sequence_analysis_vals[] = {
3678
14
        {"no-analysis", "No-Analysis",     false},
3679
14
        {"mac-only",    "Only-MAC-frames", SEQUENCE_ANALYSIS_MAC_ONLY},
3680
14
        {"rlc-only",    "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
3681
14
        {NULL, NULL, -1}
3682
14
    };
3683
3684
14
    module_t *rlc_lte_module;
3685
14
    expert_module_t* expert_rlc_lte;
3686
3687
    /* Register protocol. */
3688
14
    proto_rlc_lte = proto_register_protocol("RLC-LTE", "RLC-LTE", "rlc-lte");
3689
14
    proto_register_field_array(proto_rlc_lte, hf, array_length(hf));
3690
14
    proto_register_subtree_array(ett, array_length(ett));
3691
14
    expert_rlc_lte = expert_register_protocol(proto_rlc_lte);
3692
14
    expert_register_field_array(expert_rlc_lte, ei, array_length(ei));
3693
3694
    /* Allow other dissectors to find this one by name. */
3695
14
    register_dissector("rlc-lte", dissect_rlc_lte, proto_rlc_lte);
3696
3697
    /* Register the tap name */
3698
14
    rlc_lte_tap = register_tap("rlc-3gpp");
3699
3700
    /* Preferences */
3701
14
    rlc_lte_module = prefs_register_protocol(proto_rlc_lte, NULL);
3702
3703
14
    prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis_am",
3704
14
        "Do sequence analysis for AM channels",
3705
14
        "Attempt to keep track of PDUs for AM channels, and point out problems",
3706
14
        &global_rlc_lte_am_sequence_analysis, sequence_analysis_vals, false);
3707
3708
14
    prefs_register_enum_preference(rlc_lte_module, "do_sequence_analysis",
3709
14
        "Do sequence analysis for UM channels",
3710
14
        "Attempt to keep track of PDUs for UM channels, and point out problems",
3711
14
        &global_rlc_lte_um_sequence_analysis, sequence_analysis_vals, false);
3712
3713
14
    prefs_register_bool_preference(rlc_lte_module, "call_pdcp_for_srb",
3714
14
        "Call PDCP dissector for SRB PDUs",
3715
14
        "Call PDCP dissector for signalling PDUs.  Note that without reassembly, it can"
3716
14
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3717
14
        &global_rlc_lte_call_pdcp_for_srb);
3718
3719
14
    prefs_register_enum_preference(rlc_lte_module, "call_pdcp_for_drb",
3720
14
        "Call PDCP dissector for DRB PDUs",
3721
14
        "Call PDCP dissector for user-plane PDUs.  Note that without reassembly, it can"
3722
14
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3723
14
        &global_rlc_lte_call_pdcp_for_drb, pdcp_drb_col_vals, false);
3724
3725
3726
14
    prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_ccch",
3727
14
        "Call RRC dissector for CCCH PDUs",
3728
14
        "Call RRC dissector for CCCH PDUs",
3729
14
        &global_rlc_lte_call_rrc_for_ccch);
3730
3731
14
    prefs_register_bool_preference(rlc_lte_module, "call_rrc_for_mcch",
3732
14
        "Call RRC dissector for MCCH PDUs",
3733
14
        "Call RRC dissector for MCCH PDUs  Note that without reassembly, it can"
3734
14
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3735
14
        &global_rlc_lte_call_rrc_for_mcch);
3736
3737
14
    prefs_register_bool_preference(rlc_lte_module, "call_ip_for_mtch",
3738
14
        "Call IP dissector for MTCH PDUs",
3739
14
        "Call ip dissector for MTCH PDUs  Note that without reassembly, it can"
3740
14
        "only be called for complete PDUs (i.e. not segmented over RLC)",
3741
14
        &global_rlc_lte_call_ip_for_mtch);
3742
3743
14
    prefs_register_obsolete_preference(rlc_lte_module, "heuristic_rlc_lte_over_udp");
3744
3745
14
    prefs_register_bool_preference(rlc_lte_module, "header_only_mode",
3746
14
        "May see RLC headers only",
3747
14
        "When enabled, if data is not present, don't report as an error, but instead "
3748
14
        "add expert info to indicate that headers were omitted",
3749
14
        &global_rlc_lte_headers_expected);
3750
3751
14
    prefs_register_bool_preference(rlc_lte_module, "reassembly",
3752
14
        "Attempt SDU reassembly",
3753
14
        "When enabled, attempts to re-assemble upper-layer SDUs that are split over "
3754
14
        "more than one RLC PDU.  Note: does not currently support out-of-order or "
3755
14
        "re-segmentation. N.B. sequence analysis must also be turned on in order "
3756
14
        "for reassembly to work",
3757
14
        &global_rlc_lte_reassembly);
3758
3759
14
    ue_parameters_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3760
3761
14
    sequence_analysis_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3762
14
    sequence_analysis_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3763
14
    repeated_nack_channel_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_channel_hash_func, rlc_channel_equal);
3764
14
    repeated_nack_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3765
14
    reassembly_report_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), rlc_result_hash_func, rlc_result_hash_equal);
3766
14
}
3767
3768
void proto_reg_handoff_rlc_lte(void)
3769
14
{
3770
    /* Add as a heuristic UDP dissector */
3771
14
    heur_dissector_add("udp", dissect_rlc_lte_heur, "RLC-LTE over UDP", "rlc_lte_udp", proto_rlc_lte, HEURISTIC_DISABLE);
3772
3773
14
    pdcp_lte_handle        = find_dissector_add_dependency("pdcp-lte", proto_rlc_lte);
3774
14
    ip_handle              = find_dissector_add_dependency("ip", proto_rlc_lte);
3775
14
    lte_rrc_mcch           = find_dissector_add_dependency("lte_rrc.mcch", proto_rlc_lte);
3776
14
    lte_rrc_ul_ccch        = find_dissector_add_dependency("lte_rrc.ul_ccch", proto_rlc_lte);
3777
14
    lte_rrc_dl_ccch        = find_dissector_add_dependency("lte_rrc.dl_ccch", proto_rlc_lte);
3778
14
    lte_rrc_bcch_bch       = find_dissector_add_dependency("lte_rrc.bcch_bch", proto_rlc_lte);
3779
14
    lte_rrc_bcch_dl_sch    = find_dissector_add_dependency("lte_rrc.bcch_dl_sch", proto_rlc_lte);
3780
14
    lte_rrc_pcch           = find_dissector_add_dependency("lte_rrc.pcch", proto_rlc_lte);
3781
14
    lte_rrc_ul_ccch_nb     = find_dissector_add_dependency("lte_rrc.ul_ccch.nb", proto_rlc_lte);
3782
14
    lte_rrc_dl_ccch_nb     = find_dissector_add_dependency("lte_rrc.dl_ccch.nb", proto_rlc_lte);
3783
14
    lte_rrc_bcch_bch_nb    = find_dissector_add_dependency("lte_rrc.bcch_bch.nb", proto_rlc_lte);
3784
14
    lte_rrc_bcch_dl_sch_nb = find_dissector_add_dependency("lte_rrc.bcch_dl_sch.nb", proto_rlc_lte);
3785
14
    lte_rrc_pcch_nb        = find_dissector_add_dependency("lte_rrc.pcch.nb", proto_rlc_lte);
3786
3787
14
    proto_mac_lte = proto_get_id_by_filter_name("mac-lte");
3788
14
    proto_pdcp_lte = proto_get_id_by_filter_name("pdcp-lte");
3789
14
}
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
 */