xref: /netbsd-src/external/bsd/libpcap/dist/sf-pcap.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: sf-pcap.c,v 1.4 2013/12/31 17:08:23 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1993, 1994, 1995, 1996, 1997
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  *
23  * sf-pcap.c - libpcap-file-format-specific code from savefile.c
24  *	Extraction/creation by Jeffrey Mogul, DECWRL
25  *	Modified by Steve McCanne, LBL.
26  *
27  * Used to save the received packet headers, after filtering, to
28  * a file, and then read them later.
29  * The first record in the file contains saved values for the machine
30  * dependent values so we can print the dump file on any architecture.
31  */
32 
33 #ifndef lint
34 static const char rcsid[] _U_ =
35     "@(#) Header (LBL)";
36 #endif
37 
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 
42 #ifdef WIN32
43 #include <pcap-stdinc.h>
44 #else /* WIN32 */
45 #if HAVE_INTTYPES_H
46 #include <inttypes.h>
47 #elif HAVE_STDINT_H
48 #include <stdint.h>
49 #endif
50 #ifdef HAVE_SYS_BITYPES_H
51 #include <sys/bitypes.h>
52 #endif
53 #include <sys/types.h>
54 #endif /* WIN32 */
55 
56 #include <errno.h>
57 #include <memory.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 
62 #include "pcap-int.h"
63 
64 #include "pcap-common.h"
65 
66 #ifdef HAVE_OS_PROTO_H
67 #include "os-proto.h"
68 #endif
69 
70 #include "sf-pcap.h"
71 
72 /*
73  * Setting O_BINARY on DOS/Windows is a bit tricky
74  */
75 #if defined(WIN32)
76   #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
77 #elif defined(MSDOS)
78   #if defined(__HIGHC__)
79   #define SET_BINMODE(f)  setmode(f, O_BINARY)
80   #else
81   #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
82   #endif
83 #endif
84 
85 /*
86  * Standard libpcap format.
87  */
88 #define TCPDUMP_MAGIC		0xa1b2c3d4
89 
90 /*
91  * Alexey Kuznetzov's modified libpcap format.
92  */
93 #define KUZNETZOV_TCPDUMP_MAGIC	0xa1b2cd34
94 
95 /*
96  * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
97  * for another modified format.
98  */
99 #define FMESQUITA_TCPDUMP_MAGIC	0xa1b234cd
100 
101 /*
102  * Navtel Communcations' format, with nanosecond timestamps,
103  * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
104  */
105 #define NAVTEL_TCPDUMP_MAGIC	0xa12b3c4d
106 
107 /*
108  * Normal libpcap format, except for seconds/nanoseconds timestamps,
109  * as per a request by Ulf Lamping <ulf.lamping@web.de>
110  */
111 #define NSEC_TCPDUMP_MAGIC	0xa1b23c4d
112 
113 /*
114  * Mechanism for storing information about a capture in the upper
115  * 6 bits of a linktype value in a capture file.
116  *
117  * LT_LINKTYPE_EXT(x) extracts the additional information.
118  *
119  * The rest of the bits are for a value describing the link-layer
120  * value.  LT_LINKTYPE(x) extracts that value.
121  */
122 #define LT_LINKTYPE(x)		((x) & 0x03FFFFFF)
123 #define LT_LINKTYPE_EXT(x)	((x) & 0xFC000000)
124 
125 static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
126 
127 /*
128  * Private data for reading pcap savefiles.
129  */
130 typedef enum {
131 	NOT_SWAPPED,
132 	SWAPPED,
133 	MAYBE_SWAPPED
134 } swapped_type_t;
135 
136 typedef enum {
137 	PASS_THROUGH,
138 	SCALE_UP,
139 	SCALE_DOWN
140 } tstamp_scale_type_t;
141 
142 struct pcap_sf {
143 	size_t hdrsize;
144 	swapped_type_t lengths_swapped;
145 	tstamp_scale_type_t scale_type;
146 };
147 
148 /*
149  * Check whether this is a pcap savefile and, if it is, extract the
150  * relevant information from the header.
151  */
152 pcap_t *
153 pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
154     int *err)
155 {
156 	struct pcap_file_header hdr;
157 	size_t amt_read;
158 	pcap_t *p;
159 	int swapped = 0;
160 	struct pcap_sf *ps;
161 
162 	/*
163 	 * Assume no read errors.
164 	 */
165 	*err = 0;
166 
167 	/*
168 	 * Check whether the first 4 bytes of the file are the magic
169 	 * number for a pcap savefile, or for a byte-swapped pcap
170 	 * savefile.
171 	 */
172 	if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC &&
173 	    magic != NSEC_TCPDUMP_MAGIC) {
174 		magic = SWAPLONG(magic);
175 		if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC &&
176 		    magic != NSEC_TCPDUMP_MAGIC)
177 			return (NULL);	/* nope */
178 		swapped = 1;
179 	}
180 
181 	/*
182 	 * They are.  Put the magic number in the header, and read
183 	 * the rest of the header.
184 	 */
185 	hdr.magic = magic;
186 	amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
187 	    sizeof(hdr) - sizeof(hdr.magic), fp);
188 	if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
189 		if (ferror(fp)) {
190 			snprintf(errbuf, PCAP_ERRBUF_SIZE,
191 			    "error reading dump file: %s",
192 			    pcap_strerror(errno));
193 		} else {
194 			snprintf(errbuf, PCAP_ERRBUF_SIZE,
195 			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
196 			    (unsigned long)sizeof(hdr),
197 			    (unsigned long)amt_read);
198 		}
199 		*err = 1;
200 		return (NULL);
201 	}
202 
203 	/*
204 	 * If it's a byte-swapped capture file, byte-swap the header.
205 	 */
206 	if (swapped) {
207 		hdr.version_major = SWAPSHORT(hdr.version_major);
208 		hdr.version_minor = SWAPSHORT(hdr.version_minor);
209 		hdr.thiszone = SWAPLONG(hdr.thiszone);
210 		hdr.sigfigs = SWAPLONG(hdr.sigfigs);
211 		hdr.snaplen = SWAPLONG(hdr.snaplen);
212 		hdr.linktype = SWAPLONG(hdr.linktype);
213 	}
214 
215 	if (hdr.version_major < PCAP_VERSION_MAJOR) {
216 		snprintf(errbuf, PCAP_ERRBUF_SIZE,
217 		    "archaic pcap savefile format");
218 		*err = 1;
219 		return (NULL);
220 	}
221 
222 	/*
223 	 * OK, this is a good pcap file.
224 	 * Allocate a pcap_t for it.
225 	 */
226 	p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf));
227 	if (p == NULL) {
228 		/* Allocation failed. */
229 		*err = 1;
230 		return (NULL);
231 	}
232 	p->swapped = swapped;
233 	p->version_major = hdr.version_major;
234 	p->version_minor = hdr.version_minor;
235 	p->tzoff = hdr.thiszone;
236 	p->snapshot = hdr.snaplen;
237 	p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
238 	p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
239 
240 	p->next_packet_op = pcap_next_packet;
241 
242 	ps = p->priv;
243 
244 	p->opt.tstamp_precision = precision;
245 
246 	/*
247 	 * Will we need to scale the timestamps to match what the
248 	 * user wants?
249 	 */
250 	switch (precision) {
251 
252 	case PCAP_TSTAMP_PRECISION_MICRO:
253 		if (magic == NSEC_TCPDUMP_MAGIC) {
254 			/*
255 			 * The file has nanoseconds, the user
256 			 * wants microseconds; scale the
257 			 * precision down.
258 			 */
259 			ps->scale_type = SCALE_DOWN;
260 		} else {
261 			/*
262 			 * The file has microseconds, the
263 			 * user wants microseconds; nothing to do.
264 			 */
265 			ps->scale_type = PASS_THROUGH;
266 		}
267 		break;
268 
269 	case PCAP_TSTAMP_PRECISION_NANO:
270 		if (magic == NSEC_TCPDUMP_MAGIC) {
271 			/*
272 			 * The file has nanoseconds, the
273 			 * user wants nanoseconds; nothing to do.
274 			 */
275 			ps->scale_type = PASS_THROUGH;
276 		} else {
277 			/*
278 			 * The file has microoseconds, the user
279 			 * wants nanoseconds; scale the
280 			 * precision up.
281 			 */
282 			ps->scale_type = SCALE_UP;
283 		}
284 		break;
285 
286 	default:
287 		snprintf(errbuf, PCAP_ERRBUF_SIZE,
288 		    "unknown time stamp resolution %u", precision);
289 		free(p);
290 		*err = 1;
291 		return (NULL);
292 	}
293 
294 	/*
295 	 * We interchanged the caplen and len fields at version 2.3,
296 	 * in order to match the bpf header layout.  But unfortunately
297 	 * some files were written with version 2.3 in their headers
298 	 * but without the interchanged fields.
299 	 *
300 	 * In addition, DG/UX tcpdump writes out files with a version
301 	 * number of 543.0, and with the caplen and len fields in the
302 	 * pre-2.3 order.
303 	 */
304 	switch (hdr.version_major) {
305 
306 	case 2:
307 		if (hdr.version_minor < 3)
308 			ps->lengths_swapped = SWAPPED;
309 		else if (hdr.version_minor == 3)
310 			ps->lengths_swapped = MAYBE_SWAPPED;
311 		else
312 			ps->lengths_swapped = NOT_SWAPPED;
313 		break;
314 
315 	case 543:
316 		ps->lengths_swapped = SWAPPED;
317 		break;
318 
319 	default:
320 		ps->lengths_swapped = NOT_SWAPPED;
321 		break;
322 	}
323 
324 	if (magic == KUZNETZOV_TCPDUMP_MAGIC) {
325 		/*
326 		 * XXX - the patch that's in some versions of libpcap
327 		 * changes the packet header but not the magic number,
328 		 * and some other versions with this magic number have
329 		 * some extra debugging information in the packet header;
330 		 * we'd have to use some hacks^H^H^H^H^Hheuristics to
331 		 * detect those variants.
332 		 *
333 		 * Ethereal does that, but it does so by trying to read
334 		 * the first two packets of the file with each of the
335 		 * record header formats.  That currently means it seeks
336 		 * backwards and retries the reads, which doesn't work
337 		 * on pipes.  We want to be able to read from a pipe, so
338 		 * that strategy won't work; we'd have to buffer some
339 		 * data ourselves and read from that buffer in order to
340 		 * make that work.
341 		 */
342 		ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
343 
344 		if (p->linktype == DLT_EN10MB) {
345 			/*
346 			 * This capture might have been done in raw mode
347 			 * or cooked mode.
348 			 *
349 			 * If it was done in cooked mode, p->snapshot was
350 			 * passed to recvfrom() as the buffer size, meaning
351 			 * that the most packet data that would be copied
352 			 * would be p->snapshot.  However, a faked Ethernet
353 			 * header would then have been added to it, so the
354 			 * most data that would be in a packet in the file
355 			 * would be p->snapshot + 14.
356 			 *
357 			 * We can't easily tell whether the capture was done
358 			 * in raw mode or cooked mode, so we'll assume it was
359 			 * cooked mode, and add 14 to the snapshot length.
360 			 * That means that, for a raw capture, the snapshot
361 			 * length will be misleading if you use it to figure
362 			 * out why a capture doesn't have all the packet data,
363 			 * but there's not much we can do to avoid that.
364 			 */
365 			p->snapshot += 14;
366 		}
367 	} else
368 		ps->hdrsize = sizeof(struct pcap_sf_pkthdr);
369 
370 	/*
371 	 * Allocate a buffer for the packet data.
372 	 */
373 	p->bufsize = p->snapshot;
374 	if (p->bufsize <= 0) {
375 		/*
376 		 * Bogus snapshot length; use 64KiB as a fallback.
377 		 */
378 		p->bufsize = 65536;
379 	}
380 	p->buffer = malloc(p->bufsize);
381 	if (p->buffer == NULL) {
382 		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
383 		free(p);
384 		*err = 1;
385 		return (NULL);
386 	}
387 
388 	p->cleanup_op = sf_cleanup;
389 
390 	return (p);
391 }
392 
393 /*
394  * Read and return the next packet from the savefile.  Return the header
395  * in hdr and a pointer to the contents in data.  Return 0 on success, 1
396  * if there were no more packets, and -1 on an error.
397  */
398 static int
399 pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
400 {
401 	struct pcap_sf *ps = p->priv;
402 	struct pcap_sf_patched_pkthdr sf_hdr;
403 	FILE *fp = p->rfile;
404 	size_t amt_read;
405 	bpf_u_int32 t;
406 
407 	/*
408 	 * Read the packet header; the structure we use as a buffer
409 	 * is the longer structure for files generated by the patched
410 	 * libpcap, but if the file has the magic number for an
411 	 * unpatched libpcap we only read as many bytes as the regular
412 	 * header has.
413 	 */
414 	amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);
415 	if (amt_read != ps->hdrsize) {
416 		if (ferror(fp)) {
417 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
418 			    "error reading dump file: %s",
419 			    pcap_strerror(errno));
420 			return (-1);
421 		} else {
422 			if (amt_read != 0) {
423 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
424 				    "truncated dump file; tried to read %lu header bytes, only got %lu",
425 				    (unsigned long)ps->hdrsize,
426 				    (unsigned long)amt_read);
427 				return (-1);
428 			}
429 			/* EOF */
430 			return (1);
431 		}
432 	}
433 
434 	if (p->swapped) {
435 		/* these were written in opposite byte order */
436 		hdr->caplen = SWAPLONG(sf_hdr.caplen);
437 		hdr->len = SWAPLONG(sf_hdr.len);
438 		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
439 		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
440 	} else {
441 		hdr->caplen = sf_hdr.caplen;
442 		hdr->len = sf_hdr.len;
443 		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
444 		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
445 	}
446 
447 	switch (ps->scale_type) {
448 
449 	case PASS_THROUGH:
450 		/*
451 		 * Just pass the time stamp through.
452 		 */
453 		break;
454 
455 	case SCALE_UP:
456 		/*
457 		 * File has microseconds, user wants nanoseconds; convert
458 		 * it.
459 		 */
460 		hdr->ts.tv_usec = hdr->ts.tv_usec * 1000;
461 		break;
462 
463 	case SCALE_DOWN:
464 		/*
465 		 * File has nanoseconds, user wants microseconds; convert
466 		 * it.
467 		 */
468 		hdr->ts.tv_usec = hdr->ts.tv_usec / 1000;
469 		break;
470 	}
471 
472 	/* Swap the caplen and len fields, if necessary. */
473 	switch (ps->lengths_swapped) {
474 
475 	case NOT_SWAPPED:
476 		break;
477 
478 	case MAYBE_SWAPPED:
479 		if (hdr->caplen <= hdr->len) {
480 			/*
481 			 * The captured length is <= the actual length,
482 			 * so presumably they weren't swapped.
483 			 */
484 			break;
485 		}
486 		/* FALLTHROUGH */
487 
488 	case SWAPPED:
489 		t = hdr->caplen;
490 		hdr->caplen = hdr->len;
491 		hdr->len = t;
492 		break;
493 	}
494 
495 	if ((int)hdr->caplen > p->bufsize) {
496 		/*
497 		 * This can happen due to Solaris 2.3 systems tripping
498 		 * over the BUFMOD problem and not setting the snapshot
499 		 * correctly in the savefile header.  If the caplen isn't
500 		 * grossly wrong, try to salvage.
501 		 */
502 		static u_char *tp = NULL;
503 		static size_t tsize = 0;
504 
505 		if (hdr->caplen > 65535) {
506 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
507 			    "bogus savefile header");
508 			return (-1);
509 		}
510 
511 		if (tsize < hdr->caplen) {
512 			tsize = ((hdr->caplen + 1023) / 1024) * 1024;
513 			if (tp != NULL)
514 				free((u_char *)tp);
515 			tp = (u_char *)malloc(tsize);
516 			if (tp == NULL) {
517 				tsize = 0;
518 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
519 				    "BUFMOD hack malloc");
520 				return (-1);
521 			}
522 		}
523 		amt_read = fread((char *)tp, 1, hdr->caplen, fp);
524 		if (amt_read != hdr->caplen) {
525 			if (ferror(fp)) {
526 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
527 				    "error reading dump file: %s",
528 				    pcap_strerror(errno));
529 			} else {
530 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
531 				    "truncated dump file; tried to read %u captured bytes, only got %lu",
532 				    hdr->caplen, (unsigned long)amt_read);
533 			}
534 			return (-1);
535 		}
536 		/*
537 		 * We can only keep up to p->bufsize bytes.  Since
538 		 * caplen > p->bufsize is exactly how we got here,
539 		 * we know we can only keep the first p->bufsize bytes
540 		 * and must drop the remainder.  Adjust caplen accordingly,
541 		 * so we don't get confused later as to how many bytes we
542 		 * have to play with.
543 		 */
544 		hdr->caplen = p->bufsize;
545 		memcpy(p->buffer, (char *)tp, p->bufsize);
546 	} else {
547 		/* read the packet itself */
548 		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
549 		if (amt_read != hdr->caplen) {
550 			if (ferror(fp)) {
551 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
552 				    "error reading dump file: %s",
553 				    pcap_strerror(errno));
554 			} else {
555 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
556 				    "truncated dump file; tried to read %u captured bytes, only got %lu",
557 				    hdr->caplen, (unsigned long)amt_read);
558 			}
559 			return (-1);
560 		}
561 	}
562 	*data = p->buffer;
563 
564 	if (p->swapped) {
565 		/*
566 		 * Convert pseudo-headers from the byte order of
567 		 * the host on which the file was saved to our
568 		 * byte order, as necessary.
569 		 */
570 		switch (p->linktype) {
571 
572 		case DLT_USB_LINUX:
573 			swap_linux_usb_header(hdr, *data, 0);
574 			break;
575 
576 		case DLT_USB_LINUX_MMAPPED:
577 			swap_linux_usb_header(hdr, *data, 1);
578 			break;
579 		}
580 	}
581 
582 	return (0);
583 }
584 
585 static int
586 sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen)
587 {
588 	struct pcap_file_header hdr;
589 
590 	hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC;
591 	hdr.version_major = PCAP_VERSION_MAJOR;
592 	hdr.version_minor = PCAP_VERSION_MINOR;
593 
594 	hdr.thiszone = thiszone;
595 	hdr.snaplen = snaplen;
596 	hdr.sigfigs = 0;
597 	hdr.linktype = linktype;
598 
599 	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
600 		return (-1);
601 
602 	return (0);
603 }
604 
605 /*
606  * Output a packet to the initialized dump file.
607  */
608 void
609 pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
610 {
611 	register FILE *f;
612 	struct pcap_sf_pkthdr sf_hdr;
613 
614 	f = (FILE *)user;
615 	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
616 	sf_hdr.ts.tv_usec = h->ts.tv_usec;
617 	sf_hdr.caplen     = h->caplen;
618 	sf_hdr.len        = h->len;
619 	/* XXX we should check the return status */
620 	(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
621 	(void)fwrite(sp, h->caplen, 1, f);
622 }
623 
624 static pcap_dumper_t *
625 pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
626 {
627 
628 #if defined(WIN32) || defined(MSDOS)
629 	/*
630 	 * If we're writing to the standard output, put it in binary
631 	 * mode, as savefiles are binary files.
632 	 *
633 	 * Otherwise, we turn off buffering.
634 	 * XXX - why?  And why not on the standard output?
635 	 */
636 	if (f == stdout)
637 		SET_BINMODE(f);
638 	else
639 		setbuf(f, NULL);
640 #endif
641 	if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
642 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
643 		    fname, pcap_strerror(errno));
644 		if (f != stdout)
645 			(void)fclose(f);
646 		return (NULL);
647 	}
648 	return ((pcap_dumper_t *)f);
649 }
650 
651 /*
652  * Initialize so that sf_write() will output to the file named 'fname'.
653  */
654 pcap_dumper_t *
655 pcap_dump_open(pcap_t *p, const char *fname)
656 {
657 	FILE *f;
658 	int linktype;
659 
660 	/*
661 	 * If this pcap_t hasn't been activated, it doesn't have a
662 	 * link-layer type, so we can't use it.
663 	 */
664 	if (!p->activated) {
665 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
666 		    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
667 		    fname);
668 		return (NULL);
669 	}
670 	linktype = dlt_to_linktype(p->linktype);
671 	if (linktype == -1) {
672 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
673 		    "%s: link-layer type %d isn't supported in savefiles",
674 		    fname, p->linktype);
675 		return (NULL);
676 	}
677 	linktype |= p->linktype_ext;
678 
679 	if (fname[0] == '-' && fname[1] == '\0') {
680 		f = stdout;
681 		fname = "standard output";
682 	} else {
683 #if !defined(WIN32) && !defined(MSDOS)
684 		f = fopen(fname, "w");
685 #else
686 		f = fopen(fname, "wb");
687 #endif
688 		if (f == NULL) {
689 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
690 			    fname, pcap_strerror(errno));
691 			return (NULL);
692 		}
693 	}
694 	return (pcap_setup_dump(p, linktype, f, fname));
695 }
696 
697 /*
698  * Initialize so that sf_write() will output to the given stream.
699  */
700 pcap_dumper_t *
701 pcap_dump_fopen(pcap_t *p, FILE *f)
702 {
703 	int linktype;
704 
705 	linktype = dlt_to_linktype(p->linktype);
706 	if (linktype == -1) {
707 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
708 		    "stream: link-layer type %d isn't supported in savefiles",
709 		    p->linktype);
710 		return (NULL);
711 	}
712 	linktype |= p->linktype_ext;
713 
714 	return (pcap_setup_dump(p, linktype, f, "stream"));
715 }
716 
717 FILE *
718 pcap_dump_file(pcap_dumper_t *p)
719 {
720 	return ((FILE *)p);
721 }
722 
723 long
724 pcap_dump_ftell(pcap_dumper_t *p)
725 {
726 	return (ftell((FILE *)p));
727 }
728 
729 int
730 pcap_dump_flush(pcap_dumper_t *p)
731 {
732 
733 	if (fflush((FILE *)p) == EOF)
734 		return (-1);
735 	else
736 		return (0);
737 }
738 
739 void
740 pcap_dump_close(pcap_dumper_t *p)
741 {
742 
743 #ifdef notyet
744 	if (ferror((FILE *)p))
745 		return-an-error;
746 	/* XXX should check return from fclose() too */
747 #endif
748 	(void)fclose((FILE *)p);
749 }
750