Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/pppdump.c
Line
Count
Source
1
/* pppdump.c
2
 *
3
 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4
 *
5
 * SPDX-License-Identifier: GPL-2.0-or-later
6
 */
7
8
#include "config.h"
9
#include "pppdump.h"
10
#include "wtap_module.h"
11
#include "file_wrappers.h"
12
13
#include <stdlib.h>
14
#include <errno.h>
15
#include <string.h>
16
17
#include <wsutil/array.h>
18
#include <wsutil/ws_assert.h>
19
#include <wsutil/pint.h>
20
21
/*
22
pppdump records
23
Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
24
25
+------+
26
| 0x07 |                              Reset time
27
+------+------+------+------+
28
|  t3  |  t2  |  t1  |  t0  |         t = time_t
29
+------+------+------+------+
30
31
+------+
32
| 0x06 |                              Time step (short)
33
+------+
34
|  ts  |                              ts = time step (tenths of seconds)
35
+------+
36
37
+------+
38
| 0x05 |                              Time step (long)
39
+------+------+------+------+
40
| ts3  | ts2  | ts1  | ts0  |         ts = time step (tenths of seconds)
41
+------+------+------+------+
42
43
+------+
44
| 0x04 |                              Receive delimiter (not seen in practice)
45
+------+
46
47
+------+
48
| 0x03 |                              Send delimiter (not seen in practice)
49
+------+
50
51
+------+
52
| 0x02 |                              Received data
53
+------+------+
54
|  n1  |  n0  |                       n = number of bytes following
55
+------+------+
56
|    data     |
57
|             |
58
59
+------+
60
| 0x01 |                              Sent data
61
+------+------+
62
|  n1  |  n0  |                       n = number of bytes following
63
+------+------+
64
|    data     |
65
|             |
66
*/
67
68
0
#define PPPD_SENT_DATA    0x01
69
0
#define PPPD_RECV_DATA    0x02
70
0
#define PPPD_SEND_DELIM   0x03
71
0
#define PPPD_RECV_DELIM   0x04
72
0
#define PPPD_TIME_STEP_LONG 0x05
73
0
#define PPPD_TIME_STEP_SHORT  0x06
74
0
#define PPPD_RESET_TIME   0x07
75
76
/* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
77
 * sizeof(lcp_header) + sizeof(ipcp_header).  PPPD_MTU is *very* rarely
78
 * larger than 1500 so this value is fine.
79
 *
80
 * It's less than WTAP_MAX_PACKET_SIZE_STANDARD, so we don't have to worry about
81
 * too-large packets.
82
 */
83
0
#define PPPD_BUF_SIZE   8192
84
85
typedef enum {
86
  DIRECTION_SENT,
87
  DIRECTION_RECV
88
} direction_enum;
89
90
static bool pppdump_read(wtap *wth, wtap_rec *rec,
91
  int *err, char **err_info, int64_t *data_offset);
92
static bool pppdump_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
93
        int *err, char **err_info);
94
95
static int pppdump_file_type_subtype = -1;
96
97
void register_pppdump(void);
98
99
/*
100
 * Information saved about a packet, during the initial sequential pass
101
 * through the file, to allow us to later re-read it when randomly
102
 * reading packets.
103
 *
104
 * "offset" is the offset in the file of the first data chunk containing data
105
 * from that packet; note that it may also contain data from previous
106
 * packets.
107
 *
108
 * "num_bytes_to_skip" is the number of bytes from previous packets in that
109
 * first data chunk.
110
 *
111
 * "dir" is the direction of the packet.
112
 */
113
typedef struct {
114
  int64_t   offset;
115
  int64_t   num_bytes_to_skip;
116
  direction_enum  dir;
117
} pkt_id;
118
119
/*
120
 * Information about a packet currently being processed.  There is one of
121
 * these for the sent packet being processed and one of these for the
122
 * received packet being processed, as we could be in the middle of
123
 * processing both a received packet and a sent packet.
124
 *
125
 * "dir" is the direction of the packet.
126
 *
127
 * "cnt" is the number of bytes of packet data we've accumulated.
128
 *
129
 * "esc" is true if the next byte we see is escaped (and thus must be XORed
130
 * with 0x20 before saving it), false otherwise.
131
 *
132
 * "buf" is a buffer containing the packet data we've accumulated.
133
 *
134
 * "id_offset" is the offset in the file of the first data chunk
135
 * containing data from the packet we're processing.
136
 *
137
 * "sd_offset" is the offset in the file of the first data byte from
138
 * the packet we're processing - which isn't necessarily right after
139
 * the header of the first data chunk, as we may already have assembled
140
 * packets from that chunk.
141
 *
142
 * "cd_offset" is the offset in the file of the current data chunk we're
143
 * processing.
144
 */
145
typedef struct {
146
  direction_enum  dir;
147
  int   cnt;
148
  bool  esc;
149
  uint8_t   buf[PPPD_BUF_SIZE];
150
  int64_t   id_offset;
151
  int64_t   sd_offset;
152
  int64_t   cd_offset;
153
} pkt_t;
154
155
/*
156
 * This keeps state used while processing records.
157
 *
158
 * "timestamp" is the seconds portion of the current time stamp value,
159
 * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
160
 * PPPD_TIME_STEP_SHORT records.  "tenths" is the tenths-of-seconds
161
 * portion.
162
 *
163
 * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
164
 * packets we're currently working on.
165
 *
166
 * "offset" is the current offset in the file.
167
 *
168
 * "num_bytes" and "pkt" are information saved when we finish accumulating
169
 * the data for a packet, if the data chunk we're working on still has more
170
 * data in it:
171
 *
172
 *  "num_bytes" is the number of bytes of additional data remaining
173
 *  in the chunk after we've finished accumulating the data for the
174
 *  packet.
175
 *
176
 *  "pkt" is the "pkt_t" for the type of packet the data chunk is for
177
 *  (sent or received packet).
178
 *
179
 * "seek_state" is another state structure used while processing records
180
 * when doing a seek-and-read.  (That structure doesn't itself have a
181
 * "seek_state" structure.)
182
 *
183
 * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
184
 * packets we've seen during the initial sequential pass, to allow us to
185
 * later retrieve them with random accesses.
186
 *
187
 * "pkt_cnt" is the number of packets we've seen up to this point in the
188
 * sequential pass.
189
 */
190
typedef struct _pppdump_t {
191
  time_t      timestamp;
192
  unsigned      tenths;
193
  pkt_t     spkt;
194
  pkt_t     rpkt;
195
  int64_t     offset;
196
  int     num_bytes;
197
  pkt_t     *pkt;
198
  struct _pppdump_t *seek_state;
199
  GPtrArray   *pids;
200
  unsigned      pkt_cnt;
201
} pppdump_t;
202
203
static int
204
process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, uint8_t *pd,
205
    int *err, char **err_info, pkt_id *pid);
206
207
static bool
208
collate(pppdump_t *state, FILE_T fh, int *err, char **err_info, uint8_t *pd,
209
    int *num_bytes, direction_enum *direction, pkt_id *pid,
210
    int64_t num_bytes_to_skip);
211
212
static void
213
pppdump_close(wtap *wth);
214
215
static void
216
init_state(pppdump_t *state)
217
0
{
218
219
0
  state->num_bytes = 0;
220
0
  state->pkt = NULL;
221
222
0
  state->spkt.dir = DIRECTION_SENT;
223
0
  state->spkt.cnt = 0;
224
0
  state->spkt.esc = false;
225
0
  state->spkt.id_offset = 0;
226
0
  state->spkt.sd_offset = 0;
227
0
  state->spkt.cd_offset = 0;
228
229
0
  state->rpkt.dir = DIRECTION_RECV;
230
0
  state->rpkt.cnt = 0;
231
0
  state->rpkt.esc = false;
232
0
  state->rpkt.id_offset = 0;
233
0
  state->rpkt.sd_offset = 0;
234
0
  state->rpkt.cd_offset = 0;
235
236
0
  state->seek_state = NULL;
237
0
  state->offset = 0x100000; /* to detect errors during development */
238
0
}
239
240
241
wtap_open_return_val
242
pppdump_open(wtap *wth, int *err, char **err_info)
243
0
{
244
0
  uint8_t   buffer[6];  /* Looking for: 0x07 t3 t2 t1 t0 ID */
245
0
  pppdump_t *state;
246
247
  /* There is no file header, only packet records. Fortunately for us,
248
  * timestamp records are separated from packet records, so we should
249
  * find an "initial time stamp" (i.e., a "reset time" record, or
250
  * record type 0x07) at the beginning of the file. We'll check for
251
  * that, plus a valid record following the 0x07 and the four bytes
252
  * representing the timestamp.
253
  */
254
255
0
  if (!wtap_read_bytes(wth->fh, buffer, sizeof(buffer),
256
0
      err, err_info)) {
257
0
    if (*err != WTAP_ERR_SHORT_READ)
258
0
      return WTAP_OPEN_ERROR;
259
0
    return WTAP_OPEN_NOT_MINE;
260
0
  }
261
262
0
  if (buffer[0] == PPPD_RESET_TIME &&
263
0
      (buffer[5] == PPPD_SENT_DATA ||
264
0
       buffer[5] == PPPD_RECV_DATA ||
265
0
       buffer[5] == PPPD_TIME_STEP_LONG ||
266
0
       buffer[5] == PPPD_TIME_STEP_SHORT ||
267
0
       buffer[5] == PPPD_RESET_TIME)) {
268
269
0
    goto my_file_type;
270
0
  }
271
0
  else {
272
0
    return WTAP_OPEN_NOT_MINE;
273
0
  }
274
275
0
  my_file_type:
276
277
0
  if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
278
0
    return WTAP_OPEN_ERROR;
279
280
0
  state = g_new(pppdump_t, 1);
281
0
  wth->priv = (void *)state;
282
0
  state->timestamp = pntohu32(&buffer[1]);
283
0
  state->tenths = 0;
284
285
0
  init_state(state);
286
287
0
  state->offset = 5;
288
0
  wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
289
0
  wth->file_type_subtype = pppdump_file_type_subtype;
290
291
0
  wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
292
0
  wth->subtype_read = pppdump_read;
293
0
  wth->subtype_seek_read = pppdump_seek_read;
294
0
  wth->subtype_close = pppdump_close;
295
0
  wth->file_tsprec = WTAP_TSPREC_100_MSEC;
296
297
0
  state->seek_state = g_new(pppdump_t,1);
298
299
  /* If we have a random stream open, we're going to be reading
300
     the file randomly; set up a GPtrArray of pointers to
301
     information about how to retrieve the data for each packet. */
302
0
  if (wth->random_fh != NULL)
303
0
    state->pids = g_ptr_array_new();
304
0
  else
305
0
    state->pids = NULL;
306
0
  state->pkt_cnt = 0;
307
308
  /*
309
   * Add an IDB; we don't know how many interfaces were
310
   * involved, so we just say one interface, about which
311
   * we only know the link-layer type, snapshot length,
312
   * and time stamp resolution.
313
   */
314
0
  wtap_add_generated_idb(wth);
315
316
0
  return WTAP_OPEN_MINE;
317
0
}
318
319
/* Set part of the struct wtap_rec. */
320
static void
321
pppdump_set_phdr(wtap *wth, wtap_rec *rec, int num_bytes, direction_enum direction)
322
0
{
323
0
  wtap_setup_packet_rec(rec, wth->file_encap);
324
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
325
0
  rec->rec_header.packet_header.len = num_bytes;
326
0
  rec->rec_header.packet_header.caplen = num_bytes;
327
328
0
  rec->rec_header.packet_header.pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? true : false);
329
0
}
330
331
/* Find the next packet and parse it; called from wtap_read(). */
332
static bool
333
pppdump_read(wtap *wth, wtap_rec *rec, int *err, char **err_info,
334
    int64_t *data_offset)
335
0
{
336
0
  int   num_bytes;
337
0
  direction_enum  direction;
338
0
  pppdump_t *state;
339
0
  pkt_id    *pid;
340
341
0
  state = (pppdump_t *)wth->priv;
342
343
  /* If we have a random stream open, allocate a structure to hold
344
     the information needed to read this packet's data again. */
345
0
  if (wth->random_fh != NULL) {
346
0
    pid = g_new(pkt_id, 1);
347
0
    if (!pid) {
348
0
      *err = errno;  /* assume a malloc failed and set "errno" */
349
0
      return false;
350
0
    }
351
0
    pid->offset = 0;
352
0
  } else
353
0
    pid = NULL; /* sequential only */
354
355
0
  ws_buffer_assure_space(&rec->data, PPPD_BUF_SIZE);
356
0
  if (!collate(state, wth->fh, err, err_info, ws_buffer_start_ptr(&rec->data),
357
0
      &num_bytes, &direction, pid, 0)) {
358
0
    g_free(pid);
359
0
    return false;
360
0
  }
361
362
0
  if (pid != NULL)
363
0
    pid->dir = direction;
364
365
0
  if (pid != NULL)
366
0
    g_ptr_array_add(state->pids, pid);
367
  /* The user's data_offset is not really an offset, but a packet number. */
368
0
  *data_offset = state->pkt_cnt;
369
0
  state->pkt_cnt++;
370
371
0
  pppdump_set_phdr(wth, rec, num_bytes, direction);
372
0
  rec->presence_flags = WTAP_HAS_TS;
373
0
  rec->ts.secs = state->timestamp;
374
0
  rec->ts.nsecs = state->tenths * 100000000;
375
376
0
  return true;
377
0
}
378
379
/* Returns number of bytes copied for record, -1 if failure.
380
 *
381
 * This is modeled after pppdump.c, the utility to parse pppd log files; it
382
 * comes with the ppp distribution.
383
 */
384
static int
385
process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, uint8_t *pd,
386
    int *err, char **err_info, pkt_id *pid)
387
0
{
388
0
  int c;
389
0
  int num_bytes = n;
390
0
  int num_written;
391
392
0
  for (; num_bytes > 0; --num_bytes) {
393
0
    c = file_getc(fh);
394
0
    if (c == EOF) {
395
0
      *err = file_error(fh, err_info);
396
0
      if (*err == 0) {
397
0
        *err = WTAP_ERR_SHORT_READ;
398
0
      }
399
0
      return -1;
400
0
    }
401
0
    state->offset++;
402
0
    switch (c) {
403
0
      case 0x7e:
404
        /*
405
         * Flag Sequence for RFC 1662 HDLC-like
406
         * framing.
407
         *
408
         * As this is a raw trace of octets going
409
         * over the wire, and that might include
410
         * the login sequence, there is no
411
         * guarantee that *only* PPP traffic
412
         * appears in this file, so there is no
413
         * guarantee that the first 0x7e we see is
414
         * a start flag sequence, and therefore we
415
         * cannot safely ignore all characters up
416
         * to the first 0x7e, and therefore we
417
         * might end up with some bogus PPP
418
         * packets.
419
         */
420
0
        if (pkt->cnt > 0) {
421
          /*
422
           * We've seen stuff before this,
423
           * so this is the end of a frame.
424
           * Make a frame out of that stuff.
425
           */
426
0
          pkt->esc = false;
427
428
0
          num_written = pkt->cnt;
429
0
          pkt->cnt = 0;
430
0
          if (num_written <= 0) {
431
0
            return 0;
432
0
          }
433
434
0
          if (num_written > PPPD_BUF_SIZE) {
435
0
            *err = WTAP_ERR_BAD_FILE;
436
0
            *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
437
0
                num_written, PPPD_BUF_SIZE);
438
0
            return -1;
439
0
          }
440
441
0
          memcpy(pd, pkt->buf, num_written);
442
443
          /*
444
           * Remember the offset of the
445
           * first record containing data
446
           * for this packet, and how far
447
           * into that record to skip to
448
           * get to the beginning of the
449
           * data for this packet; the number
450
           * of bytes to skip into that record
451
           * is the file offset of the first
452
           * byte of this packet minus the
453
           * file offset of the first byte of
454
           * this record, minus 3 bytes for the
455
           * header of this record (which, if
456
           * we re-read this record, we will
457
           * process, not skip).
458
           */
459
0
          if (pid) {
460
0
            pid->offset = pkt->id_offset;
461
0
            pid->num_bytes_to_skip =
462
0
                pkt->sd_offset - pkt->id_offset - 3;
463
0
            ws_assert(pid->num_bytes_to_skip >= 0);
464
0
          }
465
466
0
          num_bytes--;
467
0
          if (num_bytes > 0) {
468
            /*
469
             * There's more data in this
470
             * record.
471
             * Set the initial data offset
472
             * for the next packet.
473
             */
474
0
            pkt->id_offset = pkt->cd_offset;
475
0
            pkt->sd_offset = state->offset;
476
0
          } else {
477
            /*
478
             * There is no more data in
479
             * this record.
480
             * Thus, we don't have the
481
             * initial data offset for
482
             * the next packet.
483
             */
484
0
            pkt->id_offset = 0;
485
0
            pkt->sd_offset = 0;
486
0
          }
487
0
          state->num_bytes = num_bytes;
488
0
          state->pkt = pkt;
489
0
          return num_written;
490
0
        }
491
0
        break;
492
493
0
      case 0x7d:
494
        /*
495
         * Control Escape octet for octet-stuffed
496
         * RFC 1662 HDLC-like framing.
497
         */
498
0
        if (!pkt->esc) {
499
          /*
500
           * Control Escape not preceded by
501
           * Control Escape; discard it
502
           * but XOR the next octet with
503
           * 0x20.
504
           */
505
0
          pkt->esc = true;
506
0
          break;
507
0
        }
508
        /*
509
         * Control Escape preceded by Control Escape;
510
         * treat it as an ordinary character,
511
         * by falling through.
512
         */
513
514
      /* FALL THROUGH */
515
0
      default:
516
0
        if (pkt->esc) {
517
          /*
518
           * This character was preceded by
519
           * Control Escape, so XOR it with
520
           * 0x20, as per RFC 1662's octet-
521
           * stuffed framing, and clear
522
           * the flag saying that the
523
           * character should be escaped.
524
           */
525
0
          c ^= 0x20;
526
0
          pkt->esc = false;
527
0
        }
528
529
0
        if (pkt->cnt >= PPPD_BUF_SIZE) {
530
0
          *err = WTAP_ERR_BAD_FILE;
531
0
          *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
532
0
              pkt->cnt - 1, PPPD_BUF_SIZE);
533
0
          return -1;
534
0
        }
535
0
        pkt->buf[pkt->cnt++] = c;
536
0
        break;
537
0
    }
538
0
  }
539
540
  /* we could have run out of bytes to read */
541
0
  return 0;
542
0
}
543
544
/* Returns true if packet data copied, false if error occurred or EOF (no more records). */
545
static bool
546
collate(pppdump_t* state, FILE_T fh, int *err, char **err_info, uint8_t *pd,
547
    int *num_bytes, direction_enum *direction, pkt_id *pid,
548
    int64_t num_bytes_to_skip)
549
0
{
550
0
  int   id;
551
0
  pkt_t   *pkt = NULL;
552
0
  int   byte0, byte1;
553
0
  int   n, num_written = 0;
554
0
  int64_t   start_offset;
555
0
  uint32_t    time_long;
556
0
  uint8_t   time_short;
557
558
  /*
559
   * Process any data left over in the current record when doing
560
   * sequential processing.
561
   */
562
0
  if (state->num_bytes > 0) {
563
0
    ws_assert(num_bytes_to_skip == 0);
564
0
    pkt = state->pkt;
565
0
    num_written = process_data(state, fh, pkt, state->num_bytes,
566
0
        pd, err, err_info, pid);
567
568
0
    if (num_written < 0) {
569
0
      return false;
570
0
    }
571
0
    else if (num_written > 0) {
572
0
      *num_bytes = num_written;
573
0
      *direction = pkt->dir;
574
0
      return true;
575
0
    }
576
    /* if 0 bytes written, keep processing */
577
0
  } else {
578
    /*
579
     * We didn't have any data left over, so the packet will
580
     * start at the beginning of a record.
581
     */
582
0
    if (pid)
583
0
      pid->num_bytes_to_skip = 0;
584
0
  }
585
586
  /*
587
   * That didn't get all the data for this packet, so process
588
   * subsequent records.
589
   */
590
0
  start_offset = state->offset;
591
0
  while ((id = file_getc(fh)) != EOF) {
592
0
    state->offset++;
593
0
    switch (id) {
594
0
      case PPPD_SENT_DATA:
595
0
      case PPPD_RECV_DATA:
596
0
        pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
597
598
        /*
599
         * Save the offset of the beginning of
600
         * the current record.
601
         */
602
0
        pkt->cd_offset = state->offset - 1;
603
604
        /*
605
         * Get the length of the record.
606
         */
607
0
        byte0 = file_getc(fh);
608
0
        if (byte0 == EOF)
609
0
          goto done;
610
0
        state->offset++;
611
0
        byte1 = file_getc(fh);
612
0
        if (byte1 == EOF)
613
0
          goto done;
614
0
        state->offset++;
615
0
        n = (byte0 << 8) | byte1;
616
617
0
        if (pkt->id_offset == 0) {
618
          /*
619
           * We don't have the initial data
620
           * offset for this packet, which
621
           * means this is the first
622
           * data record for that packet.
623
           * Save the offset of the
624
           * beginning of that record and
625
           * the offset of the first data
626
           * byte in the packet, which is
627
           * the first data byte in the
628
           * record.
629
           */
630
0
          pkt->id_offset = pkt->cd_offset;
631
0
          pkt->sd_offset = state->offset;
632
0
        }
633
634
0
        if (n == 0)
635
0
          continue;
636
637
0
        ws_assert(num_bytes_to_skip < n);
638
0
        while (num_bytes_to_skip) {
639
0
          if (file_getc(fh) == EOF)
640
0
            goto done;
641
0
          state->offset++;
642
0
          num_bytes_to_skip--;
643
0
          n--;
644
0
        }
645
0
        num_written = process_data(state, fh, pkt, n,
646
0
            pd, err, err_info, pid);
647
648
0
        if (num_written < 0) {
649
0
          return false;
650
0
        }
651
0
        else if (num_written > 0) {
652
0
          *num_bytes = num_written;
653
0
          *direction = pkt->dir;
654
0
          return true;
655
0
        }
656
        /* if 0 bytes written, keep looping */
657
0
        break;
658
659
0
      case PPPD_SEND_DELIM:
660
0
      case PPPD_RECV_DELIM:
661
        /* What can we do? */
662
0
        break;
663
664
0
      case PPPD_RESET_TIME:
665
0
        if (!wtap_read_bytes(fh, &time_long, sizeof(uint32_t), err, err_info))
666
0
          return false;
667
0
        state->offset += sizeof(uint32_t);
668
0
        state->timestamp = pntohu32(&time_long);
669
0
        state->tenths = 0;
670
0
        break;
671
672
0
      case PPPD_TIME_STEP_LONG:
673
0
        if (!wtap_read_bytes(fh, &time_long, sizeof(uint32_t), err, err_info))
674
0
          return false;
675
0
        state->offset += sizeof(uint32_t);
676
0
        state->tenths += pntohu32(&time_long);
677
678
0
        if (state->tenths >= 10) {
679
0
          state->timestamp += state->tenths / 10;
680
0
          state->tenths = state->tenths % 10;
681
0
        }
682
683
0
        break;
684
685
0
      case PPPD_TIME_STEP_SHORT:
686
0
        if (!wtap_read_bytes(fh, &time_short, sizeof(uint8_t), err, err_info))
687
0
          return false;
688
0
        state->offset += sizeof(uint8_t);
689
0
        state->tenths += time_short;
690
691
0
        if (state->tenths >= 10) {
692
0
          state->timestamp += state->tenths / 10;
693
0
          state->tenths = state->tenths % 10;
694
0
        }
695
696
0
        break;
697
698
0
      default:
699
        /* XXX - bad file */
700
0
        *err = WTAP_ERR_BAD_FILE;
701
0
        *err_info = ws_strdup_printf("pppdump: bad ID byte 0x%02x", id);
702
0
        return false;
703
0
    }
704
705
0
  }
706
707
0
done:
708
0
  *err = file_error(fh, err_info);
709
0
  if (*err == 0) {
710
0
    if (state->offset != start_offset) {
711
      /*
712
       * We read at least one byte, so we were working
713
       * on a record; an EOF means that record was
714
       * cut short.
715
       */
716
0
      *err = WTAP_ERR_SHORT_READ;
717
0
    }
718
0
  }
719
0
  return false;
720
0
}
721
722
723
724
/* Used to read packets in random-access fashion */
725
static bool
726
pppdump_seek_read(wtap *wth,
727
     int64_t seek_off,
728
     wtap_rec *rec,
729
     int *err,
730
     char **err_info)
731
0
{
732
0
  int   num_bytes;
733
0
  uint8_t   *pd;
734
0
  direction_enum  direction;
735
0
  pppdump_t *state;
736
0
  pkt_id    *pid;
737
0
  int64_t   num_bytes_to_skip;
738
739
0
  state = (pppdump_t *)wth->priv;
740
741
0
  pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
742
0
  if (!pid) {
743
0
    *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
744
0
    *err_info = g_strdup("pppdump: PID not found for record");
745
0
    return false;
746
0
  }
747
748
0
  if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
749
0
    return false;
750
751
0
  init_state(state->seek_state);
752
0
  state->seek_state->offset = pid->offset;
753
754
0
  ws_buffer_assure_space(&rec->data, PPPD_BUF_SIZE);
755
0
  pd = ws_buffer_start_ptr(&rec->data);
756
757
  /*
758
   * We'll start reading at the first record containing data from
759
   * this packet; however, that doesn't mean "collate()" will
760
   * stop only when we've read that packet, as there might be
761
   * data for packets going in the other direction as well, and
762
   * we might finish processing one of those packets before we
763
   * finish processing the packet we're reading.
764
   *
765
   * Therefore, we keep reading until we get a packet that's
766
   * going in the direction we want.
767
   */
768
0
  num_bytes_to_skip = pid->num_bytes_to_skip;
769
0
  do {
770
0
    if (!collate(state->seek_state, wth->random_fh, err, err_info,
771
0
        pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
772
0
      return false;
773
0
    num_bytes_to_skip = 0;
774
0
  } while (direction != pid->dir);
775
776
0
  pppdump_set_phdr(wth, rec, num_bytes, pid->dir);
777
778
0
  return true;
779
0
}
780
781
static void
782
pppdump_close(wtap *wth)
783
0
{
784
0
  pppdump_t *state;
785
786
0
  state = (pppdump_t *)wth->priv;
787
788
0
  if (state->seek_state) { /* should always be true */
789
0
    g_free(state->seek_state);
790
0
  }
791
792
0
  if (state->pids) {
793
0
    unsigned int i;
794
0
    for (i = 0; i < g_ptr_array_len(state->pids); i++) {
795
0
      g_free(g_ptr_array_index(state->pids, i));
796
0
    }
797
0
    g_ptr_array_free(state->pids, true);
798
0
  }
799
0
}
800
801
static const struct supported_block_type pppdump_blocks_supported[] = {
802
  /*
803
   * We support packet blocks, with no comments or other options.
804
   */
805
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
806
};
807
808
static const struct file_type_subtype_info pppdump_info = {
809
  "pppd log (pppdump format)", "pppd", NULL, NULL,
810
  false, BLOCKS_SUPPORTED(pppdump_blocks_supported),
811
  NULL, NULL, NULL
812
};
813
814
void register_pppdump(void)
815
14
{
816
14
  pppdump_file_type_subtype = wtap_register_file_type_subtype(&pppdump_info);
817
818
  /*
819
   * Register name for backwards compatibility with the
820
   * wtap_filetypes table in Lua.
821
   */
822
14
  wtap_register_backwards_compatibility_lua_name("PPPDUMP",
823
14
      pppdump_file_type_subtype);
824
14
}
825
826
/*
827
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
828
 *
829
 * Local variables:
830
 * c-basic-offset: 8
831
 * tab-width: 8
832
 * indent-tabs-mode: t
833
 * End:
834
 *
835
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
836
 * :indentSize=8:tabSize=8:noTabs=false:
837
 */