Coverage Report

Created: 2025-04-03 08:45

/src/wireshark/wiretap/log3gpp.c
Line
Count
Source (jump to first uncovered line)
1
/* log3gpp.c
2
 * Routines encapsulating/dumping 3gpp protocol logs.
3
 * The purpose of this format is to be able to log the 3GPP protocol stack on a mobile phone.
4
 * Copyright 2008, Vincent Helfre
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
#include "log3gpp.h"
15
16
#define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
17
18
#include <errno.h>
19
#include <string.h>
20
#include <stdlib.h>
21
22
#include "wtap-int.h"
23
#include "file_wrappers.h"
24
25
0
#define MAX_FIRST_LINE_LENGTH      200
26
0
#define MAX_TIMESTAMP_LINE_LENGTH  100
27
#define MAX_LINE_LENGTH            65536
28
0
#define MAX_TIMESTAMP_LEN          32
29
0
#define MAX_SECONDS_CHARS          16
30
0
#define MAX_SUBSECOND_DECIMALS     4
31
0
#define MAX_PROTOCOL_NAME          64
32
0
#define MAX_PROTOCOL_PAR_STRING    64
33
34
/* 'u' or 'd' of a packet as read from file */
35
typedef enum packet_direction_t
36
{
37
    uplink,
38
    downlink
39
} packet_direction_t;
40
41
typedef struct {
42
    time_t  start_secs;
43
    uint32_t  start_usecs;
44
} log3gpp_t;
45
46
int first_packet_offset;
47
char firstline[MAX_FIRST_LINE_LENGTH];
48
char secondline[MAX_TIMESTAMP_LINE_LENGTH];
49
int secondline_length;
50
51
/***********************************************************/
52
/* Transient data used for parsing                         */
53
54
/* 'Magic number' at start of 3gpp log files. */
55
static const char log3gpp_magic[] = "3GPP protocols transcript";
56
57
/* Protocol name of the packet that the packet was captured at */
58
static char protocol_name[MAX_PROTOCOL_NAME+1];
59
60
/* Optional string parameter giving info required for the protocol dissector */
61
static char protocol_parameters[MAX_PROTOCOL_PAR_STRING+1];
62
/************************************************************/
63
/* Functions called from wiretap core                       */
64
static bool log3gpp_read( wtap* wth, wtap_rec* rec,
65
                                    int* err, char** err_info, int64_t* data_offset);
66
static bool log3gpp_seek_read(struct wtap *wth, int64_t seek_off,
67
                                  wtap_rec *rec,
68
                                  int *err, char **err_info);
69
70
/************************************************************/
71
/* Private helper functions                                 */
72
static bool read_new_line(FILE_T fh, int* length,
73
    char* buf, size_t bufsize, int* err,
74
    char** err_info);
75
76
static bool parse_line(char* linebuff, int line_length, int *seconds, int *useconds,
77
                           long *data_offset,
78
                           int *data_chars,
79
                           packet_direction_t *direction,
80
                           bool *is_text_data);
81
static int write_stub_header(unsigned char *frame_buffer, char *timestamp_string,
82
                             packet_direction_t direction);
83
static unsigned char hex_from_char(char c);
84
/*not used static char char_from_hex(unsigned char hex);*/
85
86
static bool get_file_time_stamp(const char* linebuff, time_t *secs, uint32_t *usecs);
87
88
89
static int log3gpp_file_type_subtype = -1;
90
91
void register_log3gpp(void);
92
93
/***************************************************************************/
94
/* Free log3gpp-specific capture info from file that was open for reading  */
95
/***************************************************************************/
96
static void log3gpp_close(wtap* wth)
97
0
{
98
0
    log3gpp_t* log3gpp = (log3gpp_t*)wth->priv;
99
    /* Also free this capture info */
100
0
    g_free(log3gpp);
101
0
    wth->priv = NULL;
102
0
}
103
104
/********************************************/
105
/* Open file (for reading)                 */
106
/********************************************/
107
wtap_open_return_val
108
log3gpp_open(wtap *wth, int *err, char **err_info _U_)
109
0
{
110
0
    time_t  timestamp;
111
0
    uint32_t usecs;
112
0
    log3gpp_t *log3gpp;
113
0
    wtap_open_return_val retval;
114
    /* Buffer to hold a single text line read from the file */
115
0
    static char linebuff[MAX_LINE_LENGTH];
116
0
    int firstline_length = 0;
117
118
    /* Clear errno before reading from the file */
119
0
    errno = 0;
120
121
    /********************************************************************/
122
    /* First line needs to contain at least as many characters as magic */
123
124
    /*ws_warning("Open file"); */
125
126
0
    if (!read_new_line(wth->fh, &firstline_length, linebuff,
127
0
        sizeof linebuff, err, err_info)) {
128
0
        if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
129
0
            return WTAP_OPEN_ERROR;
130
0
        }
131
0
        else {
132
0
            return WTAP_OPEN_NOT_MINE;
133
0
        }
134
0
    }
135
136
0
    if (((size_t)firstline_length < strlen(log3gpp_magic)) ||
137
0
        firstline_length >= MAX_FIRST_LINE_LENGTH)
138
0
    {
139
0
        retval = WTAP_OPEN_NOT_MINE;
140
0
        return retval;
141
0
    }
142
143
    /* This file is not for us if it doesn't match our signature */
144
0
    if (memcmp(log3gpp_magic, linebuff, strlen(log3gpp_magic)) != 0)
145
0
    {
146
0
        retval = WTAP_OPEN_NOT_MINE;
147
0
        return retval;
148
0
    }
149
150
    /***********************************************************/
151
    /* Second line contains file timestamp                     */
152
0
    if (!read_new_line(wth->fh, &secondline_length,
153
0
        linebuff, sizeof linebuff, err, err_info)) {
154
0
        if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
155
0
            return WTAP_OPEN_ERROR;
156
0
        }
157
0
        else {
158
0
            return WTAP_OPEN_NOT_MINE;
159
0
        }
160
0
    }
161
162
0
    first_packet_offset = firstline_length +  secondline_length;
163
164
0
    if ((secondline_length >= MAX_TIMESTAMP_LINE_LENGTH) ||
165
0
        (!get_file_time_stamp(linebuff, &timestamp, &usecs)))
166
0
    {
167
        /* Give up if file time line wasn't valid */
168
0
        retval = WTAP_OPEN_NOT_MINE;
169
0
        return retval;
170
0
    }
171
172
    /* Allocate struct and fill in timestamp (netmon re used)*/
173
0
    log3gpp = g_new(log3gpp_t, 1);
174
0
    log3gpp->start_secs = timestamp;
175
0
    log3gpp->start_usecs = usecs;
176
0
    wth->priv = (void *)log3gpp;
177
178
    /************************************************************/
179
    /* File is for us. Fill in details so packets can be read   */
180
181
    /* Set our file type */
182
0
    wth->file_type_subtype = log3gpp_file_type_subtype;
183
184
    /* Use our own encapsulation to send all packets to our stub dissector */
185
0
    wth->file_encap = WTAP_ENCAP_LOG_3GPP;
186
187
    /* Callbacks for reading operations */
188
0
    wth->subtype_read = log3gpp_read;
189
0
    wth->subtype_seek_read = log3gpp_seek_read;
190
0
    wth->subtype_close = log3gpp_close;
191
192
    /* Choose microseconds (have 4 decimal places...) */
193
0
    wth->file_tsprec = WTAP_TSPREC_USEC;
194
195
0
    *err = errno;
196
197
    /*
198
     * Add an IDB; we don't know how many interfaces were
199
     * involved, so we just say one interface, about which
200
     * we only know the link-layer type, snapshot length,
201
     * and time stamp resolution.
202
     */
203
0
    wtap_add_generated_idb(wth);
204
205
0
    retval = WTAP_OPEN_MINE;
206
0
    return retval;
207
0
}
208
209
210
/**************************************************/
211
/* Read packet function.                          */
212
/* Look for and read the next usable packet       */
213
/* - return true and details if found             */
214
/**************************************************/
215
bool log3gpp_read(wtap* wth, wtap_rec* rec,
216
    int* err, char** err_info, int64_t* data_offset)
217
0
{
218
0
    int64_t offset = file_tell(wth->fh);
219
0
    static char linebuff[MAX_LINE_LENGTH + 1];
220
0
    long dollar_offset;
221
0
    packet_direction_t direction;
222
0
    bool is_text_data;
223
0
    log3gpp_t *log3gpp = (log3gpp_t *)wth->priv;
224
225
    /* Search for a line containing a usable packet */
226
0
    while (1)
227
0
    {
228
0
        int line_length, seconds, useconds, data_chars;
229
0
        int64_t this_offset = offset;
230
231
        /* Are looking for first packet after 2nd line */
232
0
        if (file_tell(wth->fh) == 0)
233
0
        {
234
0
            this_offset += (int64_t)first_packet_offset +1+1;
235
0
        }
236
237
        /* Clear errno before reading from the file */
238
0
        errno = 0;
239
240
        /* Read a new line from file into linebuff */
241
0
        if (!read_new_line(wth->fh, &line_length, linebuff,
242
0
            sizeof linebuff, err, err_info)) {
243
0
            if (*err != 0) {
244
0
                return false;  /* error */
245
0
            }
246
            /* No more lines can be read, so quit. */
247
0
            break;
248
0
        }
249
250
        /* Try to parse the line as a frame record */
251
0
        if (parse_line(linebuff, line_length, &seconds, &useconds,
252
0
                       &dollar_offset,
253
0
                       &data_chars,
254
0
                       &direction,
255
0
                       &is_text_data))
256
0
        {
257
0
            unsigned char *frame_buffer;
258
0
            int n;
259
0
            int stub_offset = 0;
260
0
            char timestamp_string[MAX_TIMESTAMP_LEN+1];
261
            /*not used int64_t *pkey = NULL;*/
262
263
0
            snprintf(timestamp_string, 32, "%d.%04d", seconds, useconds/100);
264
265
            /* All packets go to 3GPP protocol stub dissector */
266
0
            rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_LOG_3GPP;
267
0
            rec->rec_type = REC_TYPE_PACKET;
268
0
            rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
269
0
            rec->presence_flags = WTAP_HAS_TS;
270
271
            /* Set data_offset to the beginning of the line we're returning.
272
               This will be the seek_off parameter when this frame is re-read.
273
            */
274
0
            *data_offset = this_offset;
275
276
            /* Fill in timestamp (capture base + packet offset) */
277
0
            rec->ts.secs = log3gpp->start_secs + seconds;
278
0
            if ((log3gpp->start_usecs + useconds) >= 1000000)
279
0
            {
280
0
                rec->ts.secs++;
281
0
            }
282
0
            rec->ts.nsecs =
283
0
                ((log3gpp->start_usecs + useconds) % 1000000) *1000;
284
285
0
            if (!is_text_data)
286
0
            {
287
              /* Get buffer pointer ready */
288
0
              ws_buffer_assure_space(&rec->data,
289
0
                                  strlen(timestamp_string)+1 + /* timestamp */
290
0
                                  strlen(protocol_name)+1 +    /* Protocol name */
291
0
                                  1 +                          /* direction */
292
0
                                  (size_t)(data_chars/2));
293
294
0
              frame_buffer = ws_buffer_start_ptr(&rec->data);
295
              /*********************/
296
              /* Write stub header */
297
0
              stub_offset = write_stub_header(frame_buffer, timestamp_string,
298
0
                                              direction);
299
300
              /* Binary data length is half bytestring length + stub header */
301
0
              rec->rec_header.packet_header.len = data_chars/2 + stub_offset;
302
0
              rec->rec_header.packet_header.caplen = data_chars/2 + stub_offset;
303
              /********************************/
304
              /* Copy packet data into buffer */
305
0
              for (n=0; n <= data_chars; n+=2)
306
0
              {
307
0
                frame_buffer[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
308
0
                                                   hex_from_char(linebuff[dollar_offset+n+1]);
309
0
              }
310
0
              *err = errno = 0;
311
0
              return true;
312
0
            }
313
0
            else
314
0
            {
315
              /* Get buffer pointer ready */
316
0
              ws_buffer_assure_space(&rec->data,
317
0
                                  strlen(timestamp_string)+1 + /* timestamp */
318
0
                                  strlen(protocol_name)+1 +    /* Protocol name */
319
0
                                  1 +                          /* direction */
320
0
                                  data_chars);
321
0
              frame_buffer = ws_buffer_start_ptr(&rec->data);
322
323
              /*********************/
324
              /* Write stub header */
325
0
              stub_offset = write_stub_header(frame_buffer, timestamp_string,
326
0
                                              direction);
327
328
              /* Binary data length is bytestring length + stub header */
329
0
              rec->rec_header.packet_header.len = data_chars + stub_offset;
330
0
              rec->rec_header.packet_header.caplen = data_chars + stub_offset;
331
332
              /* do not convert the ascii char */
333
0
              memcpy(&frame_buffer[stub_offset],&linebuff[dollar_offset],data_chars);
334
0
              frame_buffer[stub_offset+data_chars-1]= '\0';
335
0
              *err = errno = 0;
336
0
              return true;
337
0
            }
338
0
        }
339
0
    }
340
341
    /* No packet details to return... */
342
0
    *err = errno;
343
0
    return false;
344
0
}
345
346
347
/**************************************************/
348
/* Read & seek function.                          */
349
/**************************************************/
350
static bool
351
log3gpp_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
352
                    int *err, char **err_info)
353
0
{
354
0
    long dollar_offset;
355
0
    static char linebuff[MAX_LINE_LENGTH + 1];
356
0
    packet_direction_t direction;
357
0
    int seconds, useconds, data_chars;
358
0
    bool is_text_data;
359
0
    log3gpp_t* log3gpp = (log3gpp_t*)wth->priv;
360
0
    int length = 0;
361
0
    unsigned char *frame_buffer;
362
363
    /* Reset errno */
364
0
    *err = errno = 0;
365
366
    /* Seek to beginning of packet */
367
0
    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
368
0
    {
369
0
        return false;
370
0
    }
371
372
    /* Re-read whole line (this really should succeed) */
373
0
    if (!read_new_line(wth->random_fh, &length, linebuff,
374
0
        sizeof linebuff, err, err_info)) {
375
0
        return false;
376
0
    }
377
378
    /* Try to parse this line again (should succeed as re-reading...) */
379
0
    if (parse_line(linebuff, length, &seconds, &useconds,
380
0
                   &dollar_offset,
381
0
                   &data_chars,
382
0
                   &direction,
383
0
                   &is_text_data))
384
0
    {
385
0
        int n;
386
0
        int stub_offset = 0;
387
0
        char timestamp_string[32];
388
0
        snprintf(timestamp_string, 32, "%d.%04d", seconds, useconds/100);
389
390
        /* Make sure all packets go to log3gpp dissector */
391
0
        rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_LOG_3GPP;
392
0
        rec->rec_type = REC_TYPE_PACKET;
393
0
        rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
394
0
        rec->presence_flags = WTAP_HAS_TS;
395
396
        /* Fill in timestamp (capture base + packet offset) */
397
0
        rec->ts.secs = log3gpp->start_secs + seconds;
398
0
        if ((log3gpp->start_usecs + useconds) >= 1000000)
399
0
        {
400
0
            rec->ts.secs++;
401
0
        }
402
0
        rec->ts.nsecs =
403
0
            ((log3gpp->start_usecs + useconds) % 1000000) * 1000;
404
405
        /*********************/
406
        /* Write stub header */
407
0
        ws_buffer_assure_space(&rec->data,
408
0
                               strlen(timestamp_string)+1 + /* timestamp */
409
0
                               strlen(protocol_name)+1 +    /* Protocol name */
410
0
                               1 +                          /* direction */
411
0
                               data_chars);
412
0
        frame_buffer = ws_buffer_start_ptr(&rec->data);
413
0
        stub_offset = write_stub_header(frame_buffer, timestamp_string,
414
0
                                        direction);
415
416
0
        if (!is_text_data)
417
0
        {
418
          /********************************/
419
          /* Copy packet data into buffer */
420
0
          for (n=0; n <= data_chars; n+=2)
421
0
          {
422
0
            frame_buffer[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
423
0
                                               hex_from_char(linebuff[dollar_offset+n+1]);
424
0
          }
425
0
          *err = errno = 0;
426
0
          return true;
427
0
        }
428
0
        else
429
0
        {
430
          /* do not convert the ascii char */
431
0
          memcpy(&frame_buffer[stub_offset],&linebuff[dollar_offset],data_chars);
432
0
          frame_buffer[stub_offset+data_chars-1] = '\0';
433
0
          *err = errno = 0;
434
0
          return true;
435
0
        }
436
0
    }
437
438
    /* If get here, must have failed */
439
0
    *err = errno;
440
0
    *err_info = ws_strdup_printf("prot 3gpp: seek_read failed to read/parse "
441
0
                                "line at position %" PRId64,
442
0
                                seek_off);
443
0
    return false;
444
0
}
445
446
/****************************/
447
/* Private helper functions */
448
/****************************/
449
450
/**********************************************************************/
451
/* Read a new line from the file, starting at offset.                 */
452
/* - writes data to static var linebuff                               */
453
/* - on return 'offset' will point to the next position to read from  */
454
/* - return true if this read is successful                           */
455
/**********************************************************************/
456
static bool
457
read_new_line(FILE_T fh, int* length,
458
    char* linebuff, size_t linebuffsize, int* err, char** err_info)
459
0
{
460
    /* Read in a line */
461
0
    int64_t pos_before = file_tell(fh);
462
463
0
    if (file_gets(linebuff, (int)linebuffsize - 1, fh) == NULL) {
464
        /* No characters found, or error */
465
0
        *err = file_error(fh, err_info);
466
0
        return false;
467
0
    }
468
469
    /* Set length (avoiding strlen()) and offset.. */
470
0
    *length = (int)(file_tell(fh) - pos_before);
471
472
    /* ...but don't want to include newline in line length */
473
0
    if (*length > 0 && linebuff[*length - 1] == '\n') {
474
0
        linebuff[*length - 1] = '\0';
475
0
        *length = *length - 1;
476
0
    }
477
    /* Nor do we want '\r' (as will be written when log is created on windows) */
478
0
    if (*length > 0 && linebuff[*length - 1] == '\r') {
479
0
        linebuff[*length - 1] = '\0';
480
0
        *length = *length - 1;
481
0
    }
482
483
0
    return true;
484
0
}
485
486
487
/**********************************************************************/
488
/* Parse a line from buffer, by identifying:                          */
489
/* - timestamp                                                        */
490
/* - data position and length                                         */
491
/* Return true if this packet looks valid and can be displayed        */
492
/**********************************************************************/
493
bool parse_line(char* linebuff, int line_length, int *seconds, int *useconds,
494
                    long *data_offset, int *data_chars,
495
                    packet_direction_t *direction,
496
                    bool *is_text_data)
497
0
{
498
0
    int  n = 0;
499
0
    int  protocol_chars = 0;
500
0
    int  prot_option_chars = 0;
501
0
    char seconds_buff[MAX_SECONDS_CHARS+1];
502
0
    int  seconds_chars;
503
0
    char subsecond_decimals_buff[MAX_SUBSECOND_DECIMALS];
504
0
    int  subsecond_decimals_chars;
505
506
    /*********************************************************************/
507
    /* Find and read the timestamp                                       */
508
    /*********************************************************************/
509
    /* Now scan to the next digit, which should be the start of the timestamp */
510
0
    for (; !g_ascii_isdigit((unsigned char)linebuff[n]) && (n < line_length); n++);
511
0
    if (n >= line_length)
512
0
    {
513
0
        return false;
514
0
    }
515
516
    /* Seconds */
517
0
    for (seconds_chars = 0;
518
0
         (linebuff[n] != '.') &&
519
0
         (seconds_chars <= MAX_SECONDS_CHARS) &&
520
0
         (n < line_length);
521
0
         n++, seconds_chars++)
522
0
    {
523
0
        if (!g_ascii_isdigit((unsigned char)linebuff[n]))
524
0
        {
525
            /* Found a non-digit before decimal point. Fail */
526
0
            return false;
527
0
        }
528
0
        seconds_buff[seconds_chars] = linebuff[n];
529
0
    }
530
0
    if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length)
531
0
    {
532
        /* Didn't fit in buffer.  Fail rather than use truncated */
533
0
        return false;
534
0
    }
535
536
    /* Convert found value into number */
537
0
    seconds_buff[seconds_chars] = '\0';
538
539
    /* Already know they are digits, so avoid expense of ws_strtoi32() */
540
0
    int multiplier = 1;
541
0
    *seconds = 0;
542
0
    for (int d = seconds_chars - 1; d >= 0; d--) {
543
0
        *seconds += ((seconds_buff[d] - '0') * multiplier);
544
0
        multiplier *= 10;
545
0
    }
546
547
    /* The decimal point must follow the last of the seconds digits */
548
0
    if (linebuff[n] != '.')
549
0
    {
550
0
        return false;
551
0
    }
552
    /* Skip it */
553
0
    n++;
554
555
    /* Subsecond decimal digits (expect 4-digit accuracy) */
556
0
    for (subsecond_decimals_chars = 0;
557
0
         (linebuff[n] != ' ') && (subsecond_decimals_chars < MAX_SUBSECOND_DECIMALS) && (n < line_length);
558
0
         n++, subsecond_decimals_chars++)
559
0
    {
560
0
        if (!g_ascii_isdigit((unsigned char)linebuff[n]))
561
0
        {
562
0
            return false;
563
0
        }
564
0
        subsecond_decimals_buff[subsecond_decimals_chars] = linebuff[n];
565
0
    }
566
567
0
    if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length)
568
0
    {
569
        /* More numbers than expected - give up */
570
0
        return false;
571
0
    }
572
573
    /* Convert found value into microseconds */
574
0
    while (subsecond_decimals_chars < MAX_SUBSECOND_DECIMALS) {
575
0
        subsecond_decimals_buff[subsecond_decimals_chars++] = '0';
576
0
    }
577
    /* Already know they are digits, so avoid expense of ws_strtoi32() */
578
0
    *useconds = ((subsecond_decimals_buff[0] - '0') * 100000) +
579
0
                ((subsecond_decimals_buff[1] - '0') * 10000) +
580
0
                ((subsecond_decimals_buff[2] - '0') * 1000) +
581
0
                ((subsecond_decimals_buff[3] - '0') * 100);
582
583
    /* Space character must follow end of timestamp */
584
0
    if (linebuff[n] != ' ')
585
0
    {
586
0
        return false;
587
0
    }
588
0
    n++;
589
590
    /*********************************************************************/
591
    /* Find and read protocol name                                       */
592
    /*********************************************************************/
593
0
    for (protocol_chars = 0;
594
0
         (linebuff[n] != ' ') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
595
0
         n++, protocol_chars++)
596
0
    {
597
0
        if (!g_ascii_isalnum((unsigned char)linebuff[n]) && linebuff[n] != '_' && linebuff[n] != '.' && linebuff[n] != '-')
598
0
        {
599
0
            return false;
600
0
        }
601
0
        protocol_name[protocol_chars] = linebuff[n];
602
0
    }
603
0
    if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length)
604
0
    {
605
        /* If doesn't fit, fail rather than truncate */
606
0
        return false;
607
0
    }
608
0
    protocol_name[protocol_chars] = '\0';
609
610
    /* Space char must follow protocol name */
611
0
    if (linebuff[n] != ' ')
612
0
    {
613
0
        return false;
614
0
    }
615
    /* Skip it */
616
0
    n++;
617
618
    /* Scan ahead to the next space */
619
0
    for (; (!g_ascii_isalnum((unsigned char)linebuff[n])) && (n < line_length); n++);
620
0
    if (n >= line_length)
621
0
    {
622
0
        return false;
623
0
    }
624
625
626
0
    if (strcmp(protocol_name,"TXT") == 0)
627
0
    {
628
0
      *direction = uplink;
629
0
      *data_offset = n;
630
0
      *data_chars = line_length - n;
631
0
      *is_text_data = true;
632
0
    }
633
0
    else
634
0
    {
635
      /* Next character gives direction of message (must be 'u' or 'd') */
636
0
      if (linebuff[n] == 'u')
637
0
      {
638
0
        *direction = uplink;
639
0
      }
640
0
      else if (linebuff[n] == 'd')
641
0
      {
642
0
        *direction = downlink;
643
0
      }
644
0
      else
645
0
      {
646
0
        return false;
647
0
      }
648
0
      n++;
649
650
      /* Now skip ahead to find start of data (marked by '$') */
651
0
      for (; (n < line_length) && (linebuff[n] != '$') && (prot_option_chars < MAX_PROTOCOL_PAR_STRING);
652
0
           n++,prot_option_chars++)
653
0
      {
654
0
        protocol_parameters[prot_option_chars] = linebuff[n];
655
0
      }
656
0
      protocol_parameters[prot_option_chars] = '\0';
657
0
      if (prot_option_chars == MAX_PROTOCOL_PAR_STRING || n >= line_length)
658
0
      {
659
        /* If doesn't fit, fail rather than truncate */
660
0
        return false;
661
0
      }
662
663
      /* Skip it */
664
0
      n++;
665
666
    /* Set offset to data start within line */
667
0
    *data_offset = n;
668
669
    /* Set number of chars that comprise the hex string protocol data */
670
0
    *data_chars = line_length - n;
671
672
0
    *is_text_data = false;
673
0
    }
674
0
    return true;
675
0
}
676
677
/*****************************************************************/
678
/* Write the stub info to the data buffer while reading a packet */
679
/*****************************************************************/
680
int write_stub_header(unsigned char *frame_buffer, char *timestamp_string,
681
                      packet_direction_t direction)
682
0
{
683
0
    int stub_offset = 0;
684
685
    /* Timestamp within file */
686
0
    (void) g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
687
0
    stub_offset += (int)(strlen(timestamp_string) + 1);
688
689
    /* Protocol name */
690
0
    (void) g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
691
0
    stub_offset += (int)(strlen(protocol_name) + 1);
692
693
    /* Direction */
694
0
    frame_buffer[stub_offset] = direction;
695
0
    stub_offset++;
696
697
    /* Option string (might be string of length 0) */
698
0
    (void) g_strlcpy((char*)&frame_buffer[stub_offset], protocol_parameters,MAX_PROTOCOL_PAR_STRING+1);
699
0
    stub_offset += (int)(strlen(protocol_parameters) + 1);
700
0
    return stub_offset;
701
0
}
702
703
704
/********************************************************/
705
/* Return hex nibble equivalent of hex string character */
706
/********************************************************/
707
unsigned char hex_from_char(char c)
708
0
{
709
0
    if ((c >= '0') && (c <= '9'))
710
0
    {
711
0
        return c - '0';
712
0
    }
713
714
0
    if ((c >= 'a') && (c <= 'f'))
715
0
    {
716
0
        return 0x0a + (c - 'a');
717
0
    }
718
719
0
    if ((c >= 'A') && (c <= 'F'))
720
0
    {
721
0
        return 0x0a + (c - 'A');
722
0
    }
723
    /* Not a valid hex string character */
724
0
    return 0xff;
725
0
}
726
727
728
/********************************************************/
729
/* Return character corresponding to hex nibble value   */
730
/********************************************************/
731
/*char char_from_hex(unsigned char hex)
732
{
733
    static char hex_lookup[16] =
734
    { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
735
736
    if (hex > 15)
737
    {
738
        return '?';
739
    }
740
741
    return hex_lookup[hex];
742
}*/
743
744
/************************************************************************/
745
/* Parse year, month, day, hour, minute, seconds out of formatted line. */
746
/* Set secs and usecs as output                                         */
747
/* Return false if no valid time can be read                            */
748
/************************************************************************/
749
bool get_file_time_stamp(const char* linebuff, time_t *secs, uint32_t *usecs)
750
0
{
751
0
    int n;
752
0
    struct tm tm;
753
0
    #define MAX_MONTH_LETTERS 9
754
0
    char month[MAX_MONTH_LETTERS+1];
755
756
0
    int day, year, hour, minute, second;
757
0
    int scan_found;
758
759
    /* If line longer than expected, file is probably not correctly formatted */
760
0
    if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH)
761
0
    {
762
0
        return false;
763
0
    }
764
765
    /**************************************************************/
766
    /* First is month. Read until get a space following the month */
767
0
    for (n=0; (n < MAX_MONTH_LETTERS) && (linebuff[n] != ' '); n++)
768
0
    {
769
0
        month[n] = linebuff[n];
770
0
    }
771
0
    month[n] = '\0';
772
773
0
    if      (strcmp(month, "January"  ) == 0)  tm.tm_mon = 0;
774
0
    else if (strcmp(month, "February" ) == 0)  tm.tm_mon = 1;
775
0
    else if (strcmp(month, "March"    ) == 0)  tm.tm_mon = 2;
776
0
    else if (strcmp(month, "April"    ) == 0)  tm.tm_mon = 3;
777
0
    else if (strcmp(month, "May"      ) == 0)  tm.tm_mon = 4;
778
0
    else if (strcmp(month, "June"     ) == 0)  tm.tm_mon = 5;
779
0
    else if (strcmp(month, "July"     ) == 0)  tm.tm_mon = 6;
780
0
    else if (strcmp(month, "August"   ) == 0)  tm.tm_mon = 7;
781
0
    else if (strcmp(month, "September") == 0)  tm.tm_mon = 8;
782
0
    else if (strcmp(month, "October"  ) == 0)  tm.tm_mon = 9;
783
0
    else if (strcmp(month, "November" ) == 0)  tm.tm_mon = 10;
784
0
    else if (strcmp(month, "December" ) == 0)  tm.tm_mon = 11;
785
0
    else
786
0
    {
787
        /* Give up if not found a properly-formatted date */
788
0
        return false;
789
0
    }
790
    /* Skip space char */
791
0
    n++;
792
793
    /********************************************************/
794
    /* Scan for remaining numerical fields                  */
795
0
    scan_found = sscanf(linebuff+n, "%d, %d     %d:%d:%d.%u",
796
0
                        &day, &year, &hour, &minute, &second, usecs);
797
0
    if (scan_found != 6)
798
0
    {
799
        /* Give up if not all found */
800
0
        return false;
801
0
    }
802
803
    /******************************************************/
804
    /* Fill in remaining fields and return it in a time_t */
805
0
    tm.tm_year = year - 1900;
806
0
    tm.tm_mday = day;
807
0
    tm.tm_hour = hour;
808
0
    tm.tm_min = minute;
809
0
    tm.tm_sec = second;
810
0
    tm.tm_isdst = -1;    /* daylight saving time info not known */
811
812
    /* Get seconds from this time */
813
0
    *secs = mktime(&tm);
814
815
    /* Multiply 4 digits given to get micro-seconds */
816
0
    *usecs = *usecs * 100;
817
818
0
    return true;
819
0
}
820
821
static const struct supported_block_type log3gpp_blocks_supported[] = {
822
    /*
823
     * We support packet blocks, with no comments or other options.
824
     */
825
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
826
};
827
828
static const struct file_type_subtype_info log3gpp_info = {
829
    "3GPP Log", "3gpp_log", "*.log", NULL,
830
    true, BLOCKS_SUPPORTED(log3gpp_blocks_supported),
831
    NULL, NULL, NULL
832
};
833
834
void register_log3gpp(void)
835
8
{
836
8
    log3gpp_file_type_subtype = wtap_register_file_type_subtype(&log3gpp_info);
837
838
    /*
839
     * Register name for backwards compatibility with the
840
     * wtap_filetypes table in Lua.
841
     */
842
8
    wtap_register_backwards_compatibility_lua_name("LOG_3GPP",
843
8
                                                   log3gpp_file_type_subtype);
844
8
}
845
846
/*
847
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
848
 *
849
 * Local variables:
850
 * c-basic-offset: 4
851
 * tab-width: 8
852
 * indent-tabs-mode: nil
853
 * End:
854
 *
855
 * vi: set shiftwidth=4 tabstop=8 expandtab:
856
 * :indentSize=4:tabSize=8:noTabs=true:
857
 */