summaryrefslogtreecommitdiffstats
path: root/wiretap/pppdump.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /wiretap/pppdump.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'wiretap/pppdump.c')
-rw-r--r--wiretap/pppdump.c838
1 files changed, 838 insertions, 0 deletions
diff --git a/wiretap/pppdump.c b/wiretap/pppdump.c
new file mode 100644
index 00000000..15eda4fc
--- /dev/null
+++ b/wiretap/pppdump.c
@@ -0,0 +1,838 @@
+/* pppdump.c
+ *
+ * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#include "wtap-int.h"
+#include "pppdump.h"
+#include "file_wrappers.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <wsutil/ws_assert.h>
+
+/*
+pppdump records
+Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
+
++------+
+| 0x07 | Reset time
++------+------+------+------+
+| t3 | t2 | t1 | t0 | t = time_t
++------+------+------+------+
+
++------+
+| 0x06 | Time step (short)
++------+
+| ts | ts = time step (tenths of seconds)
++------+
+
++------+
+| 0x05 | Time step (long)
++------+------+------+------+
+| ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
++------+------+------+------+
+
++------+
+| 0x04 | Receive deliminator (not seen in practice)
++------+
+
++------+
+| 0x03 | Send deliminator (not seen in practice)
++------+
+
++------+
+| 0x02 | Received data
++------+------+
+| n1 | n0 | n = number of bytes following
++------+------+
+| data |
+| |
+
++------+
+| 0x01 | Sent data
++------+------+
+| n1 | n0 | n = number of bytes following
++------+------+
+| data |
+| |
+*/
+
+#define PPPD_SENT_DATA 0x01
+#define PPPD_RECV_DATA 0x02
+#define PPPD_SEND_DELIM 0x03
+#define PPPD_RECV_DELIM 0x04
+#define PPPD_TIME_STEP_LONG 0x05
+#define PPPD_TIME_STEP_SHORT 0x06
+#define PPPD_RESET_TIME 0x07
+
+/* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
+ * sizeof(lcp_header) + sizeof(ipcp_header). PPPD_MTU is *very* rarely
+ * larger than 1500 so this value is fine.
+ *
+ * It's less than WTAP_MAX_PACKET_SIZE_STANDARD, so we don't have to worry about
+ * too-large packets.
+ */
+#define PPPD_BUF_SIZE 8192
+
+typedef enum {
+ DIRECTION_SENT,
+ DIRECTION_RECV
+} direction_enum;
+
+static gboolean pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf,
+ int *err, gchar **err_info, gint64 *data_offset);
+static gboolean pppdump_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
+
+static int pppdump_file_type_subtype = -1;
+
+void register_pppdump(void);
+
+/*
+ * Information saved about a packet, during the initial sequential pass
+ * through the file, to allow us to later re-read it when randomly
+ * reading packets.
+ *
+ * "offset" is the offset in the file of the first data chunk containing data
+ * from that packet; note that it may also contain data from previous
+ * packets.
+ *
+ * "num_bytes_to_skip" is the number of bytes from previous packets in that
+ * first data chunk.
+ *
+ * "dir" is the direction of the packet.
+ */
+typedef struct {
+ gint64 offset;
+ gint64 num_bytes_to_skip;
+ direction_enum dir;
+} pkt_id;
+
+/*
+ * Information about a packet currently being processed. There is one of
+ * these for the sent packet being processed and one of these for the
+ * received packet being processed, as we could be in the middle of
+ * processing both a received packet and a sent packet.
+ *
+ * "dir" is the direction of the packet.
+ *
+ * "cnt" is the number of bytes of packet data we've accumulated.
+ *
+ * "esc" is TRUE if the next byte we see is escaped (and thus must be XORed
+ * with 0x20 before saving it), FALSE otherwise.
+ *
+ * "buf" is a buffer containing the packet data we've accumulated.
+ *
+ * "id_offset" is the offset in the file of the first data chunk
+ * containing data from the packet we're processing.
+ *
+ * "sd_offset" is the offset in the file of the first data byte from
+ * the packet we're processing - which isn't necessarily right after
+ * the header of the first data chunk, as we may already have assembled
+ * packets from that chunk.
+ *
+ * "cd_offset" is the offset in the file of the current data chunk we're
+ * processing.
+ */
+typedef struct {
+ direction_enum dir;
+ int cnt;
+ gboolean esc;
+ guint8 buf[PPPD_BUF_SIZE];
+ gint64 id_offset;
+ gint64 sd_offset;
+ gint64 cd_offset;
+} pkt_t;
+
+/*
+ * This keeps state used while processing records.
+ *
+ * "timestamp" is the seconds portion of the current time stamp value,
+ * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
+ * PPPD_TIME_STEP_SHORT records. "tenths" is the tenths-of-seconds
+ * portion.
+ *
+ * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
+ * packets we're currently working on.
+ *
+ * "offset" is the current offset in the file.
+ *
+ * "num_bytes" and "pkt" are information saved when we finish accumulating
+ * the data for a packet, if the data chunk we're working on still has more
+ * data in it:
+ *
+ * "num_bytes" is the number of bytes of additional data remaining
+ * in the chunk after we've finished accumulating the data for the
+ * packet.
+ *
+ * "pkt" is the "pkt_t" for the type of packet the data chunk is for
+ * (sent or received packet).
+ *
+ * "seek_state" is another state structure used while processing records
+ * when doing a seek-and-read. (That structure doesn't itself have a
+ * "seek_state" structure.)
+ *
+ * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
+ * packets we've seen during the initial sequential pass, to allow us to
+ * later retrieve them with random accesses.
+ *
+ * "pkt_cnt" is the number of packets we've seen up to this point in the
+ * sequential pass.
+ */
+typedef struct _pppdump_t {
+ time_t timestamp;
+ guint tenths;
+ pkt_t spkt;
+ pkt_t rpkt;
+ gint64 offset;
+ int num_bytes;
+ pkt_t *pkt;
+ struct _pppdump_t *seek_state;
+ GPtrArray *pids;
+ guint pkt_cnt;
+} pppdump_t;
+
+static int
+process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
+ int *err, gchar **err_info, pkt_id *pid);
+
+static gboolean
+collate(pppdump_t *state, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
+ int *num_bytes, direction_enum *direction, pkt_id *pid,
+ gint64 num_bytes_to_skip);
+
+static void
+pppdump_close(wtap *wth);
+
+static void
+init_state(pppdump_t *state)
+{
+
+ state->num_bytes = 0;
+ state->pkt = NULL;
+
+ state->spkt.dir = DIRECTION_SENT;
+ state->spkt.cnt = 0;
+ state->spkt.esc = FALSE;
+ state->spkt.id_offset = 0;
+ state->spkt.sd_offset = 0;
+ state->spkt.cd_offset = 0;
+
+ state->rpkt.dir = DIRECTION_RECV;
+ state->rpkt.cnt = 0;
+ state->rpkt.esc = FALSE;
+ state->rpkt.id_offset = 0;
+ state->rpkt.sd_offset = 0;
+ state->rpkt.cd_offset = 0;
+
+ state->seek_state = NULL;
+ state->offset = 0x100000; /* to detect errors during development */
+}
+
+
+wtap_open_return_val
+pppdump_open(wtap *wth, int *err, gchar **err_info)
+{
+ guint8 buffer[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
+ pppdump_t *state;
+
+ /* There is no file header, only packet records. Fortunately for us,
+ * timestamp records are separated from packet records, so we should
+ * find an "initial time stamp" (i.e., a "reset time" record, or
+ * record type 0x07) at the beginning of the file. We'll check for
+ * that, plus a valid record following the 0x07 and the four bytes
+ * representing the timestamp.
+ */
+
+ if (!wtap_read_bytes(wth->fh, buffer, sizeof(buffer),
+ err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ if (buffer[0] == PPPD_RESET_TIME &&
+ (buffer[5] == PPPD_SENT_DATA ||
+ buffer[5] == PPPD_RECV_DATA ||
+ buffer[5] == PPPD_TIME_STEP_LONG ||
+ buffer[5] == PPPD_TIME_STEP_SHORT ||
+ buffer[5] == PPPD_RESET_TIME)) {
+
+ goto my_file_type;
+ }
+ else {
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ my_file_type:
+
+ if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
+ return WTAP_OPEN_ERROR;
+
+ state = g_new(pppdump_t, 1);
+ wth->priv = (void *)state;
+ state->timestamp = pntoh32(&buffer[1]);
+ state->tenths = 0;
+
+ init_state(state);
+
+ state->offset = 5;
+ wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
+ wth->file_type_subtype = pppdump_file_type_subtype;
+
+ wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
+ wth->subtype_read = pppdump_read;
+ wth->subtype_seek_read = pppdump_seek_read;
+ wth->subtype_close = pppdump_close;
+ wth->file_tsprec = WTAP_TSPREC_100_MSEC;
+
+ state->seek_state = g_new(pppdump_t,1);
+
+ /* If we have a random stream open, we're going to be reading
+ the file randomly; set up a GPtrArray of pointers to
+ information about how to retrieve the data for each packet. */
+ if (wth->random_fh != NULL)
+ state->pids = g_ptr_array_new();
+ else
+ state->pids = NULL;
+ state->pkt_cnt = 0;
+
+ /*
+ * Add an IDB; we don't know how many interfaces were
+ * involved, so we just say one interface, about which
+ * we only know the link-layer type, snapshot length,
+ * and time stamp resolution.
+ */
+ wtap_add_generated_idb(wth);
+
+ return WTAP_OPEN_MINE;
+}
+
+/* Set part of the struct wtap_rec. */
+static void
+pppdump_set_phdr(wtap_rec *rec, int num_bytes,
+ direction_enum direction)
+{
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
+ rec->rec_header.packet_header.len = num_bytes;
+ rec->rec_header.packet_header.caplen = num_bytes;
+ rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
+
+ rec->rec_header.packet_header.pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
+}
+
+/* Find the next packet and parse it; called from wtap_read(). */
+static gboolean
+pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info,
+ gint64 *data_offset)
+{
+ int num_bytes;
+ direction_enum direction;
+ pppdump_t *state;
+ pkt_id *pid;
+
+ state = (pppdump_t *)wth->priv;
+
+ /* If we have a random stream open, allocate a structure to hold
+ the information needed to read this packet's data again. */
+ if (wth->random_fh != NULL) {
+ pid = g_new(pkt_id, 1);
+ if (!pid) {
+ *err = errno; /* assume a malloc failed and set "errno" */
+ return FALSE;
+ }
+ pid->offset = 0;
+ } else
+ pid = NULL; /* sequential only */
+
+ ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
+ if (!collate(state, wth->fh, err, err_info, ws_buffer_start_ptr(buf),
+ &num_bytes, &direction, pid, 0)) {
+ g_free(pid);
+ return FALSE;
+ }
+
+ if (pid != NULL)
+ pid->dir = direction;
+
+ if (pid != NULL)
+ g_ptr_array_add(state->pids, pid);
+ /* The user's data_offset is not really an offset, but a packet number. */
+ *data_offset = state->pkt_cnt;
+ state->pkt_cnt++;
+
+ pppdump_set_phdr(rec, num_bytes, direction);
+ rec->presence_flags = WTAP_HAS_TS;
+ rec->ts.secs = state->timestamp;
+ rec->ts.nsecs = state->tenths * 100000000;
+
+ return TRUE;
+}
+
+/* Returns number of bytes copied for record, -1 if failure.
+ *
+ * This is modeled after pppdump.c, the utility to parse pppd log files; it
+ * comes with the ppp distribution.
+ */
+static int
+process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
+ int *err, gchar **err_info, pkt_id *pid)
+{
+ int c;
+ int num_bytes = n;
+ int num_written;
+
+ for (; num_bytes > 0; --num_bytes) {
+ c = file_getc(fh);
+ if (c == EOF) {
+ *err = file_error(fh, err_info);
+ if (*err == 0) {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return -1;
+ }
+ state->offset++;
+ switch (c) {
+ case 0x7e:
+ /*
+ * Flag Sequence for RFC 1662 HDLC-like
+ * framing.
+ *
+ * As this is a raw trace of octets going
+ * over the wire, and that might include
+ * the login sequence, there is no
+ * guarantee that *only* PPP traffic
+ * appears in this file, so there is no
+ * guarantee that the first 0x7e we see is
+ * a start flag sequence, and therefore we
+ * cannot safely ignore all characters up
+ * to the first 0x7e, and therefore we
+ * might end up with some bogus PPP
+ * packets.
+ */
+ if (pkt->cnt > 0) {
+ /*
+ * We've seen stuff before this,
+ * so this is the end of a frame.
+ * Make a frame out of that stuff.
+ */
+ pkt->esc = FALSE;
+
+ num_written = pkt->cnt;
+ pkt->cnt = 0;
+ if (num_written <= 0) {
+ return 0;
+ }
+
+ if (num_written > PPPD_BUF_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
+ num_written, PPPD_BUF_SIZE);
+ return -1;
+ }
+
+ memcpy(pd, pkt->buf, num_written);
+
+ /*
+ * Remember the offset of the
+ * first record containing data
+ * for this packet, and how far
+ * into that record to skip to
+ * get to the beginning of the
+ * data for this packet; the number
+ * of bytes to skip into that record
+ * is the file offset of the first
+ * byte of this packet minus the
+ * file offset of the first byte of
+ * this record, minus 3 bytes for the
+ * header of this record (which, if
+ * we re-read this record, we will
+ * process, not skip).
+ */
+ if (pid) {
+ pid->offset = pkt->id_offset;
+ pid->num_bytes_to_skip =
+ pkt->sd_offset - pkt->id_offset - 3;
+ ws_assert(pid->num_bytes_to_skip >= 0);
+ }
+
+ num_bytes--;
+ if (num_bytes > 0) {
+ /*
+ * There's more data in this
+ * record.
+ * Set the initial data offset
+ * for the next packet.
+ */
+ pkt->id_offset = pkt->cd_offset;
+ pkt->sd_offset = state->offset;
+ } else {
+ /*
+ * There is no more data in
+ * this record.
+ * Thus, we don't have the
+ * initial data offset for
+ * the next packet.
+ */
+ pkt->id_offset = 0;
+ pkt->sd_offset = 0;
+ }
+ state->num_bytes = num_bytes;
+ state->pkt = pkt;
+ return num_written;
+ }
+ break;
+
+ case 0x7d:
+ /*
+ * Control Escape octet for octet-stuffed
+ * RFC 1662 HDLC-like framing.
+ */
+ if (!pkt->esc) {
+ /*
+ * Control Escape not preceded by
+ * Control Escape; discard it
+ * but XOR the next octet with
+ * 0x20.
+ */
+ pkt->esc = TRUE;
+ break;
+ }
+ /*
+ * Control Escape preceded by Control Escape;
+ * treat it as an ordinary character,
+ * by falling through.
+ */
+
+ /* FALL THROUGH */
+ default:
+ if (pkt->esc) {
+ /*
+ * This character was preceded by
+ * Control Escape, so XOR it with
+ * 0x20, as per RFC 1662's octet-
+ * stuffed framing, and clear
+ * the flag saying that the
+ * character should be escaped.
+ */
+ c ^= 0x20;
+ pkt->esc = FALSE;
+ }
+
+ if (pkt->cnt >= PPPD_BUF_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = ws_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
+ pkt->cnt - 1, PPPD_BUF_SIZE);
+ return -1;
+ }
+ pkt->buf[pkt->cnt++] = c;
+ break;
+ }
+ }
+
+ /* we could have run out of bytes to read */
+ return 0;
+}
+
+/* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
+static gboolean
+collate(pppdump_t* state, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
+ int *num_bytes, direction_enum *direction, pkt_id *pid,
+ gint64 num_bytes_to_skip)
+{
+ int id;
+ pkt_t *pkt = NULL;
+ int byte0, byte1;
+ int n, num_written = 0;
+ gint64 start_offset;
+ guint32 time_long;
+ guint8 time_short;
+
+ /*
+ * Process any data left over in the current record when doing
+ * sequential processing.
+ */
+ if (state->num_bytes > 0) {
+ ws_assert(num_bytes_to_skip == 0);
+ pkt = state->pkt;
+ num_written = process_data(state, fh, pkt, state->num_bytes,
+ pd, err, err_info, pid);
+
+ if (num_written < 0) {
+ return FALSE;
+ }
+ else if (num_written > 0) {
+ *num_bytes = num_written;
+ *direction = pkt->dir;
+ return TRUE;
+ }
+ /* if 0 bytes written, keep processing */
+ } else {
+ /*
+ * We didn't have any data left over, so the packet will
+ * start at the beginning of a record.
+ */
+ if (pid)
+ pid->num_bytes_to_skip = 0;
+ }
+
+ /*
+ * That didn't get all the data for this packet, so process
+ * subsequent records.
+ */
+ start_offset = state->offset;
+ while ((id = file_getc(fh)) != EOF) {
+ state->offset++;
+ switch (id) {
+ case PPPD_SENT_DATA:
+ case PPPD_RECV_DATA:
+ pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
+
+ /*
+ * Save the offset of the beginning of
+ * the current record.
+ */
+ pkt->cd_offset = state->offset - 1;
+
+ /*
+ * Get the length of the record.
+ */
+ byte0 = file_getc(fh);
+ if (byte0 == EOF)
+ goto done;
+ state->offset++;
+ byte1 = file_getc(fh);
+ if (byte1 == EOF)
+ goto done;
+ state->offset++;
+ n = (byte0 << 8) | byte1;
+
+ if (pkt->id_offset == 0) {
+ /*
+ * We don't have the initial data
+ * offset for this packet, which
+ * means this is the first
+ * data record for that packet.
+ * Save the offset of the
+ * beginning of that record and
+ * the offset of the first data
+ * byte in the packet, which is
+ * the first data byte in the
+ * record.
+ */
+ pkt->id_offset = pkt->cd_offset;
+ pkt->sd_offset = state->offset;
+ }
+
+ if (n == 0)
+ continue;
+
+ ws_assert(num_bytes_to_skip < n);
+ while (num_bytes_to_skip) {
+ if (file_getc(fh) == EOF)
+ goto done;
+ state->offset++;
+ num_bytes_to_skip--;
+ n--;
+ }
+ num_written = process_data(state, fh, pkt, n,
+ pd, err, err_info, pid);
+
+ if (num_written < 0) {
+ return FALSE;
+ }
+ else if (num_written > 0) {
+ *num_bytes = num_written;
+ *direction = pkt->dir;
+ return TRUE;
+ }
+ /* if 0 bytes written, keep looping */
+ break;
+
+ case PPPD_SEND_DELIM:
+ case PPPD_RECV_DELIM:
+ /* What can we do? */
+ break;
+
+ case PPPD_RESET_TIME:
+ if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
+ return FALSE;
+ state->offset += sizeof(guint32);
+ state->timestamp = pntoh32(&time_long);
+ state->tenths = 0;
+ break;
+
+ case PPPD_TIME_STEP_LONG:
+ if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
+ return FALSE;
+ state->offset += sizeof(guint32);
+ state->tenths += pntoh32(&time_long);
+
+ if (state->tenths >= 10) {
+ state->timestamp += state->tenths / 10;
+ state->tenths = state->tenths % 10;
+ }
+
+ break;
+
+ case PPPD_TIME_STEP_SHORT:
+ if (!wtap_read_bytes(fh, &time_short, sizeof(guint8), err, err_info))
+ return FALSE;
+ state->offset += sizeof(guint8);
+ state->tenths += time_short;
+
+ if (state->tenths >= 10) {
+ state->timestamp += state->tenths / 10;
+ state->tenths = state->tenths % 10;
+ }
+
+ break;
+
+ default:
+ /* XXX - bad file */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = ws_strdup_printf("pppdump: bad ID byte 0x%02x", id);
+ return FALSE;
+ }
+
+ }
+
+done:
+ *err = file_error(fh, err_info);
+ if (*err == 0) {
+ if (state->offset != start_offset) {
+ /*
+ * We read at least one byte, so we were working
+ * on a record; an EOF means that record was
+ * cut short.
+ */
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/* Used to read packets in random-access fashion */
+static gboolean
+pppdump_seek_read(wtap *wth,
+ gint64 seek_off,
+ wtap_rec *rec,
+ Buffer *buf,
+ int *err,
+ gchar **err_info)
+{
+ int num_bytes;
+ guint8 *pd;
+ direction_enum direction;
+ pppdump_t *state;
+ pkt_id *pid;
+ gint64 num_bytes_to_skip;
+
+ state = (pppdump_t *)wth->priv;
+
+ pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
+ if (!pid) {
+ *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
+ *err_info = g_strdup("pppdump: PID not found for record");
+ return FALSE;
+ }
+
+ if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
+ return FALSE;
+
+ init_state(state->seek_state);
+ state->seek_state->offset = pid->offset;
+
+ ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
+ pd = ws_buffer_start_ptr(buf);
+
+ /*
+ * We'll start reading at the first record containing data from
+ * this packet; however, that doesn't mean "collate()" will
+ * stop only when we've read that packet, as there might be
+ * data for packets going in the other direction as well, and
+ * we might finish processing one of those packets before we
+ * finish processing the packet we're reading.
+ *
+ * Therefore, we keep reading until we get a packet that's
+ * going in the direction we want.
+ */
+ num_bytes_to_skip = pid->num_bytes_to_skip;
+ do {
+ if (!collate(state->seek_state, wth->random_fh, err, err_info,
+ pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
+ return FALSE;
+ num_bytes_to_skip = 0;
+ } while (direction != pid->dir);
+
+ pppdump_set_phdr(rec, num_bytes, pid->dir);
+
+ return TRUE;
+}
+
+static void
+pppdump_close(wtap *wth)
+{
+ pppdump_t *state;
+
+ state = (pppdump_t *)wth->priv;
+
+ if (state->seek_state) { /* should always be TRUE */
+ g_free(state->seek_state);
+ }
+
+ if (state->pids) {
+ unsigned int i;
+ for (i = 0; i < g_ptr_array_len(state->pids); i++) {
+ g_free(g_ptr_array_index(state->pids, i));
+ }
+ g_ptr_array_free(state->pids, TRUE);
+ }
+}
+
+static const struct supported_block_type pppdump_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info pppdump_info = {
+ "pppd log (pppdump format)", "pppd", NULL, NULL,
+ FALSE, BLOCKS_SUPPORTED(pppdump_blocks_supported),
+ NULL, NULL, NULL
+};
+
+void register_pppdump(void)
+{
+ pppdump_file_type_subtype = wtap_register_file_type_subtype(&pppdump_info);
+
+ /*
+ * Register name for backwards compatibility with the
+ * wtap_filetypes table in Lua.
+ */
+ wtap_register_backwards_compatibility_lua_name("PPPDUMP",
+ pppdump_file_type_subtype);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */