HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / wiretap / pppdump.c
blobcc82c0948508b42d904277fd9528793a6adf7d13
1 /* pppdump.c
3 * $Id$
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.
22 #include "config.h"
23 #include "wtap-int.h"
24 #include "buffer.h"
25 #include "pppdump.h"
26 #include "file_wrappers.h"
28 #include <glib.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
35 pppdump records
36 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
38 +------+
39 | 0x07 | Reset time
40 +------+------+------+------+
41 | t3 | t2 | t1 | t0 | t = time_t
42 +------+------+------+------+
44 +------+
45 | 0x06 | Time step (short)
46 +------+
47 | ts | ts = time step (tenths of seconds)
48 +------+
50 +------+
51 | 0x05 | Time step (long)
52 +------+------+------+------+
53 | ts3 | ts2 | ts1 | ts0 | ts = time step (tenths of seconds)
54 +------+------+------+------+
56 +------+
57 | 0x04 | Receive deliminator (not seen in practice)
58 +------+
60 +------+
61 | 0x03 | Send deliminator (not seen in practice)
62 +------+
64 +------+
65 | 0x02 | Received data
66 +------+------+
67 | n1 | n0 | n = number of bytes following
68 +------+------+
69 | data |
70 | |
72 +------+
73 | 0x01 | Sent data
74 +------+------+
75 | n1 | n0 | n = number of bytes following
76 +------+------+
77 | data |
78 | |
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
95 typedef enum {
96 DIRECTION_SENT,
97 DIRECTION_RECV
98 } direction_enum;
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
109 * reading packets.
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
113 * packets.
115 * "num_bytes_to_skip" is the number of bytes from previous packets in that
116 * first data chunk.
118 * "dir" is the direction of the packet.
120 typedef struct {
121 gint64 offset;
122 gint64 num_bytes_to_skip;
123 direction_enum dir;
124 } pkt_id;
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
150 * processing.
152 typedef struct {
153 direction_enum dir;
154 int cnt;
155 gboolean esc;
156 guint8 buf[PPPD_BUF_SIZE];
157 gint64 id_offset;
158 gint64 sd_offset;
159 gint64 cd_offset;
160 } pkt_t;
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
168 * portion.
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
177 * data in it:
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
181 * packet.
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
195 * sequential pass.
197 typedef struct _pppdump_t {
198 time_t timestamp;
199 guint tenths;
200 pkt_t spkt;
201 pkt_t rpkt;
202 gint64 offset;
203 int num_bytes;
204 pkt_t *pkt;
205 struct _pppdump_t *seek_state;
206 GPtrArray *pids;
207 guint pkt_cnt;
208 } pppdump_t;
210 static int
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);
214 static gboolean
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);
219 static void
220 pppdump_close(wtap *wth);
222 static void
223 init_state(pppdump_t *state)
226 state->num_bytes = 0;
227 state->pkt = NULL;
229 state->spkt.dir = DIRECTION_SENT;
230 state->spkt.cnt = 0;
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;
237 state->rpkt.cnt = 0;
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 */
252 int bytes_read;
253 pppdump_t *state;
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)
267 return -1;
268 return 0;
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)) {
278 goto my_file_type;
280 else {
281 return 0;
284 my_file_type:
286 if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
287 return -1;
289 state = (pppdump_t *)g_malloc(sizeof(pppdump_t));
290 wth->priv = (void *)state;
291 state->timestamp = pntohl(&buffer[1]);
292 state->tenths = 0;
294 init_state(state);
296 state->offset = 5;
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();
313 else
314 state->pids = NULL;
315 state->pkt_cnt = 0;
317 return 1;
320 /* Set part of the struct wtap_pkthdr. */
321 static void
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(). */
333 static gboolean
334 pppdump_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
336 int num_bytes;
337 direction_enum direction;
338 guint8 *buf;
339 pppdump_t *state;
340 pkt_id *pid;
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);
348 if (!pid) {
349 *err = errno; /* assume a malloc failed and set "errno" */
350 return FALSE;
352 pid->offset = 0;
353 } else
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,
360 pid, 0)) {
361 if (pid != NULL)
362 g_free(pid);
363 return FALSE;
366 if (pid != NULL)
367 pid->dir = direction;
369 if (pid != NULL)
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;
373 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);
380 return TRUE;
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.
388 static int
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)
392 int c;
393 int num_bytes = n;
394 int num_written;
396 for (; num_bytes > 0; --num_bytes) {
397 c = file_getc(fh);
398 if (c == EOF) {
399 *err = file_error(fh, err_info);
400 if (*err == 0) {
401 *err = WTAP_ERR_SHORT_READ;
403 return -1;
405 state->offset++;
406 switch (c) {
407 case 0x7e:
409 * Flag Sequence for RFC 1662 HDLC-like
410 * framing.
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
422 * packets.
424 if (pkt->cnt > 0) {
426 * We've seen stuff before this,
427 * so this is the end of a frame.
428 * Make a frame out of that stuff.
430 pkt->esc = FALSE;
432 num_written = pkt->cnt;
433 pkt->cnt = 0;
434 if (num_written <= 0) {
435 return 0;
438 if (num_written > PPPD_BUF_SIZE) {
439 *err = WTAP_ERR_UNC_OVERFLOW;
440 return -1;
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).
461 if (pid) {
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);
468 num_bytes--;
469 if (num_bytes > 0) {
471 * There's more data in this
472 * record.
473 * Set the initial data offset
474 * for the next packet.
476 pkt->id_offset = pkt->cd_offset;
477 pkt->sd_offset = state->offset;
478 } else {
480 * There is no more data in
481 * this record.
482 * Thus, we don't have the
483 * initial data offset for
484 * the next packet.
486 pkt->id_offset = 0;
487 pkt->sd_offset = 0;
489 state->num_bytes = num_bytes;
490 state->pkt = pkt;
491 return num_written;
493 break;
495 case 0x7d:
497 * Control Escape octet for octet-stuffed
498 * RFC 1662 HDLC-like framing.
500 if (!pkt->esc) {
502 * Control Escape not preceded by
503 * Control Escape; discard it
504 * but XOR the next octet with
505 * 0x20.
507 pkt->esc = TRUE;
508 break;
511 * Control Escape preceded by Control Escape;
512 * treat it as an ordinary character,
513 * by falling through.
516 default:
517 if (pkt->esc) {
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.
526 c ^= 0x20;
527 pkt->esc = FALSE;
530 if (pkt->cnt >= PPPD_BUF_SIZE) {
531 *err = WTAP_ERR_UNC_OVERFLOW;
532 return -1;
534 pkt->buf[pkt->cnt++] = c;
535 break;
539 /* we could have run out of bytes to read */
540 return 0;
543 /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
544 static gboolean
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)
549 int id;
550 pkt_t *pkt = NULL;
551 int byte0, byte1;
552 int n, num_written = 0;
553 gint64 start_offset;
554 guint32 time_long;
555 guint8 time_short;
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);
563 pkt = state->pkt;
564 num_written = process_data(state, fh, pkt, state->num_bytes,
565 pd, err, err_info, pid);
567 if (num_written < 0) {
568 return FALSE;
570 else if (num_written > 0) {
571 *num_bytes = num_written;
572 *direction = pkt->dir;
573 return TRUE;
575 /* if 0 bytes written, keep processing */
576 } else {
578 * We didn't have any data left over, so the packet will
579 * start at the beginning of a record.
581 if (pid)
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) {
591 state->offset++;
592 switch (id) {
593 case PPPD_SENT_DATA:
594 case PPPD_RECV_DATA:
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);
607 if (byte0 == EOF)
608 goto done;
609 state->offset++;
610 byte1 = file_getc(fh);
611 if (byte1 == EOF)
612 goto done;
613 state->offset++;
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
627 * record.
629 pkt->id_offset = pkt->cd_offset;
630 pkt->sd_offset = state->offset;
633 if (n == 0)
634 continue;
636 g_assert(num_bytes_to_skip < n);
637 while (num_bytes_to_skip) {
638 if (file_getc(fh) == EOF)
639 goto done;
640 state->offset++;
641 num_bytes_to_skip--;
642 n--;
644 num_written = process_data(state, fh, pkt, n,
645 pd, err, err_info, pid);
647 if (num_written < 0) {
648 return FALSE;
650 else if (num_written > 0) {
651 *num_bytes = num_written;
652 *direction = pkt->dir;
653 return TRUE;
655 /* if 0 bytes written, keep looping */
656 break;
658 case PPPD_SEND_DELIM:
659 case PPPD_RECV_DELIM:
660 /* What can we do? */
661 break;
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);
667 state->tenths = 0;
668 break;
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;
680 break;
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;
692 break;
694 default:
695 /* XXX - bad file */
696 *err = WTAP_ERR_BAD_FILE;
697 *err_info = g_strdup_printf("pppdump: bad ID byte 0x%02x", id);
698 return FALSE;
703 done:
704 *err = file_error(fh, err_info);
705 if (*err == 0) {
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
710 * cut short.
712 *err = WTAP_ERR_SHORT_READ;
715 return FALSE;
720 /* Used to read packets in random-access fashion */
721 static gboolean
722 pppdump_seek_read(wtap *wth,
723 gint64 seek_off,
724 struct wtap_pkthdr *phdr,
725 Buffer *buf,
726 int len,
727 int *err,
728 gchar **err_info)
730 int num_bytes;
731 guint8 *pd;
732 direction_enum direction;
733 pppdump_t *state;
734 pkt_id *pid;
735 gint64 num_bytes_to_skip;
737 state = (pppdump_t *)wth->priv;
739 pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
740 if (!pid) {
741 *err = WTAP_ERR_BAD_FILE; /* XXX - better error? */
742 *err_info = g_strdup("pppdump: PID not found for record");
743 return FALSE;
746 if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
747 return FALSE;
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;
767 do {
768 if (!collate(state->seek_state, wth->random_fh, err, err_info,
769 pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
770 return FALSE;
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",
777 len, num_bytes);
778 return FALSE;
781 pppdump_set_phdr(phdr, num_bytes, pid->dir);
783 return TRUE;
786 static void
787 pppdump_close(wtap *wth)
789 pppdump_t *state;
791 state = (pppdump_t *)wth->priv;
793 if (state->seek_state) { /* should always be TRUE */
794 g_free(state->seek_state);
797 if (state->pids) {
798 unsigned int i;
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);