Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-log3gpp.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-log3gpp.c
2
 * Routines for dissecting phone logs containing 3GPP protocol messages.
3
 * Copyright 2008, Vincent Helfre
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/prefs.h>
16
#include <epan/proto_data.h>
17
#include <wiretap/wtap.h>
18
#include <wsutil/strtoi.h>
19
#include <wsutil/array.h>
20
21
#include "packet-mac-lte.h"
22
#include "packet-pdcp-lte.h"
23
#include "packet-rlc-lte.h"
24
25
0
#define FD1 0
26
28
#define REL8 1
27
28
void proto_register_log3gpp(void);
29
void proto_reg_handoff_log3gpp(void);
30
31
/* Protocol and registered fields. */
32
static int proto_log3gpp;
33
34
35
static int hf_log3gpp_timestamp;
36
static int hf_log3gpp_protocol;
37
static int hf_log3gpp_direction;
38
static int hf_log3gpp_dissector_option;
39
static int hf_log3gpp_unparsed_data;
40
static int hf_log3gpp_dissected_length;
41
42
/* Protocol subtree. */
43
static int ett_log3gpp;
44
45
/* Variables used to select a version for RRC and NAS */
46
static int lte_rrc_prot_version = REL8;
47
static int nas_eps_prot_version = REL8;
48
49
static const enum_val_t lte_rrc_dissector_version[] = {
50
  {"FD1", "FD1", FD1},
51
  {"Rel8", "Rel8 dec 2008", REL8}, /* Add new dissector version after */
52
  {NULL, NULL, -1}
53
};
54
55
static const enum_val_t nas_eps_dissector_version[] = {
56
  {"FD1", "FD1", FD1},
57
  {"Rel8", "Rel8 dec 2008", REL8}, /* Add new dissector version after */
58
  {NULL, NULL, -1}
59
};
60
61
typedef enum packet_direction_t
62
{
63
    UPLINK,
64
    DOWNLINK
65
} packet_direction_t;
66
67
static const value_string direction_vals[] = {
68
    { 0,   "Uplink" },
69
    { 1,   "Downlink" },
70
    { 0,   NULL },
71
};
72
/* Pseudo header functions*/
73
typedef bool (*pseudo_hdr_func_ptr_t) (char *, packet_info *pinfo, uint16_t, packet_direction_t);
74
75
static bool lte_mac_pseudo_hdr(char *, packet_info *pinfo, uint16_t, packet_direction_t);
76
static bool lte_rlc_pseudo_hdr(char *, packet_info *pinfo, uint16_t, packet_direction_t);
77
static bool lte_pdcp_pseudo_hdr(char *, packet_info *pinfo, uint16_t, packet_direction_t);
78
79
typedef struct
80
{
81
  const char * protocol_name;
82
  const char * ul_dissector_name;
83
  const char * dl_dissector_name;
84
  dissector_handle_t ul_dissector_handle;
85
  dissector_handle_t dl_dissector_handle;
86
  pseudo_hdr_func_ptr_t hdr_process;
87
} lookup_dissector_element_t;
88
89
/* Look up table for protocol name /dissector: should be in alphabetic order!!!
90
   the purpose is to match a protocol name with a dissector,
91
   and to store the dissector handle the first time to avoid looking it up every time.
92
   This table should contain all 3GPP specified protocols */
93
static lookup_dissector_element_t dissector_lookup_table[] = {
94
  {"DATA","data","data",0,0,NULL},
95
  {"GAN.TCP","umatcp","umatcp",0,0,NULL},
96
  {"GAN.UDP","umaudp","umaudp",0,0,NULL},
97
  {"GSM.CCCH","gsm_a_ccch","gsm_a_ccch",0,0,NULL},
98
  {"GSM.SACCH","gsm_a_sacch","gsm_a_sacch",0,0,NULL},
99
  {"GTP","gtp","gtp",0,0,NULL},
100
  {"LLC","llcgprs","llcgprs",0,0,NULL},
101
  {"LTE-MAC","mac-lte","mac-lte",0,0, lte_mac_pseudo_hdr},
102
  {"LTE-PDCP","pdcp-lte","pdcp-lte",0,0, lte_pdcp_pseudo_hdr},
103
  {"LTE-RLC","rlc-lte","rlc-lte",0,0, lte_rlc_pseudo_hdr},
104
  {"LTE-RRC.BCCH.BCH",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
105
  {"LTE-RRC.BCCH.DL.SCH",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
106
  {"LTE-RRC.CCCH",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
107
  {"LTE-RRC.DCCH",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
108
  {"LTE-RRC.PCCH",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
109
  {"NAS","gsm_a_dtap","gsm_a_dtap",0,0,NULL},
110
  {"NAS-EPS",0,0,0,0,NULL}, /* Dissector set according to preferences (depending on the release) */
111
  {"RR","gsm_a_dtap","gsm_a_dtap",0,0,NULL},
112
  {"RRC.BCCH.BCH","rrc.bcch.bch","rrc.bcch.bch",0,0,NULL},
113
  {"RRC.BCCH.FACH","rrc.bcch.fach","rrc.bcch.fach",0,0,NULL},
114
  {"RRC.CCCH","rrc.ul.ccch","rrc.dl.ccch",0,0,NULL},
115
  {"RRC.DCCH","rrc.ul.dcch","rrc.dl.dcch",0,0,NULL},
116
  {"RRC.MCCH","rrc.mcch","rrc.mcch",0,0,NULL},
117
  {"RRC.MSCH","rrc.msch","rrc.msch",0,0,NULL},
118
  {"RRC.PCCH","rrc.pcch","rrc.pcch",0,0,NULL},
119
  {"RRC.SHCCH","rrc.ul.shcch","rrc.dl.shcch",0,0,NULL},
120
  {"RRC.SI.MIB","rrc.si.mib","rrc.si.mib",0,0,NULL},
121
  {"RRC.SI.SB1","rrc.sb1","rrc.sb1",0,0,NULL},
122
  {"RRC.SI.SB2","rrc.sb2","rrc.sb2",0,0,NULL},
123
  {"RRC.SI.SIB1","rrc.si.sib1","rrc.si.sib1",0,0,NULL},
124
  {"RRC.SI.SIB10","rrc.si.sib10","rrc.si.sib10",0,0,NULL},
125
  {"RRC.SI.SIB11","rrc.si.sib11","rrc.si.sib11",0,0,NULL},
126
  {"RRC.SI.SIB11bis","rrc.si.sib11bis","rrc.si.sib11bis",0,0,NULL},
127
  {"RRC.SI.SIB12","rrc.si.sib12","rrc.si.sib12",0,0,NULL},
128
  {"RRC.SI.SIB13","rrc.si.sib13","rrc.si.sib13",0,0,NULL },
129
  {"RRC.SI.SIB13-1","rrc.si.sib13-1","rrc.si.sib13-1",0,0,NULL},
130
  {"RRC.SI.SIB13-2","rrc.si.sib13-2","rrc.si.sib13-2",0,0,NULL},
131
  {"RRC.SI.SIB13-3","rrc.si.sib13-3","rrc.si.sib13-3",0,0,NULL },
132
  {"RRC.SI.SIB13-4","rrc.si.sib13-4","rrc.si.sib13-4",0,0,NULL},
133
  {"RRC.SI.SIB14","rrc.si.sib14","rrc.si.sib14",0,0,NULL},
134
  {"RRC.SI.SIB15","rrc.si.sib15","rrc.si.sib15",0,0,NULL},
135
  {"RRC.SI.SIB15bis","rrc.si.sib15bis","rrc.si.sib15bis",0,0,NULL},
136
  {"RRC.SI.SIB15-1","rrc.si.sib15-1","rrc.si.sib15-1",0,0,NULL},
137
  {"RRC.SI.SIB15-1bis","rrc.si.sib15-1bis","rrc.si.sib15-1bis",0,0,NULL },
138
  {"RRC.SI.SIB15-2","rrc.si.sib15-2","rrc.si.sib15-2",0,0,NULL},
139
  {"RRC.SI.SIB15-2bis","rrc.si.sib15-2bis","rrc.si.sib15-2bis",0,0,NULL},
140
  {"RRC.SI.SIB15-3","rrc.si.sib15-3","rrc.si.sib15-3",0,0,NULL},
141
  {"RRC.SI.SIB15-3bis","rrc.si.sib15-3bis","rrc.si.sib15-3bis",0,0,NULL},
142
  {"RRC.SI.SIB15-4","rrc.si.sib15-4","rrc.si.sib15-4",0,0,NULL},
143
  {"RRC.SI.SIB15-5","rrc.si.sib15-5","rrc.si.sib15-5",0,0,NULL},
144
  {"RRC.SI.SIB15-6","rrc.si.sib15-6","rrc.si.sib15-6",0,0,NULL},
145
  {"RRC.SI.SIB15-7","rrc.si.sib15-7","rrc.si.sib15-7",0,0,NULL},
146
  {"RRC.SI.SIB15-8","rrc.si.sib15-8","rrc.si.sib15-8",0,0,NULL},
147
  {"RRC.SI.SIB18","rrc.si.sib18","rrc.si.sib18",0,0,NULL},
148
  {"RRC.SI.SIB17","rrc.si.sib17","rrc.si.sib17",0,0,NULL},
149
  {"RRC.SI.SIB18","rrc.si.sib18","rrc.si.sib18",0,0,NULL},
150
  {"RRC.SI.SIB2","rrc.si.sib2","rrc.si.sib2",0,0,NULL},
151
  {"RRC.SI.SIB3","rrc.si.sib3","rrc.si.sib3",0,0,NULL},
152
  {"RRC.SI.SIB4","rrc.si.sib4","rrc.si.sib4",0,0,NULL},
153
  {"RRC.SI.SIB5","rrc.si.sib5","rrc.si.sib5",0,0,NULL},
154
  {"RRC.SI.SIB5bis","rrc.si.sib5bis","rrc.si.sib5bis",0,0,NULL},
155
  {"RRC.SI.SIB6","rrc.si.sib6","rrc.si.sib6",0,0,NULL},
156
  {"RRC.SI.SIB7","rrc.si.sib7","rrc.si.sib7",0,0,NULL},
157
  {"RRC.SI.SIB8","rrc.si.sib8","rrc.si.sib8",0,0,NULL},
158
  {"RRC.SI.SIB9","rrc.si.sib9","rrc.si.sib9",0,0,NULL},
159
  {"SNDCP","sndcp","sndcp",0,0,NULL},
160
  {"SNDCPXID","sndcpxid","sndcpxid",0,0,NULL}
161
};
162
163
164
static int
165
dissector_element_compare(const void *protocol_name, const void *element)
166
784
{
167
784
  return strcmp((const char *)protocol_name, ((const lookup_dissector_element_t *) element)->protocol_name);
168
784
}
169
170
static dissector_handle_t
171
look_for_dissector(char* protocol_name, packet_direction_t direction, pseudo_hdr_func_ptr_t* func_ptr _U_)
172
0
{
173
0
    lookup_dissector_element_t* element_ptr;
174
0
    dissector_handle_t dissector_handle = NULL;
175
176
0
    element_ptr = (lookup_dissector_element_t*)bsearch((void*)protocol_name,
177
0
        (void*)dissector_lookup_table,
178
0
        array_length(dissector_lookup_table),
179
0
        sizeof dissector_lookup_table[0],
180
0
        dissector_element_compare);
181
0
    if (element_ptr != NULL) {
182
0
        if (direction == UPLINK)
183
0
        {
184
0
            if (element_ptr->ul_dissector_handle == 0)
185
0
            {
186
0
                element_ptr->ul_dissector_handle = find_dissector(element_ptr->ul_dissector_name);
187
0
            }
188
0
            dissector_handle = element_ptr->ul_dissector_handle;
189
0
        }
190
0
        else
191
0
        {
192
0
            if (element_ptr->dl_dissector_handle == 0)
193
0
            {
194
0
                element_ptr->dl_dissector_handle = find_dissector(element_ptr->dl_dissector_name);
195
0
            }
196
0
            dissector_handle = element_ptr->dl_dissector_handle;
197
0
        }
198
199
0
    }
200
201
0
    return dissector_handle;
202
0
}
203
204
static void
205
update_dissector_name(const char* protocol_name, packet_direction_t direction, const char* dissector_name)
206
168
{
207
168
    lookup_dissector_element_t* element_ptr;
208
209
168
    element_ptr = (lookup_dissector_element_t*)bsearch((void*)protocol_name,
210
168
        (void*)dissector_lookup_table,
211
168
        array_length(dissector_lookup_table),
212
168
        sizeof dissector_lookup_table[0],
213
168
        dissector_element_compare);
214
168
    if (element_ptr != NULL) {
215
168
        if (direction == UPLINK)
216
84
        {
217
84
            element_ptr->ul_dissector_handle = 0;
218
84
            element_ptr->ul_dissector_name = dissector_name;
219
84
        }
220
84
        else
221
84
        {
222
84
            element_ptr->dl_dissector_handle = 0;
223
84
            element_ptr->dl_dissector_name = dissector_name;
224
84
        }
225
226
168
    }
227
168
}
228
229
/******************************************************************************/
230
/* pseudo header functions: used for the dissectors that needs pseudo headers */
231
/******************************************************************************/
232
233
234
/* In the optional string, MAC info should be set as follow (M = mandatory, O = optional):
235
 * Radio type (M):  "FDD" or "TDD"
236
 * RNTI type (M): "NO_RNTI" or "P_RNTI" or "RA_RNTI" or "C_RNTI" or "SI_RNT" followed by rnti value in decimal format
237
 * subframe number (M): "SFN" followed by the subframe number in decimal format
238
 */
239
static bool
240
lte_mac_pseudo_hdr(char* option_str, packet_info* pinfo, uint16_t length, packet_direction_t direction)
241
0
{
242
0
    struct mac_lte_info* p_mac_lte_info;
243
0
    char* par_opt_field;
244
0
    char option[30];
245
0
    static int proto_mac_lte = 0;
246
247
    /* look up for protocol handle */
248
0
    if (proto_mac_lte == 0)
249
0
    {
250
0
        proto_mac_lte = proto_get_id_by_filter_name("mac-lte");
251
0
    }
252
253
    /* Need to copy the string in a local buffer since strtok will modify it */
254
0
    (void) g_strlcpy(option, option_str, 30);
255
256
    /* Only need to set info once per session. */
257
0
    p_mac_lte_info = (struct mac_lte_info*)p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0);
258
0
    if (p_mac_lte_info != NULL)
259
0
    {
260
0
        return 1;
261
0
    }
262
263
    /* Allocate & zero struct */
264
0
    p_mac_lte_info = (struct mac_lte_info*) wmem_new0(pinfo->pool, mac_lte_info);
265
266
    /* First mandatory parameter */
267
0
    par_opt_field = strtok(option, " ");
268
0
    if (par_opt_field == NULL)
269
0
    {
270
0
        return 0;
271
0
    }
272
0
    if (strcmp(par_opt_field, "FDD") == 0)
273
0
    {
274
0
        p_mac_lte_info->radioType = FDD_RADIO;
275
0
    }
276
0
    else if (strcmp(par_opt_field, "TDD") == 0)
277
0
    {
278
0
        p_mac_lte_info->radioType = TDD_RADIO;
279
0
    }
280
0
    else
281
0
    {
282
0
        return 0;
283
0
    }
284
285
    /* Second mandatory parameter */
286
0
    par_opt_field = strtok(NULL, " ");
287
0
    if (par_opt_field == NULL)
288
0
    {
289
0
        return 0;
290
0
    }
291
0
    if (strcmp(par_opt_field, "NO_RNTI") == 0)
292
0
    {
293
0
        p_mac_lte_info->rntiType = NO_RNTI;
294
0
    }
295
0
    else if (strcmp(par_opt_field, "P_RNTI") == 0)
296
0
    {
297
0
        p_mac_lte_info->rntiType = P_RNTI;
298
0
    }
299
0
    else if (strcmp(par_opt_field, "RA_RNTI") == 0)
300
0
    {
301
0
        p_mac_lte_info->rntiType = RA_RNTI;
302
0
    }
303
0
    else if (strcmp(par_opt_field, "C_RNTI") == 0)
304
0
    {
305
0
        p_mac_lte_info->rntiType = C_RNTI;
306
0
    }
307
0
    else if (strcmp(par_opt_field, "SI_RNTI") == 0)
308
0
    {
309
0
        p_mac_lte_info->rntiType = SI_RNTI;
310
0
    }
311
0
    else
312
0
    {
313
0
        return 0;
314
0
    }
315
    /* Get the associated rnti value */
316
0
    par_opt_field = strtok(NULL, " ");
317
0
    if (par_opt_field)
318
0
    {
319
0
        ws_strtoi16(par_opt_field, NULL, &p_mac_lte_info->rnti);
320
0
    }
321
0
    else
322
0
    {
323
0
        return 0;
324
0
    }
325
326
    /* First optional parameter */
327
0
    p_mac_lte_info->subframeNumber = 0;
328
0
    par_opt_field = strtok(NULL, " ");
329
0
    if (par_opt_field == NULL)
330
0
    {
331
0
        return 0;
332
0
    }
333
0
    if (strcmp(par_opt_field, "SFN") == 0)
334
0
    {
335
0
        par_opt_field = strtok(NULL, " ");
336
0
        if (par_opt_field != NULL)
337
0
        {
338
0
            ws_strtoi16(par_opt_field, NULL, &p_mac_lte_info->subframeNumber);
339
0
        }
340
0
    }
341
0
    p_mac_lte_info->direction = (direction == UPLINK) ? DIRECTION_UPLINK : DIRECTION_DOWNLINK;
342
0
    p_mac_lte_info->length = length;
343
344
    /* Store info in packet */
345
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0, p_mac_lte_info);
346
347
0
    return 1;
348
0
}
349
350
/* In the optional string, RLC info should be set as follow (M = mandatory, O = optional):
351
 * Channel type (M): "SRB" or "DRB" followed by the RB ID
352
 * RLC mode (M): "TM" or  "UM" or "AM" or "NA"
353
 * UM Sequence nb length (O): "SN_5b" or "SN_10b"
354
 */
355
356
static bool
357
lte_rlc_pseudo_hdr(char* option_str, packet_info* pinfo, uint16_t length, packet_direction_t direction)
358
0
{
359
0
    struct rlc_lte_info* p_rlc_lte_info;
360
0
    char* par_opt_field;
361
0
    char option[30];
362
0
    static int proto_rlc_lte = 0;
363
364
    /* look up for protocol handle */
365
0
    if (proto_rlc_lte == 0)
366
0
    {
367
0
        proto_rlc_lte = proto_get_id_by_filter_name("rlc-lte");
368
0
    }
369
0
    (void) g_strlcpy(option, option_str, 30);
370
371
    /* Only need to set info once per session. */
372
0
    p_rlc_lte_info = (struct rlc_lte_info*)p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0);
373
0
    if (p_rlc_lte_info != NULL)
374
0
    {
375
0
        return 1;
376
0
    }
377
378
    /* Allocate & zero struct */
379
0
    p_rlc_lte_info = (struct rlc_lte_info*) wmem_new0(pinfo->pool, rlc_lte_info);
380
    /* First mandatory parameter */
381
0
    par_opt_field = strtok(option, " ");
382
0
    if (par_opt_field == NULL)
383
0
    {
384
0
        return 0;
385
0
    }
386
0
    if (strcmp(par_opt_field, "SRB") == 0)
387
0
    {
388
0
        p_rlc_lte_info->channelType = CHANNEL_TYPE_SRB;
389
0
    }
390
0
    else if (strcmp(par_opt_field, "DRB") == 0)
391
0
    {
392
0
        p_rlc_lte_info->channelType = CHANNEL_TYPE_DRB;
393
0
    }
394
0
    else
395
0
    {
396
0
        return 0;
397
0
    }
398
    /* Fill in the RB ID */
399
0
    par_opt_field = strtok(NULL, " ");
400
0
    if (par_opt_field == NULL)
401
0
    {
402
0
        return 0;
403
0
    }
404
0
    ws_strtou16(par_opt_field, NULL, &p_rlc_lte_info->channelId);
405
406
    /* Second mandatory parameter */
407
0
    par_opt_field = strtok(NULL, " ");
408
0
    if (par_opt_field == NULL)
409
0
    {
410
0
        return 0;
411
0
    }
412
0
    if (strcmp(par_opt_field, "TM") == 0)
413
0
    {
414
0
        p_rlc_lte_info->rlcMode = RLC_TM_MODE;
415
0
    }
416
0
    else if (strcmp(par_opt_field, "UM") == 0)
417
0
    {
418
0
        p_rlc_lte_info->rlcMode = RLC_UM_MODE;
419
0
    }
420
0
    else if (strcmp(par_opt_field, "AM") == 0)
421
0
    {
422
0
        p_rlc_lte_info->rlcMode = RLC_AM_MODE;
423
0
    }
424
0
    else if (strcmp(par_opt_field, "NA") == 0)
425
0
    {
426
0
        p_rlc_lte_info->rlcMode = RLC_PREDEF;
427
0
    }
428
0
    else
429
0
    {
430
0
        return 0;
431
0
    }
432
433
    /* First optional parameter */
434
0
    par_opt_field = strtok(NULL, " ");
435
0
    if (par_opt_field != NULL)
436
0
    {
437
0
        if (strcmp(par_opt_field, "SN_5b") == 0)
438
0
        {
439
0
            p_rlc_lte_info->sequenceNumberLength = UM_SN_LENGTH_5_BITS;
440
0
        }
441
0
        else if (strcmp(par_opt_field, "SN_10b") == 0)
442
0
        {
443
0
            p_rlc_lte_info->sequenceNumberLength = UM_SN_LENGTH_10_BITS;
444
0
        }
445
0
    }
446
0
    p_rlc_lte_info->direction = (direction == UPLINK) ? DIRECTION_UPLINK : DIRECTION_DOWNLINK;
447
0
    p_rlc_lte_info->priority = 0;
448
0
    p_rlc_lte_info->ueid = 0;
449
0
    p_rlc_lte_info->pduLength = length;
450
451
    /* Store info in packet */
452
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0, p_rlc_lte_info);
453
454
0
    return 1;
455
0
}
456
457
/* In the optional string, PDCP info should be set as follow (M = mandatory, O = optional):
458
 * Plane: "SRB" or "DRB"
459
 * Sequence number length: "SN_7b" or "SN_12b"
460
 */
461
static bool
462
lte_pdcp_pseudo_hdr(char* option_str, packet_info* pinfo, uint16_t length _U_, packet_direction_t direction)
463
0
{
464
0
    struct pdcp_lte_info* p_pdcp_lte_info;
465
0
    char* par_opt_field;
466
0
    char option[30];
467
0
    static int proto_pdcp_lte = 0;
468
469
    /* look up for protocol handle */
470
0
    if (proto_pdcp_lte == 0)
471
0
    {
472
0
        proto_pdcp_lte = proto_get_id_by_filter_name("pdcp-lte");
473
0
    }
474
0
    (void) g_strlcpy(option, option_str, 30);
475
476
    /* Only need to set info once per session. */
477
0
    p_pdcp_lte_info = (struct pdcp_lte_info*)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
478
0
    if (p_pdcp_lte_info != NULL)
479
0
    {
480
0
        return 1;
481
0
    }
482
483
    /* Allocate & zero struct */
484
0
    p_pdcp_lte_info = (struct pdcp_lte_info*) wmem_new0(pinfo->pool, pdcp_lte_info);
485
    /* First mandatory parameter */
486
0
    par_opt_field = strtok(option, " ");
487
0
    if (par_opt_field == NULL)
488
0
    {
489
0
        return 0;
490
0
    }
491
0
    if (strcmp(par_opt_field, "SRB") == 0)
492
0
    {
493
0
        p_pdcp_lte_info->plane = SIGNALING_PLANE;
494
0
    }
495
0
    else if (strcmp(par_opt_field, "DRB") == 0)
496
0
    {
497
0
        p_pdcp_lte_info->plane = USER_PLANE;
498
0
    }
499
0
    else
500
0
    {
501
0
        return 0;
502
0
    }
503
    /* Second mandatory parameter */
504
0
    par_opt_field = strtok(NULL, " ");
505
0
    if (par_opt_field == NULL)
506
0
    {
507
0
        return 0;
508
0
    }
509
0
    if (strcmp(par_opt_field, "SN_7b") == 0)
510
0
    {
511
0
        p_pdcp_lte_info->seqnum_length = PDCP_SN_LENGTH_7_BITS;
512
0
    }
513
0
    else if (strcmp(par_opt_field, "SN_12b") == 0)
514
0
    {
515
0
        p_pdcp_lte_info->seqnum_length = PDCP_SN_LENGTH_12_BITS;
516
0
    }
517
0
    else
518
0
    {
519
0
        return 0;
520
0
    }
521
0
    p_pdcp_lte_info->no_header_pdu = 0;
522
0
    p_pdcp_lte_info->rohc.rohc_compression = 0;
523
0
    p_pdcp_lte_info->direction = (direction == UPLINK) ? DIRECTION_UPLINK : DIRECTION_DOWNLINK;
524
525
    /* Store info in packet */
526
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0, p_pdcp_lte_info);
527
528
0
    return 1;
529
0
}
530
531
532
/*****************************************/
533
/* Main dissection function.             */
534
/*****************************************/
535
static int
536
dissect_log3gpp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
537
0
{
538
0
    proto_tree* prot3gpp_tree = NULL;
539
0
    proto_item* ti = NULL;
540
0
    int         offset = 0;
541
0
    int         protocol_name_start;
542
0
    int         protocol_name_length;
543
0
    int         protocol_option_start;
544
0
    int         protocol_option_length;
545
0
    int         timestamp_start;
546
0
    int         timestamp_length;
547
0
    packet_direction_t      direction;
548
0
    tvbuff_t* next_tvb;
549
0
    dissector_handle_t protocol_handle = 0;
550
0
    int sub_dissector_result = 0;
551
0
    char* protocol_name;
552
0
    char* protocol_option;
553
0
    bool is_hex_data;
554
555
    /* Clear Info */
556
0
    col_clear(pinfo->cinfo, COL_INFO);
557
558
    /* Create root (protocol) tree. */
559
0
    ti = proto_tree_add_item(tree, proto_log3gpp, tvb, offset, -1, ENC_NA);
560
0
    prot3gpp_tree = proto_item_add_subtree(ti, ett_log3gpp);
561
562
    /*********************************************************************/
563
    /* Note that these are the fields of the stub header as written out  */
564
    /* by the wiretap module                                             */
565
566
    /* Timestamp in file */
567
0
    timestamp_start = offset;
568
0
    timestamp_length = tvb_strsize(tvb, offset);
569
0
    if (prot3gpp_tree) {
570
0
        proto_tree_add_double_format_value(prot3gpp_tree, hf_log3gpp_timestamp, tvb,
571
0
            offset, timestamp_length,
572
0
            g_ascii_strtod(tvb_format_text(pinfo->pool, tvb, offset, timestamp_length), NULL),
573
0
            "%s", tvb_format_text(pinfo->pool, tvb, offset, timestamp_length - 1));
574
0
    }
575
0
    offset += timestamp_length;
576
577
578
    /* protocol name */
579
0
    protocol_name_start = offset;
580
0
    protocol_name_length = tvb_strsize(tvb, offset);
581
0
    if (prot3gpp_tree) {
582
0
        proto_tree_add_item(prot3gpp_tree, hf_log3gpp_protocol, tvb, offset, protocol_name_length, ENC_ASCII | ENC_NA);
583
0
    }
584
0
    offset += protocol_name_length;
585
586
    /* Direction */
587
0
    direction = (packet_direction_t)tvb_get_uint8(tvb, offset);
588
0
    if (prot3gpp_tree) {
589
0
        proto_tree_add_item(prot3gpp_tree, hf_log3gpp_direction, tvb, offset, 1, ENC_BIG_ENDIAN);
590
0
    }
591
0
    offset++;
592
593
    /* protocol option */
594
0
    protocol_option_start = offset;
595
0
    protocol_option_length = tvb_strsize(tvb, offset);
596
0
    if (prot3gpp_tree) {
597
0
        proto_tree_add_item(prot3gpp_tree, hf_log3gpp_dissector_option, tvb, offset, protocol_option_length, ENC_ASCII | ENC_NA);
598
0
    }
599
0
    offset += protocol_option_length;
600
601
0
    if (prot3gpp_tree)
602
0
    {
603
        /* Set selection length of prot3gpp tree */
604
0
        proto_item_set_len(prot3gpp_tree, offset);
605
0
    }
606
607
    /* Add useful details to protocol tree label */
608
0
    protocol_name = (char*)tvb_get_string_enc(pinfo->pool, tvb, protocol_name_start, protocol_name_length, ENC_UTF_8 | ENC_NA);
609
    /* Set Protocol */
610
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, protocol_name);
611
    /* To know whether the data following is row byte stream or text data */
612
0
    is_hex_data = strcmp(protocol_name, "TXT");
613
614
0
    proto_item_append_text(ti, " t=%s   %c   prot=%s",
615
0
        tvb_get_string_enc(pinfo->pool, tvb, timestamp_start, timestamp_length, ENC_UTF_8 | ENC_NA),
616
0
        (direction == 0) ? 'U' : 'D',
617
0
        protocol_name);
618
619
0
    if (is_hex_data)
620
0
    {
621
        /* We might need to prepend pseudo header for the dissector */
622
0
        pseudo_hdr_func_ptr_t func_ptr = NULL;
623
624
        /* Look up for the optional information */
625
0
        protocol_option = (char*)tvb_get_string_enc(pinfo->pool, tvb, protocol_option_start, protocol_option_length, ENC_UTF_8 | ENC_NA);
626
627
        /* look up for the right dissector handle */
628
0
        protocol_handle = look_for_dissector(protocol_name, direction, &func_ptr);
629
630
        /***********************************************************************/
631
        /* Now hand off to the dissector of intended packet encapsulation type */
632
633
        /* Try appropriate dissector, if one has been selected */
634
0
        if (protocol_handle != 0)
635
0
        {
636
            /* Dissect the remainder of the frame using chosen protocol handle */
637
0
            next_tvb = tvb_new_subset_length_caplen(tvb, offset, -1, tvb_reported_length(tvb) - offset);
638
639
            /* This part is optional, only for dissector that need pseudo header information */
640
0
            if (func_ptr != NULL && strlen(protocol_option) != 0)
641
0
            {
642
0
                if (func_ptr(protocol_option, pinfo, offset, direction) == 0)
643
0
                {
644
                    /* There was an error, return */
645
0
                    return tvb_reported_length(tvb);
646
0
                }
647
0
            }
648
0
            sub_dissector_result = call_dissector(protocol_handle, next_tvb, pinfo, tree);
649
0
        }
650
0
    }
651
652
0
    if (protocol_handle == 0 || sub_dissector_result == 0)
653
0
    {
654
        /* Could get here because:
655
          - desired protocol is unavailable (probably disabled), OR
656
          - protocol rejected our data
657
          Show remaining bytes as unparsed data */
658
0
        proto_tree_add_item(prot3gpp_tree, hf_log3gpp_unparsed_data, tvb, offset, -1, ENC_NA);
659
660
0
        if (!is_hex_data)
661
0
        {
662
0
            col_add_str(pinfo->cinfo, COL_INFO,
663
0
                tvb_get_string_enc(pinfo->pool, tvb, offset, tvb_reported_length(tvb) - offset, ENC_UTF_8 | ENC_NA));
664
0
        }
665
0
        else
666
0
        {
667
0
            col_add_fstr(pinfo->cinfo, COL_INFO,
668
0
                "Not dissected  ( t=%s   %c   prot=%s)",
669
0
                tvb_get_string_enc(pinfo->pool, tvb, timestamp_start, timestamp_length, ENC_UTF_8 | ENC_NA),
670
0
                (direction == 0) ? 'U' : 'D',
671
0
                tvb_get_string_enc(pinfo->pool, tvb, protocol_name_start, protocol_name_length, ENC_UTF_8 | ENC_NA));
672
0
        }
673
0
    }
674
0
    else
675
0
    {
676
        /* Show number of dissected bytes */
677
0
        proto_item* ti_local = proto_tree_add_uint(prot3gpp_tree,
678
0
            hf_log3gpp_dissected_length,
679
0
            tvb, 0, 0, tvb_reported_length(tvb) - offset);
680
0
        proto_item_set_generated(ti_local);
681
0
    }
682
0
    return tvb_reported_length(tvb);
683
0
}
684
685
/******************************************************************************/
686
/* Associate this protocol with the log3gpp file encapsulation type. */
687
/******************************************************************************/
688
void proto_reg_handoff_log3gpp(void)
689
14
{
690
14
    static bool init = false;
691
692
14
    if (init == false)
693
14
    {
694
14
        dissector_handle_t log3gpp_handle;
695
696
14
        log3gpp_handle = find_dissector("prot3gpp");
697
14
        dissector_add_uint("wtap_encap", WTAP_ENCAP_LOG_3GPP, log3gpp_handle);
698
14
        init = true;
699
14
    }
700
14
    if (lte_rrc_prot_version == REL8)
701
14
    {
702
14
        update_dissector_name("LTE-RRC.BCCH.BCH", UPLINK, "lte-rrc.bcch.bch");
703
14
        update_dissector_name("LTE-RRC.BCCH.BCH", DOWNLINK, "lte-rrc.bcch.bch");
704
14
        update_dissector_name("LTE-RRC.BCCH.DL.SCH", UPLINK, "lte-rrc.bcch.dl.sch");
705
14
        update_dissector_name("LTE-RRC.BCCH.DL.SCH", DOWNLINK, "lte-rrc.bcch.dl.sch");
706
14
        update_dissector_name("LTE-RRC.CCCH", UPLINK, "lte-rrc.ul.ccch");
707
14
        update_dissector_name("LTE-RRC.CCCH", DOWNLINK, "lte-rrc.dl.ccch");
708
14
        update_dissector_name("LTE-RRC.DCCH", UPLINK, "lte-rrc.ul.dcch");
709
14
        update_dissector_name("LTE-RRC.DCCH", DOWNLINK, "lte-rrc.dl.dcch");
710
14
        update_dissector_name("LTE-RRC.PCCH", UPLINK, "lte-rrc.pcch");
711
14
        update_dissector_name("LTE-RRC.PCCH", DOWNLINK, "lte-rrc.pcch");
712
14
    }
713
0
    else if (lte_rrc_prot_version == FD1)
714
0
    {
715
0
        update_dissector_name("LTE-RRC.BCCH.BCH", UPLINK, "lte-rrc-fd1.bcch.bch");
716
0
        update_dissector_name("LTE-RRC.BCCH.BCH", DOWNLINK, "lte-rrc-fd1.bcch.bch");
717
0
        update_dissector_name("LTE-RRC.BCCH.DL.SCH", UPLINK, "lte-rrc-fd1.bcch.dl.sch");
718
0
        update_dissector_name("LTE-RRC.BCCH.DL.SCH", DOWNLINK, "lte-rrc-fd1.bcch.dl.sch");
719
0
        update_dissector_name("LTE-RRC.CCCH", UPLINK, "lte-rrc-fd1.ul.ccch");
720
0
        update_dissector_name("LTE-RRC.CCCH", DOWNLINK, "lte-rrc-fd1.dl.ccch");
721
0
        update_dissector_name("LTE-RRC.DCCH", UPLINK, "lte-rrc-fd1.ul.dcch");
722
0
        update_dissector_name("LTE-RRC.DCCH", DOWNLINK, "lte-rrc-fd1.dl.dcch");
723
0
        update_dissector_name("LTE-RRC.PCCH", UPLINK, "lte-rrc-fd1.pcch");
724
0
        update_dissector_name("LTE-RRC.PCCH", DOWNLINK, "lte-rrc-fd1.pcch");
725
0
    }
726
14
    if (nas_eps_prot_version == REL8)
727
14
    {
728
14
        update_dissector_name("NAS-EPS", UPLINK, "nas-eps");
729
14
        update_dissector_name("NAS-EPS", DOWNLINK, "nas-eps");
730
14
    }
731
0
    else if (nas_eps_prot_version == FD1)
732
0
    {
733
0
        update_dissector_name("NAS-EPS", UPLINK, "nas-eps-fd1");
734
0
        update_dissector_name("NAS-EPS", DOWNLINK, "nas-eps-fd1");
735
0
    }
736
14
}
737
738
/****************************************/
739
/* Register the protocol                */
740
/****************************************/
741
void proto_register_log3gpp(void)
742
14
{
743
14
  module_t *log3gpp_module;
744
14
    static hf_register_info hf[] =
745
14
    {
746
14
        { &hf_log3gpp_timestamp,
747
14
            { "Timestamp",
748
14
              "log3gpp.timestamp", FT_DOUBLE, BASE_NONE, NULL, 0x0,
749
14
              "File timestamp", HFILL
750
14
            }
751
14
        },
752
14
        { &hf_log3gpp_protocol,
753
14
            { "3GPP protocol",
754
14
              "log3gpp.protocol", FT_STRING, BASE_NONE, NULL, 0x0,
755
14
              "Original 3GPP protocol name", HFILL
756
14
            }
757
14
        },
758
14
        { &hf_log3gpp_dissector_option,
759
14
            { "option",
760
14
              "log3gpp.option", FT_STRING, BASE_NONE, NULL, 0x0,
761
14
              "Protocol option", HFILL
762
14
            }
763
14
        },
764
14
        { &hf_log3gpp_direction,
765
14
            { "Direction",
766
14
              "log3gpp.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
767
14
              "Frame direction (Uplink or Downlink)", HFILL
768
14
            }
769
14
        },
770
14
        { &hf_log3gpp_unparsed_data,
771
14
            { "Unparsed protocol data",
772
14
              "log3gpp.unparsed_data", FT_BYTES, BASE_NONE, NULL, 0x0,
773
14
              "Unparsed 3GPP protocol data", HFILL
774
14
            }
775
14
        },
776
14
        { &hf_log3gpp_dissected_length,
777
14
            { "Dissected length",
778
14
              "log3gpp.dissected-length", FT_UINT16, BASE_DEC, NULL, 0x0,
779
14
              "Number of bytes dissected by subdissector(s)", HFILL
780
14
            }
781
14
        },
782
14
    };
783
784
14
    static int *ett[] =
785
14
    {
786
14
        &ett_log3gpp
787
14
    };
788
789
    /* Register protocol. */
790
14
    proto_log3gpp = proto_register_protocol("3GPP log packet",
791
14
                                            "LOG3GPP",
792
14
                                            "log3gpp");
793
14
    proto_register_field_array(proto_log3gpp, hf, array_length(hf));
794
14
    proto_register_subtree_array(ett, array_length(ett));
795
796
14
    log3gpp_module = prefs_register_protocol(proto_log3gpp, proto_reg_handoff_log3gpp);
797
14
    prefs_register_enum_preference(log3gpp_module,
798
14
                                   "rrc_release_version",
799
14
                                   "Select the release version of LTE RRC protocol",
800
14
                                   "There might be plugins corresponding to different version of the specification "
801
14
                                   "If they are present they should be listed here.",
802
14
                                   &lte_rrc_prot_version,
803
14
                                   lte_rrc_dissector_version,
804
14
                                   false);
805
806
14
    prefs_register_enum_preference(log3gpp_module,
807
14
                                   "nas_eps_release_version",
808
14
                                   "Select the release version of NAS EPS protocol",
809
14
                                   "There might be plugins corresponding to different version of the specification "
810
14
                                   "If they are present they should be listed here.",
811
14
                                   &nas_eps_prot_version,
812
14
                                   nas_eps_dissector_version,
813
14
                                   false);
814
815
    /* Allow dissector to find be found by name. */
816
14
    register_dissector("prot3gpp", dissect_log3gpp, proto_log3gpp);
817
14
}
818
819
/*
820
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
821
 *
822
 * Local variables:
823
 * c-basic-offset: 4
824
 * tab-width: 8
825
 * indent-tabs-mode: nil
826
 * End:
827
 *
828
 * vi: set shiftwidth=4 tabstop=8 expandtab:
829
 * :indentSize=4:tabSize=8:noTabs=true:
830
 */