3 * $Id: pppdump.c,v 1.9 2001/10/04 08:30:36 guy Exp $
5 * Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
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>
41 | 0x07 +------+------+------+ Reset time
42 | t3 | t2 | t1 | t0 | t = time_t
43 +------+------+------+------+
46 | 0x06 | Time step (short)
47 | ts | ts = time step (tenths)
51 | 0x05 +------+------+------+ Time step (long)
52 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths)
53 +------+------+------+------+
56 | 0x04 | Receive deliminator (not seen in practice)
60 | 0x03 | Send deliminator (not seen in practice)
64 | 0x02 +------+ Received data
65 | n1 | n0 | n = number of bytes following
70 | 0x01 +------+ Sent data
71 | n1 | n0 | n = number of bytes following
76 #define PPPD_SENT_DATA 0x01
77 #define PPPD_RECV_DATA 0x02
78 #define PPPD_SEND_DELIM 0x03
79 #define PPPD_RECV_DELIM 0x04
80 #define PPPD_TIME_STEP_LONG 0x05
81 #define PPPD_TIME_STEP_SHORT 0x06
82 #define PPPD_RESET_TIME 0x07
84 #define PPPD_NULL 0x00 /* For my own use */
86 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) + sizeof(lcp_header) +
87 * sizeof(ipcp_header). PPPD_MTU is *very* rarely larger than 1500 so this value is fine
89 #define PPPD_BUF_SIZE 8192
96 static gboolean pppdump_read(wtap *wth, int *err, long *data_offset);
97 static int pppdump_seek_read(wtap *wth, long seek_off,
98 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len);
102 int num_saved_states;
110 guint8 buf[PPPD_BUF_SIZE];
114 /* Partial-record state */
122 typedef struct _pppdump_t {
129 struct _pppdump_t *seek_state;
132 int num_saved_states;
136 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd, int *err,
137 gboolean *state_saved);
140 collate(pppdump_t*, FILE_T fh, int *err, guint8 *pd, int *num_bytes,
141 direction_enum *direction, pkt_id *pid);
144 pppdump_close(wtap *wth);
147 init_state(pppdump_t *state)
152 state->spkt.dir = DIRECTION_SENT;
154 state->spkt.esc = FALSE;
155 state->spkt.id_offset = 0;
157 state->rpkt.dir = DIRECTION_RECV;
159 state->rpkt.esc = FALSE;
160 state->rpkt.id_offset = 0;
162 state->seek_state = NULL;
163 state->offset = 0x100000; /* to detect errors during development */
168 pppdump_open(wtap *wth, int *err)
170 guint8 buffer[6]; /* Looking for: 0x07 t3 t2 t1 t0 ID */
173 /* There is no file header, only packet records. Fortunately for us,
174 * timestamp records are separated from packet records, so we should
175 * find an "initial time stamp" (i.e., a "reset time" record, or
176 * record type 0x07) at the beginning of the file. We'll check for
177 * that, plus a valid record following the 0x07 and the four bytes
178 * representing the timestamp.
181 wtap_file_read_unknown_bytes(buffer, sizeof(buffer), wth->fh, err);
183 if (buffer[0] == PPPD_RESET_TIME &&
184 (buffer[5] == PPPD_SENT_DATA ||
185 buffer[5] == PPPD_RECV_DATA ||
186 buffer[5] == PPPD_TIME_STEP_LONG ||
187 buffer[5] == PPPD_TIME_STEP_SHORT ||
188 buffer[5] == PPPD_RESET_TIME)) {
198 state = wth->capture.generic = g_malloc(sizeof(pppdump_t));
199 state->timestamp = pntohl(&buffer[1]);
205 file_seek(wth->fh, 5, SEEK_SET);
206 wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
207 wth->file_type = WTAP_FILE_PPPDUMP;
209 wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
210 wth->subtype_read = pppdump_read;
211 wth->subtype_seek_read = pppdump_seek_read;
212 wth->subtype_close = pppdump_close;
214 state->seek_state = g_malloc(sizeof(pppdump_t));
216 state->pids = g_ptr_array_new();
218 state->num_saved_states = 0;
223 /* Find the next packet and parse it; called from wtap_loop(). */
225 pppdump_read(wtap *wth, int *err, long *data_offset)
229 direction_enum direction;
234 buffer_assure_space(wth->frame_buffer, PPPD_BUF_SIZE);
235 buf = buffer_start_ptr(wth->frame_buffer);
237 state = wth->capture.generic;
238 pid = g_new(pkt_id, 1);
240 *err = errno; /* assume a malloc failed and set "errno" */
244 pid->num_saved_states = 0;
246 retval = collate(state, wth->fh, err, buf, &num_bytes, &direction, pid);
253 pid->dir = direction;
255 g_ptr_array_add(state->pids, pid);
256 /* The user's data_offset is not really an offset, but a packet number. */
257 *data_offset = state->pkt_cnt;
260 wth->phdr.len = num_bytes;
261 wth->phdr.caplen = num_bytes;
262 wth->phdr.ts.tv_sec = state->timestamp;
263 wth->phdr.ts.tv_usec = state->tenths * 100000;
264 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
266 wth->pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
271 #define PKT(x) (x)->dir == DIRECTION_SENT ? "SENT" : "RECV"
274 save_prec_state(pppdump_t *state, int num_bytes, pkt_t *pkt)
278 prec = g_new(prec_state, 1);
282 prec->num_bytes = num_bytes;
285 state->precs = g_list_append(state->precs, prec);
290 process_data_from_prec_state(pppdump_t *state, FILE_T fh, guint8* pd, int *err,
291 gboolean *state_saved, pkt_t **ppkt)
295 prec = state->precs->data;
297 state->precs = g_list_remove(state->precs, prec);
301 return process_data(state, fh, prec->pkt, prec->num_bytes, pd, err, state_saved);
306 /* Returns number of bytes copied for record, -1 if failure.
308 * This is modeled after pppdump.c, the utility to parse pppd log files; it comes with the ppp
312 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd, int *err,
313 gboolean *state_saved)
319 *state_saved = FALSE;
320 for (; num_bytes > 0; --num_bytes) {
326 *err = WTAP_ERR_SHORT_READ;
335 num_written = pkt->cnt - 2;
337 if (num_written <= 0) {
341 if (num_written > PPPD_BUF_SIZE) {
342 *err = WTAP_ERR_UNC_OVERFLOW;
346 memcpy(pd, pkt->buf, num_written);
350 if (!save_prec_state(state, num_bytes, pkt)) {
365 /* else fall through */
373 pkt->buf[pkt->cnt++] = c;
374 if (pkt->cnt > PPPD_BUF_SIZE) {
375 *err = WTAP_ERR_UNC_OVERFLOW;
382 /* we could have run out of bytes to read */
390 /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
392 collate(pppdump_t* state, FILE_T fh, int *err, guint8 *pd, int *num_bytes,
393 direction_enum *direction, pkt_id *pid)
397 int n, num_written = 0;
403 state->num_saved_states = 0;
406 pid->num_saved_states = state->num_saved_states;
410 while (state->precs) {
411 num_written = process_data_from_prec_state(state, fh, pd, err, &ss, &pkt);
412 state->num_saved_states++;
414 pid->num_saved_states++;
417 if (num_written < 0) {
420 else if (num_written > 0) {
421 *num_bytes = num_written;
422 *direction = pkt->dir;
424 pid->offset = pkt->id_offset;
431 /* if 0 bytes written, keep processing */
434 while ((id = file_getc(fh)) != EOF) {
439 pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
441 if (pkt->id_offset == 0) {
442 pkt->id_offset = state->offset - 1;
446 n = (n << 8) + file_getc(fh);
449 num_written = process_data(state, fh, pkt, n, pd, err, &ss);
451 if (num_written < 0) {
454 else if (num_written > 0) {
455 *num_bytes = num_written;
456 *direction = pkt->dir;
458 pid->offset = pkt->id_offset;
465 /* if 0 bytes written, keep looping */
469 case PPPD_SEND_DELIM:
470 case PPPD_RECV_DELIM:
471 /* What can we do? */
474 case PPPD_TIME_STEP_LONG:
475 wtap_file_read_unknown_bytes(&time_long, sizeof(guint32), fh, err);
476 state->offset += sizeof(guint32);
477 state->timestamp = time_long;
481 case PPPD_RESET_TIME:
482 wtap_file_read_unknown_bytes(&time_long, sizeof(guint32), fh, err);
483 state->offset += sizeof(guint32);
484 state->tenths += time_long;
486 if (state->tenths >= 10) {
487 state->timestamp += state->tenths / 10;
488 state->tenths = state->tenths % 10;
493 case PPPD_TIME_STEP_SHORT:
494 wtap_file_read_unknown_bytes(&time_short, sizeof(guint8), fh, err);
495 state->offset += sizeof(guint8);
496 state->tenths += time_short;
498 if (state->tenths >= 10) {
499 state->timestamp += state->tenths / 10;
500 state->tenths = state->tenths % 10;
507 g_assert_not_reached();
517 /* Used to read packets in random-access fashion */
519 pppdump_seek_read (wtap *wth,
521 union wtap_pseudo_header *pseudo_header,
527 direction_enum direction;
534 state = wth->capture.generic;
536 pid = g_ptr_array_index(state->pids, seek_off);
541 file_seek(wth->random_fh, pid->offset, SEEK_SET);
543 init_state(state->seek_state);
545 for (i = 0 ; i <= pid->num_saved_states; i++) {
547 retval = collate(state->seek_state, wth->random_fh, &err, pd, &num_bytes,
554 if (direction != pid->dir) {
559 if (len != num_bytes) {
563 pseudo_header->p2p.sent = (pid->dir == DIRECTION_SENT ? TRUE : FALSE);
569 simple_g_free(gpointer data, gpointer junk)
576 pppdump_close(wtap *wth)
580 state = wth->capture.generic;
583 g_list_foreach(state->precs, simple_g_free, NULL);
584 g_list_free(state->precs);
587 if (state->seek_state) { /* should always be TRUE */
588 g_free(state->seek_state);
591 if (state->pids) { /* should always be TRUE */
592 g_ptr_array_free(state->pids, TRUE); /* free data, too */