5 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include "file_wrappers.h"
38 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
42 +------+------+------+------+
43 | t3 | t2 | t1 | t0 | t = time_t
44 +------+------+------+------+
47 | 0x06 | Time step (short)
49 | ts | ts = time step (tenths of seconds)
53 | 0x05 | Time step (long)
54 +------+------+------+------+
55 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
56 +------+------+------+------+
59 | 0x04 | Receive deliminator (not seen in practice)
63 | 0x03 | Send deliminator (not seen in practice)
67 | 0x02 | Received data
69 | n1 | n0 | n = number of bytes following
77 | n1 | n0 | n = number of bytes following
83 #define PPPD_SENT_DATA 0x01
84 #define PPPD_RECV_DATA 0x02
85 #define PPPD_SEND_DELIM 0x03
86 #define PPPD_RECV_DELIM 0x04
87 #define PPPD_TIME_STEP_LONG 0x05
88 #define PPPD_TIME_STEP_SHORT 0x06
89 #define PPPD_RESET_TIME 0x07
91 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
92 * sizeof(lcp_header) + sizeof(ipcp_header). PPPD_MTU is *very* rarely
93 * larger than 1500 so this value is fine.
95 #define PPPD_BUF_SIZE 8192
102 static gboolean pppdump_read(wtap *wth, int *err, gchar **err_info,
103 gint64 *data_offset);
104 static gboolean pppdump_seek_read(wtap *wth, gint64 seek_off,
105 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
106 int *err, gchar **err_info);
109 * Information saved about a packet, during the initial sequential pass
110 * through the file, to allow us to later re-read it when randomly
113 * "offset" is the offset in the file of the first data chunk containing data
114 * from that packet; note that it may also contain data from previous
117 * "num_bytes_to_skip" is the number of bytes from previous packets in that
120 * "dir" is the direction of the packet.
124 gint64 num_bytes_to_skip;
129 * Information about a packet currently being processed. There is one of
130 * these for the sent packet being processed and one of these for the
131 * received packet being processed, as we could be in the middle of
132 * processing both a received packet and a sent packet.
134 * "dir" is the direction of the packet.
136 * "cnt" is the number of bytes of packet data we've accumulated.
138 * "esc" is TRUE if the next byte we see is escaped (and thus must be XORed
139 * with 0x20 before saving it), FALSE otherwise.
141 * "buf" is a buffer containing the packet data we've accumulated.
143 * "id_offset" is the offset in the file of the first data chunk
144 * containing data from the packet we're processing.
146 * "sd_offset" is the offset in the file of the first data byte from
147 * the packet we're processing - which isn't necessarily right after
148 * the header of the first data chunk, as we may already have assembled
149 * packets from that chunk.
151 * "cd_offset" is the offset in the file of the current data chunk we're
158 guint8 buf[PPPD_BUF_SIZE];
165 * This keeps state used while processing records.
167 * "timestamp" is the seconds portion of the current time stamp value,
168 * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
169 * PPPD_TIME_STEP_SHORT records. "tenths" is the tenths-of-seconds
172 * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
173 * packets we're currently working on.
175 * "offset" is the current offset in the file.
177 * "num_bytes" and "pkt" are information saved when we finish accumulating
178 * the data for a packet, if the data chunk we're working on still has more
181 * "num_bytes" is the number of bytes of additional data remaining
182 * in the chunk after we've finished accumulating the data for the
185 * "pkt" is the "pkt_t" for the type of packet the data chunk is for
186 * (sent or received packet).
188 * "seek_state" is another state structure used while processing records
189 * when doing a seek-and-read. (That structure doesn't itself have a
190 * "seek_state" structure.)
192 * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
193 * packets we've seen during the initial sequential pass, to allow us to
194 * later retrieve them with random accesses.
196 * "pkt_cnt" is the number of packets we've seen up to this point in the
199 typedef struct _pppdump_t {
207 struct _pppdump_t *seek_state;
213 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
214 int *err, gchar **err_info, pkt_id *pid);
217 collate(pppdump_t*, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
218 int *num_bytes, direction_enum *direction, pkt_id *pid,
219 gint64 num_bytes_to_skip);
222 pppdump_close(wtap *wth);
225 init_state(pppdump_t *state)
228 state->num_bytes = 0;
231 state->spkt.dir = DIRECTION_SENT;
233 state->spkt.esc = FALSE;
234 state->spkt.id_offset = 0;
235 state->spkt.sd_offset = 0;
236 state->spkt.cd_offset = 0;
238 state->rpkt.dir = DIRECTION_RECV;
240 state->rpkt.esc = FALSE;
241 state->rpkt.id_offset = 0;
242 state->rpkt.sd_offset = 0;
243 state->rpkt.cd_offset = 0;
245 state->seek_state = NULL;
246 state->offset = 0x100000; /* to detect errors during development */
251 pppdump_open(wtap *wth, int *err, gchar **err_info)
253 guint8 buffer[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
256 /* There is no file header, only packet records. Fortunately for us,
257 * timestamp records are separated from packet records, so we should
258 * find an "initial time stamp" (i.e., a "reset time" record, or
259 * record type 0x07) at the beginning of the file. We'll check for
260 * that, plus a valid record following the 0x07 and the four bytes
261 * representing the timestamp.
264 wtap_file_read_unknown_bytes(buffer, sizeof(buffer), wth->fh, err,
267 if (buffer[0] == PPPD_RESET_TIME &&
268 (buffer[5] == PPPD_SENT_DATA ||
269 buffer[5] == PPPD_RECV_DATA ||
270 buffer[5] == PPPD_TIME_STEP_LONG ||
271 buffer[5] == PPPD_TIME_STEP_SHORT ||
272 buffer[5] == PPPD_RESET_TIME)) {
282 if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
285 state = (pppdump_t *)g_malloc(sizeof(pppdump_t));
286 wth->priv = (void *)state;
287 state->timestamp = pntohl(&buffer[1]);
293 wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
294 wth->file_type = WTAP_FILE_PPPDUMP;
296 wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
297 wth->subtype_read = pppdump_read;
298 wth->subtype_seek_read = pppdump_seek_read;
299 wth->subtype_close = pppdump_close;
300 wth->tsprecision = WTAP_FILE_TSPREC_DSEC;
302 state->seek_state = g_malloc(sizeof(pppdump_t));
304 /* If we have a random stream open, we're going to be reading
305 the file randomly; set up a GPtrArray of pointers to
306 information about how to retrieve the data for each packet. */
307 if (wth->random_fh != NULL)
308 state->pids = g_ptr_array_new();
316 /* Find the next packet and parse it; called from wtap_read(). */
318 pppdump_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
321 direction_enum direction;
326 buffer_assure_space(wth->frame_buffer, PPPD_BUF_SIZE);
327 buf = buffer_start_ptr(wth->frame_buffer);
331 /* If we have a random stream open, allocate a structure to hold
332 the information needed to read this packet's data again. */
333 if (wth->random_fh != NULL) {
334 pid = g_new(pkt_id, 1);
336 *err = errno; /* assume a malloc failed and set "errno" */
341 pid = NULL; /* sequential only */
343 if (!collate(state, wth->fh, err, err_info, buf, &num_bytes, &direction,
351 pid->dir = direction;
354 g_ptr_array_add(state->pids, pid);
355 /* The user's data_offset is not really an offset, but a packet number. */
356 *data_offset = state->pkt_cnt;
359 wth->phdr.len = num_bytes;
360 wth->phdr.caplen = num_bytes;
361 wth->phdr.ts.secs = state->timestamp;
362 wth->phdr.ts.nsecs = state->tenths * 100000000;
363 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
365 wth->pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
370 /* Returns number of bytes copied for record, -1 if failure.
372 * This is modeled after pppdump.c, the utility to parse pppd log files; it
373 * comes with the ppp distribution.
376 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
377 int *err, gchar **err_info, pkt_id *pid)
383 for (; num_bytes > 0; --num_bytes) {
386 *err = file_error(fh, err_info);
388 *err = WTAP_ERR_SHORT_READ;
396 * Flag Sequence for RFC 1662 HDLC-like
399 * As this is a raw trace of octets going
400 * over the wire, and that might include
401 * the login sequence, there is no
402 * guarantee that *only* PPP traffic
403 * appears in this file, so there is no
404 * guarantee that the first 0x7e we see is
405 * a start flag sequence, and therefore we
406 * cannot safely ignore all characters up
407 * to the first 0x7e, and therefore we
408 * might end up with some bogus PPP
413 * We've seen stuff before this,
414 * so this is the end of a frame.
415 * Make a frame out of that stuff.
419 num_written = pkt->cnt;
421 if (num_written <= 0) {
425 if (num_written > PPPD_BUF_SIZE) {
426 *err = WTAP_ERR_UNC_OVERFLOW;
430 memcpy(pd, pkt->buf, num_written);
433 * Remember the offset of the
434 * first record containing data
435 * for this packet, and how far
436 * into that record to skip to
437 * get to the beginning of the
438 * data for this packet; the number
439 * of bytes to skip into that record
440 * is the file offset of the first
441 * byte of this packet minus the
442 * file offset of the first byte of
443 * this record, minus 3 bytes for the
444 * header of this record (which, if
445 * we re-read this record, we will
446 * process, not skip).
449 pid->offset = pkt->id_offset;
450 pid->num_bytes_to_skip =
451 pkt->sd_offset - pkt->id_offset - 3;
452 g_assert(pid->num_bytes_to_skip >= 0);
458 * There's more data in this
460 * Set the initial data offset
461 * for the next packet.
463 pkt->id_offset = pkt->cd_offset;
464 pkt->sd_offset = state->offset;
467 * There is no more data in
469 * Thus, we don't have the
470 * initial data offset for
476 state->num_bytes = num_bytes;
484 * Control Escape octet for octet-stuffed
485 * RFC 1662 HDLC-like framing.
489 * Control Escape not preceded by
490 * Control Escape; discard it
491 * but XOR the next octet with
498 * Control Escape preceded by Control Escape;
499 * treat it as an ordinary character,
500 * by falling through.
506 * This character was preceded by
507 * Control Escape, so XOR it with
508 * 0x20, as per RFC 1662's octet-
509 * stuffed framing, and clear
510 * the flag saying that the
511 * character should be escaped.
517 if (pkt->cnt >= PPPD_BUF_SIZE) {
518 *err = WTAP_ERR_UNC_OVERFLOW;
521 pkt->buf[pkt->cnt++] = c;
526 /* we could have run out of bytes to read */
530 /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
532 collate(pppdump_t* state, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
533 int *num_bytes, direction_enum *direction, pkt_id *pid,
534 gint64 num_bytes_to_skip)
539 int n, num_written = 0;
545 * Process any data left over in the current record when doing
546 * sequential processing.
548 if (state->num_bytes > 0) {
549 g_assert(num_bytes_to_skip == 0);
551 num_written = process_data(state, fh, pkt, state->num_bytes,
552 pd, err, err_info, pid);
554 if (num_written < 0) {
557 else if (num_written > 0) {
558 *num_bytes = num_written;
559 *direction = pkt->dir;
562 /* if 0 bytes written, keep processing */
565 * We didn't have any data left over, so the packet will
566 * start at the beginning of a record.
569 pid->num_bytes_to_skip = 0;
573 * That didn't get all the data for this packet, so process
574 * subsequent records.
576 start_offset = state->offset;
577 while ((id = file_getc(fh)) != EOF) {
582 pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
585 * Save the offset of the beginning of
586 * the current record.
588 pkt->cd_offset = state->offset - 1;
591 * Get the length of the record.
593 byte0 = file_getc(fh);
597 byte1 = file_getc(fh);
601 n = (byte0 << 8) | byte1;
603 if (pkt->id_offset == 0) {
605 * We don't have the initial data
606 * offset for this packet, which
607 * means this is the first
608 * data record for that packet.
609 * Save the offset of the
610 * beginning of that record and
611 * the offset of the first data
612 * byte in the packet, which is
613 * the first data byte in the
616 pkt->id_offset = pkt->cd_offset;
617 pkt->sd_offset = state->offset;
623 g_assert(num_bytes_to_skip < n);
624 while (num_bytes_to_skip) {
625 if (file_getc(fh) == EOF)
631 num_written = process_data(state, fh, pkt, n,
632 pd, err, err_info, pid);
634 if (num_written < 0) {
637 else if (num_written > 0) {
638 *num_bytes = num_written;
639 *direction = pkt->dir;
642 /* if 0 bytes written, keep looping */
645 case PPPD_SEND_DELIM:
646 case PPPD_RECV_DELIM:
647 /* What can we do? */
650 case PPPD_RESET_TIME:
651 wtap_file_read_unknown_bytes(&time_long, sizeof(guint32), fh, err, err_info);
652 state->offset += sizeof(guint32);
653 state->timestamp = pntohl(&time_long);
657 case PPPD_TIME_STEP_LONG:
658 wtap_file_read_unknown_bytes(&time_long, sizeof(guint32), fh, err, err_info);
659 state->offset += sizeof(guint32);
660 state->tenths += pntohl(&time_long);
662 if (state->tenths >= 10) {
663 state->timestamp += state->tenths / 10;
664 state->tenths = state->tenths % 10;
669 case PPPD_TIME_STEP_SHORT:
670 wtap_file_read_unknown_bytes(&time_short, sizeof(guint8), fh, err, err_info);
671 state->offset += sizeof(guint8);
672 state->tenths += time_short;
674 if (state->tenths >= 10) {
675 state->timestamp += state->tenths / 10;
676 state->tenths = state->tenths % 10;
683 *err = WTAP_ERR_BAD_FILE;
684 *err_info = g_strdup_printf("pppdump: bad ID byte 0x%02x", id);
691 *err = file_error(fh, err_info);
693 if (state->offset != start_offset) {
695 * We read at least one byte, so we were working
696 * on a record; an EOF means that record was
699 *err = WTAP_ERR_SHORT_READ;
707 /* Used to read packets in random-access fashion */
709 pppdump_seek_read(wtap *wth,
711 union wtap_pseudo_header *pseudo_header,
718 direction_enum direction;
721 gint64 num_bytes_to_skip;
725 pid = g_ptr_array_index(state->pids, seek_off);
727 *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
728 *err_info = g_strdup("pppdump: PID not found for record");
732 if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
735 init_state(state->seek_state);
736 state->seek_state->offset = pid->offset;
739 * We'll start reading at the first record containing data from
740 * this packet; however, that doesn't mean "collate()" will
741 * stop only when we've read that packet, as there might be
742 * data for packets going in the other direction as well, and
743 * we might finish processing one of those packets before we
744 * finish processing the packet we're reading.
746 * Therefore, we keep reading until we get a packet that's
747 * going in the direction we want.
749 num_bytes_to_skip = pid->num_bytes_to_skip;
751 if (!collate(state->seek_state, wth->random_fh, err, err_info,
752 pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
754 num_bytes_to_skip = 0;
755 } while (direction != pid->dir);
757 if (len != num_bytes) {
758 *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
759 *err_info = g_strdup_printf("pppdump: requested length %d doesn't match record length %d",
764 pseudo_header->p2p.sent = (pid->dir == DIRECTION_SENT ? TRUE : FALSE);
770 pppdump_close(wtap *wth)
774 state = (pppdump_t *)wth->priv;
776 if (state->seek_state) { /* should always be TRUE */
777 g_free(state->seek_state);
782 for (i = 0; i < g_ptr_array_len(state->pids); i++) {
783 g_free(g_ptr_array_index(state->pids, i));
785 g_ptr_array_free(state->pids, TRUE);