erf: use ws_strtoi function.
[metze/wireshark/wip.git] / wiretap / pppdump.c
1 /* pppdump.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "config.h"
21 #include "wtap-int.h"
22 #include "pppdump.h"
23 #include "file_wrappers.h"
24
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28
29 /*
30 pppdump records
31 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
32
33 +------+
34 | 0x07 |                              Reset time
35 +------+------+------+------+
36 |  t3  |  t2  |  t1  |  t0  |         t = time_t
37 +------+------+------+------+
38
39 +------+
40 | 0x06 |                              Time step (short)
41 +------+
42 |  ts  |                              ts = time step (tenths of seconds)
43 +------+
44
45 +------+
46 | 0x05 |                              Time step (long)
47 +------+------+------+------+
48 | ts3  | ts2  | ts1  | ts0  |         ts = time step (tenths of seconds)
49 +------+------+------+------+
50
51 +------+
52 | 0x04 |                              Receive deliminator (not seen in practice)
53 +------+
54
55 +------+
56 | 0x03 |                              Send deliminator (not seen in practice)
57 +------+
58
59 +------+
60 | 0x02 |                              Received data
61 +------+------+
62 |  n1  |  n0  |                       n = number of bytes following
63 +------+------+
64 |    data     |
65 |             |
66
67 +------+
68 | 0x01 |                              Sent data
69 +------+------+
70 |  n1  |  n0  |                       n = number of bytes following
71 +------+------+
72 |    data     |
73 |             |
74 */
75
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
83
84 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
85  * sizeof(lcp_header) + sizeof(ipcp_header).  PPPD_MTU is *very* rarely
86  * larger than 1500 so this value is fine.
87  *
88  * It's less than WTAP_MAX_PACKET_SIZE, so we don't have to worry about
89  * too-large packets.
90  */
91 #define PPPD_BUF_SIZE           8192
92
93 typedef enum {
94         DIRECTION_SENT,
95         DIRECTION_RECV
96 } direction_enum;
97
98 static gboolean pppdump_read(wtap *wth, int *err, gchar **err_info,
99         gint64 *data_offset);
100 static gboolean pppdump_seek_read(wtap *wth, gint64 seek_off,
101         struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
102
103 /*
104  * Information saved about a packet, during the initial sequential pass
105  * through the file, to allow us to later re-read it when randomly
106  * reading packets.
107  *
108  * "offset" is the offset in the file of the first data chunk containing data
109  * from that packet; note that it may also contain data from previous
110  * packets.
111  *
112  * "num_bytes_to_skip" is the number of bytes from previous packets in that
113  * first data chunk.
114  *
115  * "dir" is the direction of the packet.
116  */
117 typedef struct {
118         gint64          offset;
119         gint64          num_bytes_to_skip;
120         direction_enum  dir;
121 } pkt_id;
122
123 /*
124  * Information about a packet currently being processed.  There is one of
125  * these for the sent packet being processed and one of these for the
126  * received packet being processed, as we could be in the middle of
127  * processing both a received packet and a sent packet.
128  *
129  * "dir" is the direction of the packet.
130  *
131  * "cnt" is the number of bytes of packet data we've accumulated.
132  *
133  * "esc" is TRUE if the next byte we see is escaped (and thus must be XORed
134  * with 0x20 before saving it), FALSE otherwise.
135  *
136  * "buf" is a buffer containing the packet data we've accumulated.
137  *
138  * "id_offset" is the offset in the file of the first data chunk
139  * containing data from the packet we're processing.
140  *
141  * "sd_offset" is the offset in the file of the first data byte from
142  * the packet we're processing - which isn't necessarily right after
143  * the header of the first data chunk, as we may already have assembled
144  * packets from that chunk.
145  *
146  * "cd_offset" is the offset in the file of the current data chunk we're
147  * processing.
148  */
149 typedef struct {
150         direction_enum  dir;
151         int             cnt;
152         gboolean        esc;
153         guint8          buf[PPPD_BUF_SIZE];
154         gint64          id_offset;
155         gint64          sd_offset;
156         gint64          cd_offset;
157 } pkt_t;
158
159 /*
160  * This keeps state used while processing records.
161  *
162  * "timestamp" is the seconds portion of the current time stamp value,
163  * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
164  * PPPD_TIME_STEP_SHORT records.  "tenths" is the tenths-of-seconds
165  * portion.
166  *
167  * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
168  * packets we're currently working on.
169  *
170  * "offset" is the current offset in the file.
171  *
172  * "num_bytes" and "pkt" are information saved when we finish accumulating
173  * the data for a packet, if the data chunk we're working on still has more
174  * data in it:
175  *
176  *      "num_bytes" is the number of bytes of additional data remaining
177  *      in the chunk after we've finished accumulating the data for the
178  *      packet.
179  *
180  *      "pkt" is the "pkt_t" for the type of packet the data chunk is for
181  *      (sent or received packet).
182  *
183  * "seek_state" is another state structure used while processing records
184  * when doing a seek-and-read.  (That structure doesn't itself have a
185  * "seek_state" structure.)
186  *
187  * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
188  * packets we've seen during the initial sequential pass, to allow us to
189  * later retrieve them with random accesses.
190  *
191  * "pkt_cnt" is the number of packets we've seen up to this point in the
192  * sequential pass.
193  */
194 typedef struct _pppdump_t {
195         time_t                  timestamp;
196         guint                   tenths;
197         pkt_t                   spkt;
198         pkt_t                   rpkt;
199         gint64                  offset;
200         int                     num_bytes;
201         pkt_t                   *pkt;
202         struct _pppdump_t       *seek_state;
203         GPtrArray               *pids;
204         guint                   pkt_cnt;
205 } pppdump_t;
206
207 static int
208 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
209     int *err, gchar **err_info, pkt_id *pid);
210
211 static gboolean
212 collate(pppdump_t*, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
213                 int *num_bytes, direction_enum *direction, pkt_id *pid,
214                 gint64 num_bytes_to_skip);
215
216 static void
217 pppdump_close(wtap *wth);
218
219 static void
220 init_state(pppdump_t *state)
221 {
222
223         state->num_bytes = 0;
224         state->pkt = NULL;
225
226         state->spkt.dir = DIRECTION_SENT;
227         state->spkt.cnt = 0;
228         state->spkt.esc = FALSE;
229         state->spkt.id_offset = 0;
230         state->spkt.sd_offset = 0;
231         state->spkt.cd_offset = 0;
232
233         state->rpkt.dir = DIRECTION_RECV;
234         state->rpkt.cnt = 0;
235         state->rpkt.esc = FALSE;
236         state->rpkt.id_offset = 0;
237         state->rpkt.sd_offset = 0;
238         state->rpkt.cd_offset = 0;
239
240         state->seek_state = NULL;
241         state->offset = 0x100000; /* to detect errors during development */
242 }
243
244
245 wtap_open_return_val
246 pppdump_open(wtap *wth, int *err, gchar **err_info)
247 {
248         guint8          buffer[6];      /* Looking for: 0x07 t3 t2 t1 t0 ID */
249         pppdump_t       *state;
250
251         /* There is no file header, only packet records. Fortunately for us,
252         * timestamp records are separated from packet records, so we should
253         * find an "initial time stamp" (i.e., a "reset time" record, or
254         * record type 0x07) at the beginning of the file. We'll check for
255         * that, plus a valid record following the 0x07 and the four bytes
256         * representing the timestamp.
257         */
258
259         if (!wtap_read_bytes(wth->fh, buffer, sizeof(buffer),
260             err, err_info)) {
261                 if (*err != WTAP_ERR_SHORT_READ)
262                         return WTAP_OPEN_ERROR;
263                 return WTAP_OPEN_NOT_MINE;
264         }
265
266         if (buffer[0] == PPPD_RESET_TIME &&
267                         (buffer[5] == PPPD_SENT_DATA ||
268                          buffer[5] == PPPD_RECV_DATA ||
269                          buffer[5] == PPPD_TIME_STEP_LONG ||
270                          buffer[5] == PPPD_TIME_STEP_SHORT ||
271                          buffer[5] == PPPD_RESET_TIME)) {
272
273                 goto my_file_type;
274         }
275         else {
276                 return WTAP_OPEN_NOT_MINE;
277         }
278
279   my_file_type:
280
281         if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
282                 return WTAP_OPEN_ERROR;
283
284         state = (pppdump_t *)g_malloc(sizeof(pppdump_t));
285         wth->priv = (void *)state;
286         state->timestamp = pntoh32(&buffer[1]);
287         state->tenths = 0;
288
289         init_state(state);
290
291         state->offset = 5;
292         wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
293         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PPPDUMP;
294
295         wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
296         wth->subtype_read = pppdump_read;
297         wth->subtype_seek_read = pppdump_seek_read;
298         wth->subtype_close = pppdump_close;
299         wth->file_tsprec = WTAP_TSPREC_DSEC;
300
301         state->seek_state = g_new(pppdump_t,1);
302
303         /* If we have a random stream open, we're going to be reading
304            the file randomly; set up a GPtrArray of pointers to
305            information about how to retrieve the data for each packet. */
306         if (wth->random_fh != NULL)
307                 state->pids = g_ptr_array_new();
308         else
309                 state->pids = NULL;
310         state->pkt_cnt = 0;
311
312         return WTAP_OPEN_MINE;
313 }
314
315 /* Set part of the struct wtap_pkthdr. */
316 static void
317 pppdump_set_phdr(struct wtap_pkthdr *phdr, int num_bytes,
318     direction_enum direction)
319 {
320         phdr->rec_type = REC_TYPE_PACKET;
321         phdr->len = num_bytes;
322         phdr->caplen = num_bytes;
323         phdr->pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
324
325         phdr->pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
326 }
327
328 /* Find the next packet and parse it; called from wtap_read(). */
329 static gboolean
330 pppdump_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
331 {
332         int             num_bytes;
333         direction_enum  direction;
334         guint8          *buf;
335         pppdump_t       *state;
336         pkt_id          *pid;
337
338         state = (pppdump_t *)wth->priv;
339
340         /* If we have a random stream open, allocate a structure to hold
341            the information needed to read this packet's data again. */
342         if (wth->random_fh != NULL) {
343                 pid = g_new(pkt_id, 1);
344                 if (!pid) {
345                         *err = errno;   /* assume a malloc failed and set "errno" */
346                         return FALSE;
347                 }
348                 pid->offset = 0;
349         } else
350                 pid = NULL;     /* sequential only */
351
352         ws_buffer_assure_space(wth->frame_buffer, PPPD_BUF_SIZE);
353         buf = ws_buffer_start_ptr(wth->frame_buffer);
354
355         if (!collate(state, wth->fh, err, err_info, buf, &num_bytes, &direction,
356             pid, 0)) {
357                 if (pid != NULL)
358                         g_free(pid);
359                 return FALSE;
360         }
361
362         if (pid != NULL)
363                 pid->dir = direction;
364
365         if (pid != NULL)
366                 g_ptr_array_add(state->pids, pid);
367         /* The user's data_offset is not really an offset, but a packet number. */
368         *data_offset = state->pkt_cnt;
369         state->pkt_cnt++;
370
371         pppdump_set_phdr(&wth->phdr, num_bytes, direction);
372         wth->phdr.presence_flags = WTAP_HAS_TS;
373         wth->phdr.ts.secs       = state->timestamp;
374         wth->phdr.ts.nsecs      = state->tenths * 100000000;
375
376         return TRUE;
377 }
378
379 /* Returns number of bytes copied for record, -1 if failure.
380  *
381  * This is modeled after pppdump.c, the utility to parse pppd log files; it
382  * comes with the ppp distribution.
383  */
384 static int
385 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
386     int *err, gchar **err_info, pkt_id *pid)
387 {
388         int     c;
389         int     num_bytes = n;
390         int     num_written;
391
392         for (; num_bytes > 0; --num_bytes) {
393                 c = file_getc(fh);
394                 if (c == EOF) {
395                         *err = file_error(fh, err_info);
396                         if (*err == 0) {
397                                 *err = WTAP_ERR_SHORT_READ;
398                         }
399                         return -1;
400                 }
401                 state->offset++;
402                 switch (c) {
403                         case 0x7e:
404                                 /*
405                                  * Flag Sequence for RFC 1662 HDLC-like
406                                  * framing.
407                                  *
408                                  * As this is a raw trace of octets going
409                                  * over the wire, and that might include
410                                  * the login sequence, there is no
411                                  * guarantee that *only* PPP traffic
412                                  * appears in this file, so there is no
413                                  * guarantee that the first 0x7e we see is
414                                  * a start flag sequence, and therefore we
415                                  * cannot safely ignore all characters up
416                                  * to the first 0x7e, and therefore we
417                                  * might end up with some bogus PPP
418                                  * packets.
419                                  */
420                                 if (pkt->cnt > 0) {
421                                         /*
422                                          * We've seen stuff before this,
423                                          * so this is the end of a frame.
424                                          * Make a frame out of that stuff.
425                                          */
426                                         pkt->esc = FALSE;
427
428                                         num_written = pkt->cnt;
429                                         pkt->cnt = 0;
430                                         if (num_written <= 0) {
431                                                 return 0;
432                                         }
433
434                                         if (num_written > PPPD_BUF_SIZE) {
435                                                 *err = WTAP_ERR_BAD_FILE;
436                                                 *err_info = g_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
437                                                     num_written, PPPD_BUF_SIZE);
438                                                 return -1;
439                                         }
440
441                                         memcpy(pd, pkt->buf, num_written);
442
443                                         /*
444                                          * Remember the offset of the
445                                          * first record containing data
446                                          * for this packet, and how far
447                                          * into that record to skip to
448                                          * get to the beginning of the
449                                          * data for this packet; the number
450                                          * of bytes to skip into that record
451                                          * is the file offset of the first
452                                          * byte of this packet minus the
453                                          * file offset of the first byte of
454                                          * this record, minus 3 bytes for the
455                                          * header of this record (which, if
456                                          * we re-read this record, we will
457                                          * process, not skip).
458                                          */
459                                         if (pid) {
460                                                 pid->offset = pkt->id_offset;
461                                                 pid->num_bytes_to_skip =
462                                                     pkt->sd_offset - pkt->id_offset - 3;
463                                                 g_assert(pid->num_bytes_to_skip >= 0);
464                                         }
465
466                                         num_bytes--;
467                                         if (num_bytes > 0) {
468                                                 /*
469                                                  * There's more data in this
470                                                  * record.
471                                                  * Set the initial data offset
472                                                  * for the next packet.
473                                                  */
474                                                 pkt->id_offset = pkt->cd_offset;
475                                                 pkt->sd_offset = state->offset;
476                                         } else {
477                                                 /*
478                                                  * There is no more data in
479                                                  * this record.
480                                                  * Thus, we don't have the
481                                                  * initial data offset for
482                                                  * the next packet.
483                                                  */
484                                                 pkt->id_offset = 0;
485                                                 pkt->sd_offset = 0;
486                                         }
487                                         state->num_bytes = num_bytes;
488                                         state->pkt = pkt;
489                                         return num_written;
490                                 }
491                                 break;
492
493                         case 0x7d:
494                                 /*
495                                  * Control Escape octet for octet-stuffed
496                                  * RFC 1662 HDLC-like framing.
497                                  */
498                                 if (!pkt->esc) {
499                                         /*
500                                          * Control Escape not preceded by
501                                          * Control Escape; discard it
502                                          * but XOR the next octet with
503                                          * 0x20.
504                                          */
505                                         pkt->esc = TRUE;
506                                         break;
507                                 }
508                                 /*
509                                  * Control Escape preceded by Control Escape;
510                                  * treat it as an ordinary character,
511                                  * by falling through.
512                                  */
513
514                         default:
515                                 if (pkt->esc) {
516                                         /*
517                                          * This character was preceded by
518                                          * Control Escape, so XOR it with
519                                          * 0x20, as per RFC 1662's octet-
520                                          * stuffed framing, and clear
521                                          * the flag saying that the
522                                          * character should be escaped.
523                                          */
524                                         c ^= 0x20;
525                                         pkt->esc = FALSE;
526                                 }
527
528                                 if (pkt->cnt >= PPPD_BUF_SIZE) {
529                                         *err = WTAP_ERR_BAD_FILE;
530                                         *err_info = g_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
531                                             pkt->cnt - 1, PPPD_BUF_SIZE);
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                                 if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
665                                         return FALSE;
666                                 state->offset += sizeof(guint32);
667                                 state->timestamp = pntoh32(&time_long);
668                                 state->tenths = 0;
669                                 break;
670
671                         case PPPD_TIME_STEP_LONG:
672                                 if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
673                                         return FALSE;
674                                 state->offset += sizeof(guint32);
675                                 state->tenths += pntoh32(&time_long);
676
677                                 if (state->tenths >= 10) {
678                                         state->timestamp += state->tenths / 10;
679                                         state->tenths = state->tenths % 10;
680                                 }
681
682                                 break;
683
684                         case PPPD_TIME_STEP_SHORT:
685                                 if (!wtap_read_bytes(fh, &time_short, sizeof(guint8), err, err_info))
686                                         return FALSE;
687                                 state->offset += sizeof(guint8);
688                                 state->tenths += time_short;
689
690                                 if (state->tenths >= 10) {
691                                         state->timestamp += state->tenths / 10;
692                                         state->tenths = state->tenths % 10;
693                                 }
694
695                                 break;
696
697                         default:
698                                 /* XXX - bad file */
699                                 *err = WTAP_ERR_BAD_FILE;
700                                 *err_info = g_strdup_printf("pppdump: bad ID byte 0x%02x", id);
701                                 return FALSE;
702                 }
703
704         }
705
706 done:
707         *err = file_error(fh, err_info);
708         if (*err == 0) {
709                 if (state->offset != start_offset) {
710                         /*
711                          * We read at least one byte, so we were working
712                          * on a record; an EOF means that record was
713                          * cut short.
714                          */
715                         *err = WTAP_ERR_SHORT_READ;
716                 }
717         }
718         return FALSE;
719 }
720
721
722
723 /* Used to read packets in random-access fashion */
724 static gboolean
725 pppdump_seek_read(wtap *wth,
726                  gint64 seek_off,
727                  struct wtap_pkthdr *phdr,
728                  Buffer *buf,
729                  int *err,
730                  gchar **err_info)
731 {
732         int             num_bytes;
733         guint8          *pd;
734         direction_enum  direction;
735         pppdump_t       *state;
736         pkt_id          *pid;
737         gint64          num_bytes_to_skip;
738
739         state = (pppdump_t *)wth->priv;
740
741         pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
742         if (!pid) {
743                 *err = WTAP_ERR_BAD_FILE;       /* XXX - better error? */
744                 *err_info = g_strdup("pppdump: PID not found for record");
745                 return FALSE;
746         }
747
748         if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
749                 return FALSE;
750
751         init_state(state->seek_state);
752         state->seek_state->offset = pid->offset;
753
754         ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
755         pd = ws_buffer_start_ptr(buf);
756
757         /*
758          * We'll start reading at the first record containing data from
759          * this packet; however, that doesn't mean "collate()" will
760          * stop only when we've read that packet, as there might be
761          * data for packets going in the other direction as well, and
762          * we might finish processing one of those packets before we
763          * finish processing the packet we're reading.
764          *
765          * Therefore, we keep reading until we get a packet that's
766          * going in the direction we want.
767          */
768         num_bytes_to_skip = pid->num_bytes_to_skip;
769         do {
770                 if (!collate(state->seek_state, wth->random_fh, err, err_info,
771                     pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
772                         return FALSE;
773                 num_bytes_to_skip = 0;
774         } while (direction != pid->dir);
775
776         pppdump_set_phdr(phdr, num_bytes, pid->dir);
777
778         return TRUE;
779 }
780
781 static void
782 pppdump_close(wtap *wth)
783 {
784         pppdump_t       *state;
785
786         state = (pppdump_t *)wth->priv;
787
788         if (state->seek_state) { /* should always be TRUE */
789                 g_free(state->seek_state);
790         }
791
792         if (state->pids) {
793                 unsigned int i;
794                 for (i = 0; i < g_ptr_array_len(state->pids); i++) {
795                         g_free(g_ptr_array_index(state->pids, i));
796                 }
797                 g_ptr_array_free(state->pids, TRUE);
798         }
799 }
800
801 /*
802  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
803  *
804  * Local variables:
805  * c-basic-offset: 8
806  * tab-width: 8
807  * indent-tabs-mode: t
808  * End:
809  *
810  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
811  * :indentSize=8:tabSize=8:noTabs=false:
812  */