The "file types" we have are actually combinations of types and
[metze/wireshark/wip.git] / wiretap / pppdump.c
1 /* pppdump.c
2  *
3  * $Id$
4  *
5  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include "config.h"
23 #include "wtap-int.h"
24 #include "buffer.h"
25 #include "pppdump.h"
26 #include "file_wrappers.h"
27
28 #include <glib.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33
34 /*
35 pppdump records
36 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
37
38 +------+
39 | 0x07 |                              Reset time
40 +------+------+------+------+
41 |  t3  |  t2  |  t1  |  t0  |         t = time_t
42 +------+------+------+------+
43
44 +------+
45 | 0x06 |                              Time step (short)
46 +------+
47 |  ts  |                              ts = time step (tenths of seconds)
48 +------+
49
50 +------+
51 | 0x05 |                              Time step (long)
52 +------+------+------+------+
53 | ts3  | ts2  | ts1  | ts0  |         ts = time step (tenths of seconds)
54 +------+------+------+------+
55
56 +------+
57 | 0x04 |                              Receive deliminator (not seen in practice)
58 +------+
59
60 +------+
61 | 0x03 |                              Send deliminator (not seen in practice)
62 +------+
63
64 +------+
65 | 0x02 |                              Received data
66 +------+------+
67 |  n1  |  n0  |                       n = number of bytes following
68 +------+------+
69 |    data     |
70 |             |
71
72 +------+
73 | 0x01 |                              Sent data
74 +------+------+
75 |  n1  |  n0  |                       n = number of bytes following
76 +------+------+
77 |    data     |
78 |             |
79 */
80
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
88
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.
92  */
93 #define PPPD_BUF_SIZE           8192
94
95 typedef enum {
96         DIRECTION_SENT,
97         DIRECTION_RECV
98 } direction_enum;
99
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);
105
106 /*
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.
110  *
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.
114  *
115  * "num_bytes_to_skip" is the number of bytes from previous packets in that
116  * first data chunk.
117  *
118  * "dir" is the direction of the packet.
119  */
120 typedef struct {
121         gint64          offset;
122         gint64          num_bytes_to_skip;
123         direction_enum  dir;
124 } pkt_id;
125
126 /*
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.
131  *
132  * "dir" is the direction of the packet.
133  *
134  * "cnt" is the number of bytes of packet data we've accumulated.
135  *
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.
138  *
139  * "buf" is a buffer containing the packet data we've accumulated.
140  *
141  * "id_offset" is the offset in the file of the first data chunk
142  * containing data from the packet we're processing.
143  *
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.
148  *
149  * "cd_offset" is the offset in the file of the current data chunk we're
150  * processing.
151  */
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;
161
162 /*
163  * This keeps state used while processing records.
164  *
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.
169  *
170  * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
171  * packets we're currently working on.
172  *
173  * "offset" is the current offset in the file.
174  *
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:
178  *
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.
182  *
183  *      "pkt" is the "pkt_t" for the type of packet the data chunk is for
184  *      (sent or received packet).
185  *
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.)
189  *
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.
193  *
194  * "pkt_cnt" is the number of packets we've seen up to this point in the
195  * sequential pass.
196  */
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;
209
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);
213
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);
218
219 static void
220 pppdump_close(wtap *wth);
221
222 static void
223 init_state(pppdump_t *state)
224 {
225
226         state->num_bytes = 0;
227         state->pkt = NULL;
228
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;
235
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;
242
243         state->seek_state = NULL;
244         state->offset = 0x100000; /* to detect errors during development */
245 }
246
247
248 int
249 pppdump_open(wtap *wth, int *err, gchar **err_info)
250 {
251         guint8          buffer[6];      /* Looking for: 0x07 t3 t2 t1 t0 ID */
252         int             bytes_read;
253         pppdump_t       *state;
254
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.
261         */
262
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;
269         }
270
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)) {
277
278                 goto my_file_type;
279         }
280         else {
281                 return 0;
282         }
283
284   my_file_type:
285
286         if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
287                 return -1;
288
289         state = (pppdump_t *)g_malloc(sizeof(pppdump_t));
290         wth->priv = (void *)state;
291         state->timestamp = pntohl(&buffer[1]);
292         state->tenths = 0;
293
294         init_state(state);
295
296         state->offset = 5;
297         wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
298         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PPPDUMP;
299
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;
305
306         state->seek_state = g_new(pppdump_t,1);
307
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;
316
317         return 1;
318 }
319
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)
324 {
325         phdr->len = num_bytes;
326         phdr->caplen = num_bytes;
327         phdr->pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
328
329         phdr->pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
330 }
331
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)
335 {
336         int             num_bytes;
337         direction_enum  direction;
338         guint8          *buf;
339         pppdump_t       *state;
340         pkt_id          *pid;
341
342         state = (pppdump_t *)wth->priv;
343
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;
351                 }
352                 pid->offset = 0;
353         } else
354                 pid = NULL;     /* sequential only */
355
356         buffer_assure_space(wth->frame_buffer, PPPD_BUF_SIZE);
357         buf = buffer_start_ptr(wth->frame_buffer);
358
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;
364         }
365
366         if (pid != NULL)
367                 pid->dir = direction;
368
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++;
374
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);
379
380         return TRUE;
381 }
382
383 /* Returns number of bytes copied for record, -1 if failure.
384  *
385  * This is modeled after pppdump.c, the utility to parse pppd log files; it
386  * comes with the ppp distribution.
387  */
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)
391 {
392         int     c;
393         int     num_bytes = n;
394         int     num_written;
395
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;
402                         }
403                         return -1;
404                 }
405                 state->offset++;
406                 switch (c) {
407                         case 0x7e:
408                                 /*
409                                  * Flag Sequence for RFC 1662 HDLC-like
410                                  * framing.
411                                  *
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.
423                                  */
424                                 if (pkt->cnt > 0) {
425                                         /*
426                                          * We've seen stuff before this,
427                                          * so this is the end of a frame.
428                                          * Make a frame out of that stuff.
429                                          */
430                                         pkt->esc = FALSE;
431
432                                         num_written = pkt->cnt;
433                                         pkt->cnt = 0;
434                                         if (num_written <= 0) {
435                                                 return 0;
436                                         }
437
438                                         if (num_written > PPPD_BUF_SIZE) {
439                                                 *err = WTAP_ERR_UNC_OVERFLOW;
440                                                 return -1;
441                                         }
442
443                                         memcpy(pd, pkt->buf, num_written);
444
445                                         /*
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).
460                                          */
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);
466                                         }
467
468                                         num_bytes--;
469                                         if (num_bytes > 0) {
470                                                 /*
471                                                  * There's more data in this
472                                                  * record.
473                                                  * Set the initial data offset
474                                                  * for the next packet.
475                                                  */
476                                                 pkt->id_offset = pkt->cd_offset;
477                                                 pkt->sd_offset = state->offset;
478                                         } else {
479                                                 /*
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.
485                                                  */
486                                                 pkt->id_offset = 0;
487                                                 pkt->sd_offset = 0;
488                                         }
489                                         state->num_bytes = num_bytes;
490                                         state->pkt = pkt;
491                                         return num_written;
492                                 }
493                                 break;
494
495                         case 0x7d:
496                                 /*
497                                  * Control Escape octet for octet-stuffed
498                                  * RFC 1662 HDLC-like framing.
499                                  */
500                                 if (!pkt->esc) {
501                                         /*
502                                          * Control Escape not preceded by
503                                          * Control Escape; discard it
504                                          * but XOR the next octet with
505                                          * 0x20.
506                                          */
507                                         pkt->esc = TRUE;
508                                         break;
509                                 }
510                                 /*
511                                  * Control Escape preceded by Control Escape;
512                                  * treat it as an ordinary character,
513                                  * by falling through.
514                                  */
515
516                         default:
517                                 if (pkt->esc) {
518                                         /*
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.
525                                          */
526                                         c ^= 0x20;
527                                         pkt->esc = FALSE;
528                                 }
529
530                                 if (pkt->cnt >= PPPD_BUF_SIZE) {
531                                         *err = WTAP_ERR_UNC_OVERFLOW;
532                                         return -1;
533                                 }
534                                 pkt->buf[pkt->cnt++] = c;
535                                 break;
536                 }
537         }
538
539         /* we could have run out of bytes to read */
540         return 0;
541 }
542
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)
548 {
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;
556
557         /*
558          * Process any data left over in the current record when doing
559          * sequential processing.
560          */
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);
566
567                 if (num_written < 0) {
568                         return FALSE;
569                 }
570                 else if (num_written > 0) {
571                         *num_bytes = num_written;
572                         *direction = pkt->dir;
573                         return TRUE;
574                 }
575                 /* if 0 bytes written, keep processing */
576         } else {
577                 /*
578                  * We didn't have any data left over, so the packet will
579                  * start at the beginning of a record.
580                  */
581                 if (pid)
582                         pid->num_bytes_to_skip = 0;
583         }
584
585         /*
586          * That didn't get all the data for this packet, so process
587          * subsequent records.
588          */
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;
596
597                                 /*
598                                  * Save the offset of the beginning of
599                                  * the current record.
600                                  */
601                                 pkt->cd_offset = state->offset - 1;
602
603                                 /*
604                                  * Get the length of the record.
605                                  */
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;
615
616                                 if (pkt->id_offset == 0) {
617                                         /*
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.
628                                          */
629                                         pkt->id_offset = pkt->cd_offset;
630                                         pkt->sd_offset = state->offset;
631                                 }
632
633                                 if (n == 0)
634                                         continue;
635
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--;
643                                 }
644                                 num_written = process_data(state, fh, pkt, n,
645                                     pd, err, err_info, pid);
646
647                                 if (num_written < 0) {
648                                         return FALSE;
649                                 }
650                                 else if (num_written > 0) {
651                                         *num_bytes = num_written;
652                                         *direction = pkt->dir;
653                                         return TRUE;
654                                 }
655                                 /* if 0 bytes written, keep looping */
656                                 break;
657
658                         case PPPD_SEND_DELIM:
659                         case PPPD_RECV_DELIM:
660                                 /* What can we do? */
661                                 break;
662
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;
669
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);
674
675                                 if (state->tenths >= 10) {
676                                         state->timestamp += state->tenths / 10;
677                                         state->tenths = state->tenths % 10;
678                                 }
679
680                                 break;
681
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;
686
687                                 if (state->tenths >= 10) {
688                                         state->timestamp += state->tenths / 10;
689                                         state->tenths = state->tenths % 10;
690                                 }
691
692                                 break;
693
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;
699                 }
700
701         }
702
703 done:
704         *err = file_error(fh, err_info);
705         if (*err == 0) {
706                 if (state->offset != start_offset) {
707                         /*
708                          * We read at least one byte, so we were working
709                          * on a record; an EOF means that record was
710                          * cut short.
711                          */
712                         *err = WTAP_ERR_SHORT_READ;
713                 }
714         }
715         return FALSE;
716 }
717
718
719
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)
729 {
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;
736
737         state = (pppdump_t *)wth->priv;
738
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;
744         }
745
746         if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
747                 return FALSE;
748
749         init_state(state->seek_state);
750         state->seek_state->offset = pid->offset;
751
752         buffer_assure_space(buf, PPPD_BUF_SIZE);
753         pd = buffer_start_ptr(buf);
754
755         /*
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.
762          *
763          * Therefore, we keep reading until we get a packet that's
764          * going in the direction we want.
765          */
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);
773
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;
779         }
780
781         pppdump_set_phdr(phdr, num_bytes, pid->dir);
782
783         return TRUE;
784 }
785
786 static void
787 pppdump_close(wtap *wth)
788 {
789         pppdump_t       *state;
790
791         state = (pppdump_t *)wth->priv;
792
793         if (state->seek_state) { /* should always be TRUE */
794                 g_free(state->seek_state);
795         }
796
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));
801                 }
802                 g_ptr_array_free(state->pids, TRUE);
803         }
804 }