1 /* pppdump.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  */
7 
8 #include "config.h"
9 #include "wtap-int.h"
10 #include "pppdump.h"
11 #include "file_wrappers.h"
12 
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <string.h>
16 
17 #include <wsutil/ws_assert.h>
18 
19 /*
20 pppdump records
21 Daniel Thompson (STMicroelectronics) <daniel.thompson@st.com>
22 
23 +------+
24 | 0x07 |                              Reset time
25 +------+------+------+------+
26 |  t3  |  t2  |  t1  |  t0  |         t = time_t
27 +------+------+------+------+
28 
29 +------+
30 | 0x06 |                              Time step (short)
31 +------+
32 |  ts  |                              ts = time step (tenths of seconds)
33 +------+
34 
35 +------+
36 | 0x05 |                              Time step (long)
37 +------+------+------+------+
38 | ts3  | ts2  | ts1  | ts0  |         ts = time step (tenths of seconds)
39 +------+------+------+------+
40 
41 +------+
42 | 0x04 |                              Receive deliminator (not seen in practice)
43 +------+
44 
45 +------+
46 | 0x03 |                              Send deliminator (not seen in practice)
47 +------+
48 
49 +------+
50 | 0x02 |                              Received data
51 +------+------+
52 |  n1  |  n0  |                       n = number of bytes following
53 +------+------+
54 |    data     |
55 |             |
56 
57 +------+
58 | 0x01 |                              Sent data
59 +------+------+
60 |  n1  |  n0  |                       n = number of bytes following
61 +------+------+
62 |    data     |
63 |             |
64 */
65 
66 #define PPPD_SENT_DATA		0x01
67 #define PPPD_RECV_DATA		0x02
68 #define PPPD_SEND_DELIM		0x03
69 #define PPPD_RECV_DELIM		0x04
70 #define PPPD_TIME_STEP_LONG	0x05
71 #define PPPD_TIME_STEP_SHORT	0x06
72 #define PPPD_RESET_TIME		0x07
73 
74 /* this buffer must be at least (2*PPPD_MTU) + sizeof(ppp_header) +
75  * sizeof(lcp_header) + sizeof(ipcp_header).  PPPD_MTU is *very* rarely
76  * larger than 1500 so this value is fine.
77  *
78  * It's less than WTAP_MAX_PACKET_SIZE_STANDARD, so we don't have to worry about
79  * too-large packets.
80  */
81 #define PPPD_BUF_SIZE		8192
82 
83 typedef enum {
84 	DIRECTION_SENT,
85 	DIRECTION_RECV
86 } direction_enum;
87 
88 static gboolean pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf,
89 	int *err, gchar **err_info, gint64 *data_offset);
90 static gboolean pppdump_seek_read(wtap *wth, gint64 seek_off,
91 	wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
92 
93 static int pppdump_file_type_subtype = -1;
94 
95 void register_pppdump(void);
96 
97 /*
98  * Information saved about a packet, during the initial sequential pass
99  * through the file, to allow us to later re-read it when randomly
100  * reading packets.
101  *
102  * "offset" is the offset in the file of the first data chunk containing data
103  * from that packet; note that it may also contain data from previous
104  * packets.
105  *
106  * "num_bytes_to_skip" is the number of bytes from previous packets in that
107  * first data chunk.
108  *
109  * "dir" is the direction of the packet.
110  */
111 typedef struct {
112 	gint64		offset;
113 	gint64		num_bytes_to_skip;
114 	direction_enum	dir;
115 } pkt_id;
116 
117 /*
118  * Information about a packet currently being processed.  There is one of
119  * these for the sent packet being processed and one of these for the
120  * received packet being processed, as we could be in the middle of
121  * processing both a received packet and a sent packet.
122  *
123  * "dir" is the direction of the packet.
124  *
125  * "cnt" is the number of bytes of packet data we've accumulated.
126  *
127  * "esc" is TRUE if the next byte we see is escaped (and thus must be XORed
128  * with 0x20 before saving it), FALSE otherwise.
129  *
130  * "buf" is a buffer containing the packet data we've accumulated.
131  *
132  * "id_offset" is the offset in the file of the first data chunk
133  * containing data from the packet we're processing.
134  *
135  * "sd_offset" is the offset in the file of the first data byte from
136  * the packet we're processing - which isn't necessarily right after
137  * the header of the first data chunk, as we may already have assembled
138  * packets from that chunk.
139  *
140  * "cd_offset" is the offset in the file of the current data chunk we're
141  * processing.
142  */
143 typedef struct {
144 	direction_enum	dir;
145 	int		cnt;
146 	gboolean	esc;
147 	guint8		buf[PPPD_BUF_SIZE];
148 	gint64		id_offset;
149 	gint64		sd_offset;
150 	gint64		cd_offset;
151 } pkt_t;
152 
153 /*
154  * This keeps state used while processing records.
155  *
156  * "timestamp" is the seconds portion of the current time stamp value,
157  * as updated from PPPD_RESET_TIME, PPPD_TIME_STEP_LONG, and
158  * PPPD_TIME_STEP_SHORT records.  "tenths" is the tenths-of-seconds
159  * portion.
160  *
161  * "spkt" and "rpkt" are "pkt_t" structures for the sent and received
162  * packets we're currently working on.
163  *
164  * "offset" is the current offset in the file.
165  *
166  * "num_bytes" and "pkt" are information saved when we finish accumulating
167  * the data for a packet, if the data chunk we're working on still has more
168  * data in it:
169  *
170  *	"num_bytes" is the number of bytes of additional data remaining
171  *	in the chunk after we've finished accumulating the data for the
172  *	packet.
173  *
174  *	"pkt" is the "pkt_t" for the type of packet the data chunk is for
175  *	(sent or received packet).
176  *
177  * "seek_state" is another state structure used while processing records
178  * when doing a seek-and-read.  (That structure doesn't itself have a
179  * "seek_state" structure.)
180  *
181  * "pids" is a GPtrArray of pointers to "pkt_id" structures for all the
182  * packets we've seen during the initial sequential pass, to allow us to
183  * later retrieve them with random accesses.
184  *
185  * "pkt_cnt" is the number of packets we've seen up to this point in the
186  * sequential pass.
187  */
188 typedef struct _pppdump_t {
189 	time_t			timestamp;
190 	guint			tenths;
191 	pkt_t			spkt;
192 	pkt_t			rpkt;
193 	gint64			offset;
194 	int			num_bytes;
195 	pkt_t			*pkt;
196 	struct _pppdump_t	*seek_state;
197 	GPtrArray		*pids;
198 	guint			pkt_cnt;
199 } pppdump_t;
200 
201 static int
202 process_data(pppdump_t *state, FILE_T fh, pkt_t *pkt, int n, guint8 *pd,
203     int *err, gchar **err_info, pkt_id *pid);
204 
205 static gboolean
206 collate(pppdump_t *state, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
207 		int *num_bytes, direction_enum *direction, pkt_id *pid,
208 		gint64 num_bytes_to_skip);
209 
210 static void
211 pppdump_close(wtap *wth);
212 
213 static void
init_state(pppdump_t * state)214 init_state(pppdump_t *state)
215 {
216 
217 	state->num_bytes = 0;
218 	state->pkt = NULL;
219 
220 	state->spkt.dir = DIRECTION_SENT;
221 	state->spkt.cnt = 0;
222 	state->spkt.esc = FALSE;
223 	state->spkt.id_offset = 0;
224 	state->spkt.sd_offset = 0;
225 	state->spkt.cd_offset = 0;
226 
227 	state->rpkt.dir = DIRECTION_RECV;
228 	state->rpkt.cnt = 0;
229 	state->rpkt.esc = FALSE;
230 	state->rpkt.id_offset = 0;
231 	state->rpkt.sd_offset = 0;
232 	state->rpkt.cd_offset = 0;
233 
234 	state->seek_state = NULL;
235 	state->offset = 0x100000; /* to detect errors during development */
236 }
237 
238 
239 wtap_open_return_val
pppdump_open(wtap * wth,int * err,gchar ** err_info)240 pppdump_open(wtap *wth, int *err, gchar **err_info)
241 {
242 	guint8		buffer[6];	/* Looking for: 0x07 t3 t2 t1 t0 ID */
243 	pppdump_t	*state;
244 
245 	/* There is no file header, only packet records. Fortunately for us,
246 	* timestamp records are separated from packet records, so we should
247 	* find an "initial time stamp" (i.e., a "reset time" record, or
248 	* record type 0x07) at the beginning of the file. We'll check for
249 	* that, plus a valid record following the 0x07 and the four bytes
250 	* representing the timestamp.
251 	*/
252 
253 	if (!wtap_read_bytes(wth->fh, buffer, sizeof(buffer),
254 	    err, err_info)) {
255 		if (*err != WTAP_ERR_SHORT_READ)
256 			return WTAP_OPEN_ERROR;
257 		return WTAP_OPEN_NOT_MINE;
258 	}
259 
260 	if (buffer[0] == PPPD_RESET_TIME &&
261 			(buffer[5] == PPPD_SENT_DATA ||
262 			 buffer[5] == PPPD_RECV_DATA ||
263 			 buffer[5] == PPPD_TIME_STEP_LONG ||
264 			 buffer[5] == PPPD_TIME_STEP_SHORT ||
265 			 buffer[5] == PPPD_RESET_TIME)) {
266 
267 		goto my_file_type;
268 	}
269 	else {
270 		return WTAP_OPEN_NOT_MINE;
271 	}
272 
273   my_file_type:
274 
275 	if (file_seek(wth->fh, 5, SEEK_SET, err) == -1)
276 		return WTAP_OPEN_ERROR;
277 
278 	state = g_new(pppdump_t, 1);
279 	wth->priv = (void *)state;
280 	state->timestamp = pntoh32(&buffer[1]);
281 	state->tenths = 0;
282 
283 	init_state(state);
284 
285 	state->offset = 5;
286 	wth->file_encap = WTAP_ENCAP_PPP_WITH_PHDR;
287 	wth->file_type_subtype = pppdump_file_type_subtype;
288 
289 	wth->snapshot_length = PPPD_BUF_SIZE; /* just guessing */
290 	wth->subtype_read = pppdump_read;
291 	wth->subtype_seek_read = pppdump_seek_read;
292 	wth->subtype_close = pppdump_close;
293 	wth->file_tsprec = WTAP_TSPREC_DSEC;
294 
295 	state->seek_state = g_new(pppdump_t,1);
296 
297 	/* If we have a random stream open, we're going to be reading
298 	   the file randomly; set up a GPtrArray of pointers to
299 	   information about how to retrieve the data for each packet. */
300 	if (wth->random_fh != NULL)
301 		state->pids = g_ptr_array_new();
302 	else
303 		state->pids = NULL;
304 	state->pkt_cnt = 0;
305 
306 	/*
307 	 * Add an IDB; we don't know how many interfaces were
308 	 * involved, so we just say one interface, about which
309 	 * we only know the link-layer type, snapshot length,
310 	 * and time stamp resolution.
311 	 */
312 	wtap_add_generated_idb(wth);
313 
314 	return WTAP_OPEN_MINE;
315 }
316 
317 /* Set part of the struct wtap_rec. */
318 static void
pppdump_set_phdr(wtap_rec * rec,int num_bytes,direction_enum direction)319 pppdump_set_phdr(wtap_rec *rec, int num_bytes,
320     direction_enum direction)
321 {
322 	rec->rec_type = REC_TYPE_PACKET;
323 	rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
324 	rec->rec_header.packet_header.len = num_bytes;
325 	rec->rec_header.packet_header.caplen = num_bytes;
326 	rec->rec_header.packet_header.pkt_encap	= WTAP_ENCAP_PPP_WITH_PHDR;
327 
328 	rec->rec_header.packet_header.pseudo_header.p2p.sent = (direction == DIRECTION_SENT ? TRUE : FALSE);
329 }
330 
331 /* Find the next packet and parse it; called from wtap_read(). */
332 static gboolean
pppdump_read(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)333 pppdump_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info,
334     gint64 *data_offset)
335 {
336 	int		num_bytes;
337 	direction_enum	direction;
338 	pppdump_t	*state;
339 	pkt_id		*pid;
340 
341 	state = (pppdump_t *)wth->priv;
342 
343 	/* If we have a random stream open, allocate a structure to hold
344 	   the information needed to read this packet's data again. */
345 	if (wth->random_fh != NULL) {
346 		pid = g_new(pkt_id, 1);
347 		if (!pid) {
348 			*err = errno;	/* assume a malloc failed and set "errno" */
349 			return FALSE;
350 		}
351 		pid->offset = 0;
352 	} else
353 		pid = NULL;	/* sequential only */
354 
355 	ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
356 	if (!collate(state, wth->fh, err, err_info, ws_buffer_start_ptr(buf),
357 	    &num_bytes, &direction, pid, 0)) {
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(rec, num_bytes, direction);
372 	rec->presence_flags = WTAP_HAS_TS;
373 	rec->ts.secs = state->timestamp;
374 	rec->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
process_data(pppdump_t * state,FILE_T fh,pkt_t * pkt,int n,guint8 * pd,int * err,gchar ** err_info,pkt_id * pid)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 						ws_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 			/* FALL THROUGH */
515 			default:
516 				if (pkt->esc) {
517 					/*
518 					 * This character was preceded by
519 					 * Control Escape, so XOR it with
520 					 * 0x20, as per RFC 1662's octet-
521 					 * stuffed framing, and clear
522 					 * the flag saying that the
523 					 * character should be escaped.
524 					 */
525 					c ^= 0x20;
526 					pkt->esc = FALSE;
527 				}
528 
529 				if (pkt->cnt >= PPPD_BUF_SIZE) {
530 					*err = WTAP_ERR_BAD_FILE;
531 					*err_info = g_strdup_printf("pppdump: File has %u-byte packet, bigger than maximum of %u",
532 					    pkt->cnt - 1, PPPD_BUF_SIZE);
533 					return -1;
534 				}
535 				pkt->buf[pkt->cnt++] = c;
536 				break;
537 		}
538 	}
539 
540 	/* we could have run out of bytes to read */
541 	return 0;
542 }
543 
544 /* Returns TRUE if packet data copied, FALSE if error occurred or EOF (no more records). */
545 static gboolean
collate(pppdump_t * state,FILE_T fh,int * err,gchar ** err_info,guint8 * pd,int * num_bytes,direction_enum * direction,pkt_id * pid,gint64 num_bytes_to_skip)546 collate(pppdump_t* state, FILE_T fh, int *err, gchar **err_info, guint8 *pd,
547 		int *num_bytes, direction_enum *direction, pkt_id *pid,
548 		gint64 num_bytes_to_skip)
549 {
550 	int		id;
551 	pkt_t		*pkt = NULL;
552 	int		byte0, byte1;
553 	int		n, num_written = 0;
554 	gint64		start_offset;
555 	guint32		time_long;
556 	guint8		time_short;
557 
558 	/*
559 	 * Process any data left over in the current record when doing
560 	 * sequential processing.
561 	 */
562 	if (state->num_bytes > 0) {
563 		ws_assert(num_bytes_to_skip == 0);
564 		pkt = state->pkt;
565 		num_written = process_data(state, fh, pkt, state->num_bytes,
566 		    pd, err, err_info, pid);
567 
568 		if (num_written < 0) {
569 			return FALSE;
570 		}
571 		else if (num_written > 0) {
572 			*num_bytes = num_written;
573 			*direction = pkt->dir;
574 			return TRUE;
575 		}
576 		/* if 0 bytes written, keep processing */
577 	} else {
578 		/*
579 		 * We didn't have any data left over, so the packet will
580 		 * start at the beginning of a record.
581 		 */
582 		if (pid)
583 			pid->num_bytes_to_skip = 0;
584 	}
585 
586 	/*
587 	 * That didn't get all the data for this packet, so process
588 	 * subsequent records.
589 	 */
590 	start_offset = state->offset;
591 	while ((id = file_getc(fh)) != EOF) {
592 		state->offset++;
593 		switch (id) {
594 			case PPPD_SENT_DATA:
595 			case PPPD_RECV_DATA:
596 				pkt = id == PPPD_SENT_DATA ? &state->spkt : &state->rpkt;
597 
598 				/*
599 				 * Save the offset of the beginning of
600 				 * the current record.
601 				 */
602 				pkt->cd_offset = state->offset - 1;
603 
604 				/*
605 				 * Get the length of the record.
606 				 */
607 				byte0 = file_getc(fh);
608 				if (byte0 == EOF)
609 					goto done;
610 				state->offset++;
611 				byte1 = file_getc(fh);
612 				if (byte1 == EOF)
613 					goto done;
614 				state->offset++;
615 				n = (byte0 << 8) | byte1;
616 
617 				if (pkt->id_offset == 0) {
618 					/*
619 					 * We don't have the initial data
620 					 * offset for this packet, which
621 					 * means this is the first
622 					 * data record for that packet.
623 					 * Save the offset of the
624 					 * beginning of that record and
625 					 * the offset of the first data
626 					 * byte in the packet, which is
627 					 * the first data byte in the
628 					 * record.
629 					 */
630 					pkt->id_offset = pkt->cd_offset;
631 					pkt->sd_offset = state->offset;
632 				}
633 
634 				if (n == 0)
635 					continue;
636 
637 				ws_assert(num_bytes_to_skip < n);
638 				while (num_bytes_to_skip) {
639 					if (file_getc(fh) == EOF)
640 						goto done;
641 					state->offset++;
642 					num_bytes_to_skip--;
643 					n--;
644 				}
645 				num_written = process_data(state, fh, pkt, n,
646 				    pd, err, err_info, pid);
647 
648 				if (num_written < 0) {
649 					return FALSE;
650 				}
651 				else if (num_written > 0) {
652 					*num_bytes = num_written;
653 					*direction = pkt->dir;
654 					return TRUE;
655 				}
656 				/* if 0 bytes written, keep looping */
657 				break;
658 
659 			case PPPD_SEND_DELIM:
660 			case PPPD_RECV_DELIM:
661 				/* What can we do? */
662 				break;
663 
664 			case PPPD_RESET_TIME:
665 				if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
666 					return FALSE;
667 				state->offset += sizeof(guint32);
668 				state->timestamp = pntoh32(&time_long);
669 				state->tenths = 0;
670 				break;
671 
672 			case PPPD_TIME_STEP_LONG:
673 				if (!wtap_read_bytes(fh, &time_long, sizeof(guint32), err, err_info))
674 					return FALSE;
675 				state->offset += sizeof(guint32);
676 				state->tenths += pntoh32(&time_long);
677 
678 				if (state->tenths >= 10) {
679 					state->timestamp += state->tenths / 10;
680 					state->tenths = state->tenths % 10;
681 				}
682 
683 				break;
684 
685 			case PPPD_TIME_STEP_SHORT:
686 				if (!wtap_read_bytes(fh, &time_short, sizeof(guint8), err, err_info))
687 					return FALSE;
688 				state->offset += sizeof(guint8);
689 				state->tenths += time_short;
690 
691 				if (state->tenths >= 10) {
692 					state->timestamp += state->tenths / 10;
693 					state->tenths = state->tenths % 10;
694 				}
695 
696 				break;
697 
698 			default:
699 				/* XXX - bad file */
700 				*err = WTAP_ERR_BAD_FILE;
701 				*err_info = g_strdup_printf("pppdump: bad ID byte 0x%02x", id);
702 				return FALSE;
703 		}
704 
705 	}
706 
707 done:
708 	*err = file_error(fh, err_info);
709 	if (*err == 0) {
710 		if (state->offset != start_offset) {
711 			/*
712 			 * We read at least one byte, so we were working
713 			 * on a record; an EOF means that record was
714 			 * cut short.
715 			 */
716 			*err = WTAP_ERR_SHORT_READ;
717 		}
718 	}
719 	return FALSE;
720 }
721 
722 
723 
724 /* Used to read packets in random-access fashion */
725 static gboolean
pppdump_seek_read(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)726 pppdump_seek_read(wtap *wth,
727 		 gint64 seek_off,
728 		 wtap_rec *rec,
729 		 Buffer *buf,
730 		 int *err,
731 		 gchar **err_info)
732 {
733 	int		num_bytes;
734 	guint8		*pd;
735 	direction_enum	direction;
736 	pppdump_t	*state;
737 	pkt_id		*pid;
738 	gint64		num_bytes_to_skip;
739 
740 	state = (pppdump_t *)wth->priv;
741 
742 	pid = (pkt_id *)g_ptr_array_index(state->pids, seek_off);
743 	if (!pid) {
744 		*err = WTAP_ERR_BAD_FILE;	/* XXX - better error? */
745 		*err_info = g_strdup("pppdump: PID not found for record");
746 		return FALSE;
747 	}
748 
749 	if (file_seek(wth->random_fh, pid->offset, SEEK_SET, err) == -1)
750 		return FALSE;
751 
752 	init_state(state->seek_state);
753 	state->seek_state->offset = pid->offset;
754 
755 	ws_buffer_assure_space(buf, PPPD_BUF_SIZE);
756 	pd = ws_buffer_start_ptr(buf);
757 
758 	/*
759 	 * We'll start reading at the first record containing data from
760 	 * this packet; however, that doesn't mean "collate()" will
761 	 * stop only when we've read that packet, as there might be
762 	 * data for packets going in the other direction as well, and
763 	 * we might finish processing one of those packets before we
764 	 * finish processing the packet we're reading.
765 	 *
766 	 * Therefore, we keep reading until we get a packet that's
767 	 * going in the direction we want.
768 	 */
769 	num_bytes_to_skip = pid->num_bytes_to_skip;
770 	do {
771 		if (!collate(state->seek_state, wth->random_fh, err, err_info,
772 		    pd, &num_bytes, &direction, NULL, num_bytes_to_skip))
773 			return FALSE;
774 		num_bytes_to_skip = 0;
775 	} while (direction != pid->dir);
776 
777 	pppdump_set_phdr(rec, num_bytes, pid->dir);
778 
779 	return TRUE;
780 }
781 
782 static void
pppdump_close(wtap * wth)783 pppdump_close(wtap *wth)
784 {
785 	pppdump_t	*state;
786 
787 	state = (pppdump_t *)wth->priv;
788 
789 	if (state->seek_state) { /* should always be TRUE */
790 		g_free(state->seek_state);
791 	}
792 
793 	if (state->pids) {
794 		unsigned int i;
795 		for (i = 0; i < g_ptr_array_len(state->pids); i++) {
796 			g_free(g_ptr_array_index(state->pids, i));
797 		}
798 		g_ptr_array_free(state->pids, TRUE);
799 	}
800 }
801 
802 static const struct supported_block_type pppdump_blocks_supported[] = {
803 	/*
804 	 * We support packet blocks, with no comments or other options.
805 	 */
806 	{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
807 };
808 
809 static const struct file_type_subtype_info pppdump_info = {
810 	"pppd log (pppdump format)", "pppd", NULL, NULL,
811 	FALSE, BLOCKS_SUPPORTED(pppdump_blocks_supported),
812 	NULL, NULL, NULL
813 };
814 
register_pppdump(void)815 void register_pppdump(void)
816 {
817 	pppdump_file_type_subtype = wtap_register_file_type_subtype(&pppdump_info);
818 
819 	/*
820 	 * Register name for backwards compatibility with the
821 	 * wtap_filetypes table in Lua.
822 	 */
823 	wtap_register_backwards_compatibility_lua_name("PPPDUMP",
824 	    pppdump_file_type_subtype);
825 }
826 
827 /*
828  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
829  *
830  * Local variables:
831  * c-basic-offset: 8
832  * tab-width: 8
833  * indent-tabs-mode: t
834  * End:
835  *
836  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
837  * :indentSize=8:tabSize=8:noTabs=false:
838  */
839