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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "file_wrappers.h"
36 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
40 +------+------+------+------+
41 | t3 | t2 | t1 | t0 | t = time_t
42 +------+------+------+------+
45 | 0x06 | Time step (short)
47 | ts | ts = time step (tenths of seconds)
51 | 0x05 | Time step (long)
52 +------+------+------+------+
53 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
54 +------+------+------+------+
57 | 0x04 | Receive deliminator (not seen in practice)
61 | 0x03 | Send deliminator (not seen in practice)
65 | 0x02 | Received data
67 | n1 | n0 | n = number of bytes following
75 | n1 | n0 | n = number of bytes following
81 #define PPPD_SENT_DATA 0x01
82 #define PPPD_RECV_DATA 0x02
83 #define PPPD_SEND_DELIM 0x03
84 #define PPPD_RECV_DELIM 0x04
85 #define PPPD_TIME_STEP_LONG 0x05
86 #define PPPD_TIME_STEP_SHORT 0x06
87 #define PPPD_RESET_TIME 0x07
89 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
90 * sizeof(lcp_header) + sizeof(ipcp_header). PPPD_MTU is *very* rarely
91 * larger than 1500 so this value is fine.
93 #define PPPD_BUF_SIZE 8192
100 static gboolean
pppdump_read(wtap
*wth
, int *err
, gchar
**err_info
,
101 gint64
*data_offset
);
102 static gboolean
pppdump_seek_read(wtap
*wth
, gint64 seek_off
,
103 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len
,
104 int *err
, gchar
**err_info
);
107 * Information saved about a packet, during the initial sequential pass
108 * through the file, to allow us to later re-read it when randomly
111 * "offset" is the offset in the file of the first data chunk containing data
112 * from that packet; note that it may also contain data from previous
115 * "num_bytes_to_skip" is the number of bytes from previous packets in that
118 * "dir" is the direction of the packet.
122 gint64 num_bytes_to_skip
;
127 * Information about a packet currently being processed. There is one of
128 * these for the sent packet being processed and one of these for the
129 * received packet being processed, as we could be in the middle of
130 * processing both a received packet and a sent packet.
132 * "dir" is the direction of the packet.
134 * "cnt" is the number of bytes of packet data we've accumulated.
136 * "esc" is TRUE if the next byte we see is escaped (and thus must be XORed
137 * with 0x20 before saving it), FALSE otherwise.
139 * "buf" is a buffer containing the packet data we've accumulated.
141 * "id_offset" is the offset in the file of the first data chunk
142 * containing data from the packet we're processing.
144 * "sd_offset" is the offset in the file of the first data byte from
145 * the packet we're processing - which isn't necessarily right after
146 * the header of the first data chunk, as we may already have assembled
147 * packets from that chunk.
149 * "cd_offset" is the offset in the file of the current data chunk we're
156 guint8 buf
[PPPD_BUF_SIZE
];
163 * This keeps state used while processing records.
165 * "timestamp" is the seconds portion of the current time stamp value,
166 * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
167 * PPPD_TIME_STEP_SHORT records. "tenths" is the tenths-of-seconds
170 * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
171 * packets we're currently working on.
173 * "offset" is the current offset in the file.
175 * "num_bytes" and "pkt" are information saved when we finish accumulating
176 * the data for a packet, if the data chunk we're working on still has more
179 * "num_bytes" is the number of bytes of additional data remaining
180 * in the chunk after we've finished accumulating the data for the
183 * "pkt" is the "pkt_t" for the type of packet the data chunk is for
184 * (sent or received packet).
186 * "seek_state" is another state structure used while processing records
187 * when doing a seek-and-read. (That structure doesn't itself have a
188 * "seek_state" structure.)
190 * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
191 * packets we've seen during the initial sequential pass, to allow us to
192 * later retrieve them with random accesses.
194 * "pkt_cnt" is the number of packets we've seen up to this point in the
197 typedef struct _pppdump_t
{
205 struct _pppdump_t
*seek_state
;
211 process_data(pppdump_t
*state
, FILE_T fh
, pkt_t
*pkt
, int n
, guint8
*pd
,
212 int *err
, gchar
**err_info
, pkt_id
*pid
);
215 collate(pppdump_t
*, FILE_T fh
, int *err
, gchar
**err_info
, guint8
*pd
,
216 int *num_bytes
, direction_enum
*direction
, pkt_id
*pid
,
217 gint64 num_bytes_to_skip
);
220 pppdump_close(wtap
*wth
);
223 init_state(pppdump_t
*state
)
226 state
->num_bytes
= 0;
229 state
->spkt
.dir
= DIRECTION_SENT
;
231 state
->spkt
.esc
= FALSE
;
232 state
->spkt
.id_offset
= 0;
233 state
->spkt
.sd_offset
= 0;
234 state
->spkt
.cd_offset
= 0;
236 state
->rpkt
.dir
= DIRECTION_RECV
;
238 state
->rpkt
.esc
= FALSE
;
239 state
->rpkt
.id_offset
= 0;
240 state
->rpkt
.sd_offset
= 0;
241 state
->rpkt
.cd_offset
= 0;
243 state
->seek_state
= NULL
;
244 state
->offset
= 0x100000; /* to detect errors during development */
249 pppdump_open(wtap
*wth
, int *err
, gchar
**err_info
)
251 guint8 buffer
[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
255 /* There is no file header, only packet records. Fortunately for us,
256 * timestamp records are separated from packet records, so we should
257 * find an "initial time stamp" (i.e., a "reset time" record, or
258 * record type 0x07) at the beginning of the file. We'll check for
259 * that, plus a valid record following the 0x07 and the four bytes
260 * representing the timestamp.
263 bytes_read
= file_read(buffer
, sizeof(buffer
), wth
->fh
);
264 if (bytes_read
!= (int) sizeof(buffer
)) {
265 *err
= file_error(wth
->fh
, err_info
);
266 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
271 if (buffer
[0] == PPPD_RESET_TIME
&&
272 (buffer
[5] == PPPD_SENT_DATA
||
273 buffer
[5] == PPPD_RECV_DATA
||
274 buffer
[5] == PPPD_TIME_STEP_LONG
||
275 buffer
[5] == PPPD_TIME_STEP_SHORT
||
276 buffer
[5] == PPPD_RESET_TIME
)) {
286 if (file_seek(wth
->fh
, 5, SEEK_SET
, err
) == -1)
289 state
= (pppdump_t
*)g_malloc(sizeof(pppdump_t
));
290 wth
->priv
= (void *)state
;
291 state
->timestamp
= pntohl(&buffer
[1]);
297 wth
->file_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
298 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_PPPDUMP
;
300 wth
->snapshot_length
= PPPD_BUF_SIZE
; /* just guessing */
301 wth
->subtype_read
= pppdump_read
;
302 wth
->subtype_seek_read
= pppdump_seek_read
;
303 wth
->subtype_close
= pppdump_close
;
304 wth
->tsprecision
= WTAP_FILE_TSPREC_DSEC
;
306 state
->seek_state
= g_new(pppdump_t
,1);
308 /* If we have a random stream open, we're going to be reading
309 the file randomly; set up a GPtrArray of pointers to
310 information about how to retrieve the data for each packet. */
311 if (wth
->random_fh
!= NULL
)
312 state
->pids
= g_ptr_array_new();
320 /* Set part of the struct wtap_pkthdr. */
322 pppdump_set_phdr(struct wtap_pkthdr
*phdr
, int num_bytes
,
323 direction_enum direction
)
325 phdr
->len
= num_bytes
;
326 phdr
->caplen
= num_bytes
;
327 phdr
->pkt_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
329 phdr
->pseudo_header
.p2p
.sent
= (direction
== DIRECTION_SENT
? TRUE
: FALSE
);
332 /* Find the next packet and parse it; called from wtap_read(). */
334 pppdump_read(wtap
*wth
, int *err
, gchar
**err_info
, gint64
*data_offset
)
337 direction_enum direction
;
342 state
= (pppdump_t
*)wth
->priv
;
344 /* If we have a random stream open, allocate a structure to hold
345 the information needed to read this packet's data again. */
346 if (wth
->random_fh
!= NULL
) {
347 pid
= g_new(pkt_id
, 1);
349 *err
= errno
; /* assume a malloc failed and set "errno" */
354 pid
= NULL
; /* sequential only */
356 buffer_assure_space(wth
->frame_buffer
, PPPD_BUF_SIZE
);
357 buf
= buffer_start_ptr(wth
->frame_buffer
);
359 if (!collate(state
, wth
->fh
, err
, err_info
, buf
, &num_bytes
, &direction
,
367 pid
->dir
= direction
;
370 g_ptr_array_add(state
->pids
, pid
);
371 /* The user's data_offset is not really an offset, but a packet number. */
372 *data_offset
= state
->pkt_cnt
;
375 wth
->phdr
.presence_flags
= WTAP_HAS_TS
;
376 wth
->phdr
.ts
.secs
= state
->timestamp
;
377 wth
->phdr
.ts
.nsecs
= state
->tenths
* 100000000;
378 pppdump_set_phdr(&wth
->phdr
, num_bytes
, direction
);
383 /* Returns number of bytes copied for record, -1 if failure.
385 * This is modeled after pppdump.c, the utility to parse pppd log files; it
386 * comes with the ppp distribution.
389 process_data(pppdump_t
*state
, FILE_T fh
, pkt_t
*pkt
, int n
, guint8
*pd
,
390 int *err
, gchar
**err_info
, pkt_id
*pid
)
396 for (; num_bytes
> 0; --num_bytes
) {
399 *err
= file_error(fh
, err_info
);
401 *err
= WTAP_ERR_SHORT_READ
;
409 * Flag Sequence for RFC 1662 HDLC-like
412 * As this is a raw trace of octets going
413 * over the wire, and that might include
414 * the login sequence, there is no
415 * guarantee that *only* PPP traffic
416 * appears in this file, so there is no
417 * guarantee that the first 0x7e we see is
418 * a start flag sequence, and therefore we
419 * cannot safely ignore all characters up
420 * to the first 0x7e, and therefore we
421 * might end up with some bogus PPP
426 * We've seen stuff before this,
427 * so this is the end of a frame.
428 * Make a frame out of that stuff.
432 num_written
= pkt
->cnt
;
434 if (num_written
<= 0) {
438 if (num_written
> PPPD_BUF_SIZE
) {
439 *err
= WTAP_ERR_UNC_OVERFLOW
;
443 memcpy(pd
, pkt
->buf
, num_written
);
446 * Remember the offset of the
447 * first record containing data
448 * for this packet, and how far
449 * into that record to skip to
450 * get to the beginning of the
451 * data for this packet; the number
452 * of bytes to skip into that record
453 * is the file offset of the first
454 * byte of this packet minus the
455 * file offset of the first byte of
456 * this record, minus 3 bytes for the
457 * header of this record (which, if
458 * we re-read this record, we will
459 * process, not skip).
462 pid
->offset
= pkt
->id_offset
;
463 pid
->num_bytes_to_skip
=
464 pkt
->sd_offset
- pkt
->id_offset
- 3;
465 g_assert(pid
->num_bytes_to_skip
>= 0);
471 * There's more data in this
473 * Set the initial data offset
474 * for the next packet.
476 pkt
->id_offset
= pkt
->cd_offset
;
477 pkt
->sd_offset
= state
->offset
;
480 * There is no more data in
482 * Thus, we don't have the
483 * initial data offset for
489 state
->num_bytes
= num_bytes
;
497 * Control Escape octet for octet-stuffed
498 * RFC 1662 HDLC-like framing.
502 * Control Escape not preceded by
503 * Control Escape; discard it
504 * but XOR the next octet with
511 * Control Escape preceded by Control Escape;
512 * treat it as an ordinary character,
513 * by falling through.
519 * This character was preceded by
520 * Control Escape, so XOR it with
521 * 0x20, as per RFC 1662's octet-
522 * stuffed framing, and clear
523 * the flag saying that the
524 * character should be escaped.
530 if (pkt
->cnt
>= PPPD_BUF_SIZE
) {
531 *err
= WTAP_ERR_UNC_OVERFLOW
;
534 pkt
->buf
[pkt
->cnt
++] = c
;
539 /* we could have run out of bytes to read */
543 /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
545 collate(pppdump_t
* state
, FILE_T fh
, int *err
, gchar
**err_info
, guint8
*pd
,
546 int *num_bytes
, direction_enum
*direction
, pkt_id
*pid
,
547 gint64 num_bytes_to_skip
)
552 int n
, num_written
= 0;
558 * Process any data left over in the current record when doing
559 * sequential processing.
561 if (state
->num_bytes
> 0) {
562 g_assert(num_bytes_to_skip
== 0);
564 num_written
= process_data(state
, fh
, pkt
, state
->num_bytes
,
565 pd
, err
, err_info
, pid
);
567 if (num_written
< 0) {
570 else if (num_written
> 0) {
571 *num_bytes
= num_written
;
572 *direction
= pkt
->dir
;
575 /* if 0 bytes written, keep processing */
578 * We didn't have any data left over, so the packet will
579 * start at the beginning of a record.
582 pid
->num_bytes_to_skip
= 0;
586 * That didn't get all the data for this packet, so process
587 * subsequent records.
589 start_offset
= state
->offset
;
590 while ((id
= file_getc(fh
)) != EOF
) {
595 pkt
= id
== PPPD_SENT_DATA
? &state
->spkt
: &state
->rpkt
;
598 * Save the offset of the beginning of
599 * the current record.
601 pkt
->cd_offset
= state
->offset
- 1;
604 * Get the length of the record.
606 byte0
= file_getc(fh
);
610 byte1
= file_getc(fh
);
614 n
= (byte0
<< 8) | byte1
;
616 if (pkt
->id_offset
== 0) {
618 * We don't have the initial data
619 * offset for this packet, which
620 * means this is the first
621 * data record for that packet.
622 * Save the offset of the
623 * beginning of that record and
624 * the offset of the first data
625 * byte in the packet, which is
626 * the first data byte in the
629 pkt
->id_offset
= pkt
->cd_offset
;
630 pkt
->sd_offset
= state
->offset
;
636 g_assert(num_bytes_to_skip
< n
);
637 while (num_bytes_to_skip
) {
638 if (file_getc(fh
) == EOF
)
644 num_written
= process_data(state
, fh
, pkt
, n
,
645 pd
, err
, err_info
, pid
);
647 if (num_written
< 0) {
650 else if (num_written
> 0) {
651 *num_bytes
= num_written
;
652 *direction
= pkt
->dir
;
655 /* if 0 bytes written, keep looping */
658 case PPPD_SEND_DELIM
:
659 case PPPD_RECV_DELIM
:
660 /* What can we do? */
663 case PPPD_RESET_TIME
:
664 wtap_file_read_unknown_bytes(&time_long
, sizeof(guint32
), fh
, err
, err_info
);
665 state
->offset
+= sizeof(guint32
);
666 state
->timestamp
= pntohl(&time_long
);
670 case PPPD_TIME_STEP_LONG
:
671 wtap_file_read_unknown_bytes(&time_long
, sizeof(guint32
), fh
, err
, err_info
);
672 state
->offset
+= sizeof(guint32
);
673 state
->tenths
+= pntohl(&time_long
);
675 if (state
->tenths
>= 10) {
676 state
->timestamp
+= state
->tenths
/ 10;
677 state
->tenths
= state
->tenths
% 10;
682 case PPPD_TIME_STEP_SHORT
:
683 wtap_file_read_unknown_bytes(&time_short
, sizeof(guint8
), fh
, err
, err_info
);
684 state
->offset
+= sizeof(guint8
);
685 state
->tenths
+= time_short
;
687 if (state
->tenths
>= 10) {
688 state
->timestamp
+= state
->tenths
/ 10;
689 state
->tenths
= state
->tenths
% 10;
696 *err
= WTAP_ERR_BAD_FILE
;
697 *err_info
= g_strdup_printf("pppdump: bad ID byte 0x%02x", id
);
704 *err
= file_error(fh
, err_info
);
706 if (state
->offset
!= start_offset
) {
708 * We read at least one byte, so we were working
709 * on a record; an EOF means that record was
712 *err
= WTAP_ERR_SHORT_READ
;
720 /* Used to read packets in random-access fashion */
722 pppdump_seek_read(wtap
*wth
,
724 struct wtap_pkthdr
*phdr
,
732 direction_enum direction
;
735 gint64 num_bytes_to_skip
;
737 state
= (pppdump_t
*)wth
->priv
;
739 pid
= (pkt_id
*)g_ptr_array_index(state
->pids
, seek_off
);
741 *err
= WTAP_ERR_BAD_FILE
; /* XXX - better error? */
742 *err_info
= g_strdup("pppdump: PID not found for record");
746 if (file_seek(wth
->random_fh
, pid
->offset
, SEEK_SET
, err
) == -1)
749 init_state(state
->seek_state
);
750 state
->seek_state
->offset
= pid
->offset
;
752 buffer_assure_space(buf
, PPPD_BUF_SIZE
);
753 pd
= buffer_start_ptr(buf
);
756 * We'll start reading at the first record containing data from
757 * this packet; however, that doesn't mean "collate()" will
758 * stop only when we've read that packet, as there might be
759 * data for packets going in the other direction as well, and
760 * we might finish processing one of those packets before we
761 * finish processing the packet we're reading.
763 * Therefore, we keep reading until we get a packet that's
764 * going in the direction we want.
766 num_bytes_to_skip
= pid
->num_bytes_to_skip
;
768 if (!collate(state
->seek_state
, wth
->random_fh
, err
, err_info
,
769 pd
, &num_bytes
, &direction
, NULL
, num_bytes_to_skip
))
771 num_bytes_to_skip
= 0;
772 } while (direction
!= pid
->dir
);
774 if (len
!= num_bytes
) {
775 *err
= WTAP_ERR_BAD_FILE
; /* XXX - better error? */
776 *err_info
= g_strdup_printf("pppdump: requested length %d doesn't match record length %d",
781 pppdump_set_phdr(phdr
, num_bytes
, pid
->dir
);
787 pppdump_close(wtap
*wth
)
791 state
= (pppdump_t
*)wth
->priv
;
793 if (state
->seek_state
) { /* should always be TRUE */
794 g_free(state
->seek_state
);
799 for (i
= 0; i
< g_ptr_array_len(state
->pids
); i
++) {
800 g_free(g_ptr_array_index(state
->pids
, i
));
802 g_ptr_array_free(state
->pids
, TRUE
);