1214455Srpaulo/*
2214455Srpaulo * Copyright (c) 1993, 1994, 1995, 1996, 1997
3214455Srpaulo *	The Regents of the University of California.  All rights reserved.
4214455Srpaulo *
5214455Srpaulo * Redistribution and use in source and binary forms, with or without
6214455Srpaulo * modification, are permitted provided that: (1) source code distributions
7214455Srpaulo * retain the above copyright notice and this paragraph in its entirety, (2)
8214455Srpaulo * distributions including binary code include the above copyright notice and
9214455Srpaulo * this paragraph in its entirety in the documentation or other materials
10214455Srpaulo * provided with the distribution, and (3) all advertising materials mentioning
11214455Srpaulo * features or use of this software display the following acknowledgement:
12214455Srpaulo * ``This product includes software developed by the University of California,
13214455Srpaulo * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14214455Srpaulo * the University nor the names of its contributors may be used to endorse
15214455Srpaulo * or promote products derived from this software without specific prior
16214455Srpaulo * written permission.
17214455Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18214455Srpaulo * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19214455Srpaulo * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20214455Srpaulo *
21214455Srpaulo * sf-pcap.c - libpcap-file-format-specific code from savefile.c
22214455Srpaulo *	Extraction/creation by Jeffrey Mogul, DECWRL
23214455Srpaulo *	Modified by Steve McCanne, LBL.
24214455Srpaulo *
25214455Srpaulo * Used to save the received packet headers, after filtering, to
26214455Srpaulo * a file, and then read them later.
27214455Srpaulo * The first record in the file contains saved values for the machine
28214455Srpaulo * dependent values so we can print the dump file on any architecture.
29214455Srpaulo */
30214455Srpaulo
31214455Srpaulo#ifndef lint
32214455Srpaulostatic const char rcsid[] _U_ =
33214455Srpaulo    "@(#) $Header$ (LBL)";
34214455Srpaulo#endif
35214455Srpaulo
36214455Srpaulo#ifdef HAVE_CONFIG_H
37214455Srpaulo#include "config.h"
38214455Srpaulo#endif
39214455Srpaulo
40214455Srpaulo#ifdef WIN32
41214455Srpaulo#include <pcap-stdinc.h>
42214455Srpaulo#else /* WIN32 */
43214455Srpaulo#if HAVE_INTTYPES_H
44214455Srpaulo#include <inttypes.h>
45214455Srpaulo#elif HAVE_STDINT_H
46214455Srpaulo#include <stdint.h>
47214455Srpaulo#endif
48214455Srpaulo#ifdef HAVE_SYS_BITYPES_H
49214455Srpaulo#include <sys/bitypes.h>
50214455Srpaulo#endif
51214455Srpaulo#include <sys/types.h>
52214455Srpaulo#endif /* WIN32 */
53214455Srpaulo
54214455Srpaulo#include <errno.h>
55214455Srpaulo#include <memory.h>
56214455Srpaulo#include <stdio.h>
57214455Srpaulo#include <stdlib.h>
58214455Srpaulo#include <string.h>
59214455Srpaulo
60214455Srpaulo#include "pcap-int.h"
61214455Srpaulo
62214455Srpaulo#include "pcap-common.h"
63214455Srpaulo
64214455Srpaulo#ifdef HAVE_OS_PROTO_H
65214455Srpaulo#include "os-proto.h"
66214455Srpaulo#endif
67214455Srpaulo
68214455Srpaulo#include "sf-pcap.h"
69214455Srpaulo
70214455Srpaulo/*
71214455Srpaulo * Setting O_BINARY on DOS/Windows is a bit tricky
72214455Srpaulo */
73214455Srpaulo#if defined(WIN32)
74214455Srpaulo  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
75214455Srpaulo#elif defined(MSDOS)
76214455Srpaulo  #if defined(__HIGHC__)
77214455Srpaulo  #define SET_BINMODE(f)  setmode(f, O_BINARY)
78214455Srpaulo  #else
79214455Srpaulo  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
80214455Srpaulo  #endif
81214455Srpaulo#endif
82214455Srpaulo
83214455Srpaulo/*
84214455Srpaulo * Standard libpcap format.
85214455Srpaulo */
86214455Srpaulo#define TCPDUMP_MAGIC		0xa1b2c3d4
87214455Srpaulo
88214455Srpaulo/*
89214455Srpaulo * Alexey Kuznetzov's modified libpcap format.
90214455Srpaulo */
91214455Srpaulo#define KUZNETZOV_TCPDUMP_MAGIC	0xa1b2cd34
92214455Srpaulo
93214455Srpaulo/*
94214455Srpaulo * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
95214455Srpaulo * for another modified format.
96214455Srpaulo */
97214455Srpaulo#define FMESQUITA_TCPDUMP_MAGIC	0xa1b234cd
98214455Srpaulo
99214455Srpaulo/*
100214455Srpaulo * Navtel Communcations' format, with nanosecond timestamps,
101214455Srpaulo * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
102214455Srpaulo */
103214455Srpaulo#define NAVTEL_TCPDUMP_MAGIC	0xa12b3c4d
104214455Srpaulo
105214455Srpaulo/*
106214455Srpaulo * Normal libpcap format, except for seconds/nanoseconds timestamps,
107214455Srpaulo * as per a request by Ulf Lamping <ulf.lamping@web.de>
108214455Srpaulo */
109214455Srpaulo#define NSEC_TCPDUMP_MAGIC	0xa1b23c4d
110214455Srpaulo
111214455Srpaulo/*
112214455Srpaulo * Mechanism for storing information about a capture in the upper
113214455Srpaulo * 6 bits of a linktype value in a capture file.
114214455Srpaulo *
115214455Srpaulo * LT_LINKTYPE_EXT(x) extracts the additional information.
116214455Srpaulo *
117214455Srpaulo * The rest of the bits are for a value describing the link-layer
118214455Srpaulo * value.  LT_LINKTYPE(x) extracts that value.
119214455Srpaulo */
120214455Srpaulo#define LT_LINKTYPE(x)		((x) & 0x03FFFFFF)
121214455Srpaulo#define LT_LINKTYPE_EXT(x)	((x) & 0xFC000000)
122214455Srpaulo
123214455Srpaulostatic int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
124214455Srpaulo
125214455Srpaulo/*
126214455Srpaulo * Check whether this is a pcap savefile and, if it is, extract the
127214455Srpaulo * relevant information from the header.
128214455Srpaulo */
129214455Srpauloint
130214455Srpaulopcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
131214455Srpaulo{
132214455Srpaulo	struct pcap_file_header hdr;
133214455Srpaulo	size_t amt_read;
134214455Srpaulo
135214455Srpaulo	/*
136214455Srpaulo	 * Check whether the first 4 bytes of the file are the magic
137214455Srpaulo	 * number for a pcap savefile, or for a byte-swapped pcap
138214455Srpaulo	 * savefile.
139214455Srpaulo	 */
140214455Srpaulo	if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) {
141214455Srpaulo		magic = SWAPLONG(magic);
142214455Srpaulo		if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC)
143214455Srpaulo			return (0);	/* nope */
144214455Srpaulo		p->sf.swapped = 1;
145214455Srpaulo	}
146214455Srpaulo
147214455Srpaulo	/*
148214455Srpaulo	 * They are.  Put the magic number in the header, and read
149214455Srpaulo	 * the rest of the header.
150214455Srpaulo	 */
151214455Srpaulo	hdr.magic = magic;
152214455Srpaulo	amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
153214455Srpaulo	    sizeof(hdr) - sizeof(hdr.magic), fp);
154214455Srpaulo	if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
155214455Srpaulo		if (ferror(fp)) {
156214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
157214455Srpaulo			    "error reading dump file: %s",
158214455Srpaulo			    pcap_strerror(errno));
159214455Srpaulo		} else {
160214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
161214455Srpaulo			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
162214455Srpaulo			    (unsigned long)sizeof(hdr),
163214455Srpaulo			    (unsigned long)amt_read);
164214455Srpaulo		}
165214455Srpaulo		return (-1);
166214455Srpaulo	}
167214455Srpaulo
168214455Srpaulo	/*
169214455Srpaulo	 * If it's a byte-swapped capture file, byte-swap the header.
170214455Srpaulo	 */
171214455Srpaulo	if (p->sf.swapped) {
172214455Srpaulo		hdr.version_major = SWAPSHORT(hdr.version_major);
173214455Srpaulo		hdr.version_minor = SWAPSHORT(hdr.version_minor);
174214455Srpaulo		hdr.thiszone = SWAPLONG(hdr.thiszone);
175214455Srpaulo		hdr.sigfigs = SWAPLONG(hdr.sigfigs);
176214455Srpaulo		hdr.snaplen = SWAPLONG(hdr.snaplen);
177214455Srpaulo		hdr.linktype = SWAPLONG(hdr.linktype);
178214455Srpaulo	}
179214455Srpaulo
180214455Srpaulo	if (hdr.version_major < PCAP_VERSION_MAJOR) {
181214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
182214455Srpaulo		    "archaic pcap savefile format");
183214455Srpaulo		return (-1);
184214455Srpaulo	}
185214455Srpaulo	p->sf.version_major = hdr.version_major;
186214455Srpaulo	p->sf.version_minor = hdr.version_minor;
187214455Srpaulo	p->tzoff = hdr.thiszone;
188214455Srpaulo	p->snapshot = hdr.snaplen;
189214455Srpaulo	p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
190214455Srpaulo	p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
191214455Srpaulo
192214455Srpaulo	p->sf.next_packet_op = pcap_next_packet;
193214455Srpaulo
194214455Srpaulo	/*
195214455Srpaulo	 * We interchanged the caplen and len fields at version 2.3,
196214455Srpaulo	 * in order to match the bpf header layout.  But unfortunately
197214455Srpaulo	 * some files were written with version 2.3 in their headers
198214455Srpaulo	 * but without the interchanged fields.
199214455Srpaulo	 *
200214455Srpaulo	 * In addition, DG/UX tcpdump writes out files with a version
201214455Srpaulo	 * number of 543.0, and with the caplen and len fields in the
202214455Srpaulo	 * pre-2.3 order.
203214455Srpaulo	 */
204214455Srpaulo	switch (hdr.version_major) {
205214455Srpaulo
206214455Srpaulo	case 2:
207214455Srpaulo		if (hdr.version_minor < 3)
208214455Srpaulo			p->sf.lengths_swapped = SWAPPED;
209214455Srpaulo		else if (hdr.version_minor == 3)
210214455Srpaulo			p->sf.lengths_swapped = MAYBE_SWAPPED;
211214455Srpaulo		else
212214455Srpaulo			p->sf.lengths_swapped = NOT_SWAPPED;
213214455Srpaulo		break;
214214455Srpaulo
215214455Srpaulo	case 543:
216214455Srpaulo		p->sf.lengths_swapped = SWAPPED;
217214455Srpaulo		break;
218214455Srpaulo
219214455Srpaulo	default:
220214455Srpaulo		p->sf.lengths_swapped = NOT_SWAPPED;
221214455Srpaulo		break;
222214455Srpaulo	}
223214455Srpaulo
224214455Srpaulo	if (magic == KUZNETZOV_TCPDUMP_MAGIC) {
225214455Srpaulo		/*
226214455Srpaulo		 * XXX - the patch that's in some versions of libpcap
227214455Srpaulo		 * changes the packet header but not the magic number,
228214455Srpaulo		 * and some other versions with this magic number have
229214455Srpaulo		 * some extra debugging information in the packet header;
230214455Srpaulo		 * we'd have to use some hacks^H^H^H^H^Hheuristics to
231214455Srpaulo		 * detect those variants.
232214455Srpaulo		 *
233214455Srpaulo		 * Ethereal does that, but it does so by trying to read
234214455Srpaulo		 * the first two packets of the file with each of the
235214455Srpaulo		 * record header formats.  That currently means it seeks
236214455Srpaulo		 * backwards and retries the reads, which doesn't work
237214455Srpaulo		 * on pipes.  We want to be able to read from a pipe, so
238214455Srpaulo		 * that strategy won't work; we'd have to buffer some
239214455Srpaulo		 * data ourselves and read from that buffer in order to
240214455Srpaulo		 * make that work.
241214455Srpaulo		 */
242214455Srpaulo		p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
243214455Srpaulo
244214455Srpaulo		if (p->linktype == DLT_EN10MB) {
245214455Srpaulo			/*
246214455Srpaulo			 * This capture might have been done in raw mode
247214455Srpaulo			 * or cooked mode.
248214455Srpaulo			 *
249214455Srpaulo			 * If it was done in cooked mode, p->snapshot was
250214455Srpaulo			 * passed to recvfrom() as the buffer size, meaning
251214455Srpaulo			 * that the most packet data that would be copied
252214455Srpaulo			 * would be p->snapshot.  However, a faked Ethernet
253214455Srpaulo			 * header would then have been added to it, so the
254214455Srpaulo			 * most data that would be in a packet in the file
255214455Srpaulo			 * would be p->snapshot + 14.
256214455Srpaulo			 *
257214455Srpaulo			 * We can't easily tell whether the capture was done
258214455Srpaulo			 * in raw mode or cooked mode, so we'll assume it was
259214455Srpaulo			 * cooked mode, and add 14 to the snapshot length.
260214455Srpaulo			 * That means that, for a raw capture, the snapshot
261214455Srpaulo			 * length will be misleading if you use it to figure
262214455Srpaulo			 * out why a capture doesn't have all the packet data,
263214455Srpaulo			 * but there's not much we can do to avoid that.
264214455Srpaulo			 */
265214455Srpaulo			p->snapshot += 14;
266214455Srpaulo		}
267214455Srpaulo	} else
268214455Srpaulo		p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr);
269214455Srpaulo
270214455Srpaulo	/*
271214455Srpaulo	 * Allocate a buffer for the packet data.
272214455Srpaulo	 */
273214455Srpaulo	p->bufsize = p->snapshot;
274235426Sdelphij	if (p->bufsize <= 0) {
275235426Sdelphij		/*
276235426Sdelphij		 * Bogus snapshot length; use 64KiB as a fallback.
277235426Sdelphij		 */
278235426Sdelphij		p->bufsize = 65536;
279235426Sdelphij	}
280214455Srpaulo	p->buffer = malloc(p->bufsize);
281214455Srpaulo	if (p->buffer == NULL) {
282214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
283214455Srpaulo		return (-1);
284214455Srpaulo	}
285214455Srpaulo
286214455Srpaulo	return (1);
287214455Srpaulo}
288214455Srpaulo
289214455Srpaulo/*
290214455Srpaulo * Read and return the next packet from the savefile.  Return the header
291214455Srpaulo * in hdr and a pointer to the contents in data.  Return 0 on success, 1
292214455Srpaulo * if there were no more packets, and -1 on an error.
293214455Srpaulo */
294214455Srpaulostatic int
295214455Srpaulopcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
296214455Srpaulo{
297214455Srpaulo	struct pcap_sf_patched_pkthdr sf_hdr;
298214455Srpaulo	FILE *fp = p->sf.rfile;
299214455Srpaulo	size_t amt_read;
300214455Srpaulo	bpf_u_int32 t;
301214455Srpaulo
302214455Srpaulo	/*
303214455Srpaulo	 * Read the packet header; the structure we use as a buffer
304214455Srpaulo	 * is the longer structure for files generated by the patched
305214455Srpaulo	 * libpcap, but if the file has the magic number for an
306214455Srpaulo	 * unpatched libpcap we only read as many bytes as the regular
307214455Srpaulo	 * header has.
308214455Srpaulo	 */
309214455Srpaulo	amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp);
310214455Srpaulo	if (amt_read != p->sf.hdrsize) {
311214455Srpaulo		if (ferror(fp)) {
312214455Srpaulo			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
313214455Srpaulo			    "error reading dump file: %s",
314214455Srpaulo			    pcap_strerror(errno));
315214455Srpaulo			return (-1);
316214455Srpaulo		} else {
317214455Srpaulo			if (amt_read != 0) {
318214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
319214455Srpaulo				    "truncated dump file; tried to read %lu header bytes, only got %lu",
320214455Srpaulo				    (unsigned long)p->sf.hdrsize,
321214455Srpaulo				    (unsigned long)amt_read);
322214455Srpaulo				return (-1);
323214455Srpaulo			}
324214455Srpaulo			/* EOF */
325214455Srpaulo			return (1);
326214455Srpaulo		}
327214455Srpaulo	}
328214455Srpaulo
329214455Srpaulo	if (p->sf.swapped) {
330214455Srpaulo		/* these were written in opposite byte order */
331214455Srpaulo		hdr->caplen = SWAPLONG(sf_hdr.caplen);
332214455Srpaulo		hdr->len = SWAPLONG(sf_hdr.len);
333214455Srpaulo		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
334214455Srpaulo		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
335214455Srpaulo	} else {
336214455Srpaulo		hdr->caplen = sf_hdr.caplen;
337214455Srpaulo		hdr->len = sf_hdr.len;
338214455Srpaulo		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
339214455Srpaulo		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
340214455Srpaulo	}
341214455Srpaulo	/* Swap the caplen and len fields, if necessary. */
342214455Srpaulo	switch (p->sf.lengths_swapped) {
343214455Srpaulo
344214455Srpaulo	case NOT_SWAPPED:
345214455Srpaulo		break;
346214455Srpaulo
347214455Srpaulo	case MAYBE_SWAPPED:
348214455Srpaulo		if (hdr->caplen <= hdr->len) {
349214455Srpaulo			/*
350214455Srpaulo			 * The captured length is <= the actual length,
351214455Srpaulo			 * so presumably they weren't swapped.
352214455Srpaulo			 */
353214455Srpaulo			break;
354214455Srpaulo		}
355214455Srpaulo		/* FALLTHROUGH */
356214455Srpaulo
357214455Srpaulo	case SWAPPED:
358214455Srpaulo		t = hdr->caplen;
359214455Srpaulo		hdr->caplen = hdr->len;
360214455Srpaulo		hdr->len = t;
361214455Srpaulo		break;
362214455Srpaulo	}
363214455Srpaulo
364214455Srpaulo	if (hdr->caplen > p->bufsize) {
365214455Srpaulo		/*
366214455Srpaulo		 * This can happen due to Solaris 2.3 systems tripping
367214455Srpaulo		 * over the BUFMOD problem and not setting the snapshot
368214455Srpaulo		 * correctly in the savefile header.  If the caplen isn't
369214455Srpaulo		 * grossly wrong, try to salvage.
370214455Srpaulo		 */
371214455Srpaulo		static u_char *tp = NULL;
372214455Srpaulo		static size_t tsize = 0;
373214455Srpaulo
374214455Srpaulo		if (hdr->caplen > 65535) {
375214455Srpaulo			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
376214455Srpaulo			    "bogus savefile header");
377214455Srpaulo			return (-1);
378214455Srpaulo		}
379214455Srpaulo
380214455Srpaulo		if (tsize < hdr->caplen) {
381214455Srpaulo			tsize = ((hdr->caplen + 1023) / 1024) * 1024;
382214455Srpaulo			if (tp != NULL)
383214455Srpaulo				free((u_char *)tp);
384214455Srpaulo			tp = (u_char *)malloc(tsize);
385214455Srpaulo			if (tp == NULL) {
386214455Srpaulo				tsize = 0;
387214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
388214455Srpaulo				    "BUFMOD hack malloc");
389214455Srpaulo				return (-1);
390214455Srpaulo			}
391214455Srpaulo		}
392214455Srpaulo		amt_read = fread((char *)tp, 1, hdr->caplen, fp);
393214455Srpaulo		if (amt_read != hdr->caplen) {
394214455Srpaulo			if (ferror(fp)) {
395214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
396214455Srpaulo				    "error reading dump file: %s",
397214455Srpaulo				    pcap_strerror(errno));
398214455Srpaulo			} else {
399214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
400214455Srpaulo				    "truncated dump file; tried to read %u captured bytes, only got %lu",
401214455Srpaulo				    hdr->caplen, (unsigned long)amt_read);
402214455Srpaulo			}
403214455Srpaulo			return (-1);
404214455Srpaulo		}
405214455Srpaulo		/*
406214455Srpaulo		 * We can only keep up to p->bufsize bytes.  Since
407214455Srpaulo		 * caplen > p->bufsize is exactly how we got here,
408214455Srpaulo		 * we know we can only keep the first p->bufsize bytes
409214455Srpaulo		 * and must drop the remainder.  Adjust caplen accordingly,
410214455Srpaulo		 * so we don't get confused later as to how many bytes we
411214455Srpaulo		 * have to play with.
412214455Srpaulo		 */
413214455Srpaulo		hdr->caplen = p->bufsize;
414214455Srpaulo		memcpy(p->buffer, (char *)tp, p->bufsize);
415214455Srpaulo	} else {
416214455Srpaulo		/* read the packet itself */
417214455Srpaulo		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
418214455Srpaulo		if (amt_read != hdr->caplen) {
419214455Srpaulo			if (ferror(fp)) {
420214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
421214455Srpaulo				    "error reading dump file: %s",
422214455Srpaulo				    pcap_strerror(errno));
423214455Srpaulo			} else {
424214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
425214455Srpaulo				    "truncated dump file; tried to read %u captured bytes, only got %lu",
426214455Srpaulo				    hdr->caplen, (unsigned long)amt_read);
427214455Srpaulo			}
428214455Srpaulo			return (-1);
429214455Srpaulo		}
430214455Srpaulo	}
431214455Srpaulo	*data = p->buffer;
432214455Srpaulo
433214455Srpaulo	if (p->sf.swapped) {
434214455Srpaulo		/*
435214455Srpaulo		 * Convert pseudo-headers from the byte order of
436214455Srpaulo		 * the host on which the file was saved to our
437214455Srpaulo		 * byte order, as necessary.
438214455Srpaulo		 */
439214455Srpaulo		switch (p->linktype) {
440214455Srpaulo
441214455Srpaulo		case DLT_USB_LINUX:
442214455Srpaulo			swap_linux_usb_header(hdr, *data, 0);
443214455Srpaulo			break;
444214455Srpaulo
445214455Srpaulo		case DLT_USB_LINUX_MMAPPED:
446214455Srpaulo			swap_linux_usb_header(hdr, *data, 1);
447214455Srpaulo			break;
448214455Srpaulo		}
449214455Srpaulo	}
450214455Srpaulo
451214455Srpaulo	return (0);
452214455Srpaulo}
453214455Srpaulo
454214455Srpaulostatic int
455214455Srpaulosf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
456214455Srpaulo{
457214455Srpaulo	struct pcap_file_header hdr;
458214455Srpaulo
459214455Srpaulo	hdr.magic = TCPDUMP_MAGIC;
460214455Srpaulo	hdr.version_major = PCAP_VERSION_MAJOR;
461214455Srpaulo	hdr.version_minor = PCAP_VERSION_MINOR;
462214455Srpaulo
463214455Srpaulo	hdr.thiszone = thiszone;
464214455Srpaulo	hdr.snaplen = snaplen;
465214455Srpaulo	hdr.sigfigs = 0;
466214455Srpaulo	hdr.linktype = linktype;
467214455Srpaulo
468214455Srpaulo	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
469214455Srpaulo		return (-1);
470214455Srpaulo
471214455Srpaulo	return (0);
472214455Srpaulo}
473214455Srpaulo
474214455Srpaulo/*
475214455Srpaulo * Output a packet to the initialized dump file.
476214455Srpaulo */
477214455Srpaulovoid
478214455Srpaulopcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
479214455Srpaulo{
480214455Srpaulo	register FILE *f;
481214455Srpaulo	struct pcap_sf_pkthdr sf_hdr;
482214455Srpaulo
483214455Srpaulo	f = (FILE *)user;
484214455Srpaulo	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
485214455Srpaulo	sf_hdr.ts.tv_usec = h->ts.tv_usec;
486214455Srpaulo	sf_hdr.caplen     = h->caplen;
487214455Srpaulo	sf_hdr.len        = h->len;
488214455Srpaulo	/* XXX we should check the return status */
489214455Srpaulo	(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
490214455Srpaulo	(void)fwrite(sp, h->caplen, 1, f);
491214455Srpaulo}
492214455Srpaulo
493214455Srpaulostatic pcap_dumper_t *
494214455Srpaulopcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
495214455Srpaulo{
496214455Srpaulo
497214455Srpaulo#if defined(WIN32) || defined(MSDOS)
498214455Srpaulo	/*
499214455Srpaulo	 * If we're writing to the standard output, put it in binary
500214455Srpaulo	 * mode, as savefiles are binary files.
501214455Srpaulo	 *
502214455Srpaulo	 * Otherwise, we turn off buffering.
503214455Srpaulo	 * XXX - why?  And why not on the standard output?
504214455Srpaulo	 */
505214455Srpaulo	if (f == stdout)
506214455Srpaulo		SET_BINMODE(f);
507214455Srpaulo	else
508214455Srpaulo		setbuf(f, NULL);
509214455Srpaulo#endif
510214455Srpaulo	if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) {
511214455Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
512214455Srpaulo		    fname, pcap_strerror(errno));
513214455Srpaulo		if (f != stdout)
514214455Srpaulo			(void)fclose(f);
515214455Srpaulo		return (NULL);
516214455Srpaulo	}
517214455Srpaulo	return ((pcap_dumper_t *)f);
518214455Srpaulo}
519214455Srpaulo
520214455Srpaulo/*
521214455Srpaulo * Initialize so that sf_write() will output to the file named 'fname'.
522214455Srpaulo */
523214455Srpaulopcap_dumper_t *
524214455Srpaulopcap_dump_open(pcap_t *p, const char *fname)
525214455Srpaulo{
526214455Srpaulo	FILE *f;
527214455Srpaulo	int linktype;
528214455Srpaulo
529214455Srpaulo	/*
530214455Srpaulo	 * If this pcap_t hasn't been activated, it doesn't have a
531214455Srpaulo	 * link-layer type, so we can't use it.
532214455Srpaulo	 */
533214455Srpaulo	if (!p->activated) {
534214455Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
535214455Srpaulo		    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
536214455Srpaulo		    fname);
537214455Srpaulo		return (NULL);
538214455Srpaulo	}
539214455Srpaulo	linktype = dlt_to_linktype(p->linktype);
540214455Srpaulo	if (linktype == -1) {
541214455Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
542214455Srpaulo		    "%s: link-layer type %d isn't supported in savefiles",
543214455Srpaulo		    fname, p->linktype);
544214455Srpaulo		return (NULL);
545214455Srpaulo	}
546214455Srpaulo	linktype |= p->linktype_ext;
547214455Srpaulo
548214455Srpaulo	if (fname[0] == '-' && fname[1] == '\0') {
549214455Srpaulo		f = stdout;
550214455Srpaulo		fname = "standard output";
551214455Srpaulo	} else {
552214455Srpaulo#if !defined(WIN32) && !defined(MSDOS)
553214455Srpaulo		f = fopen(fname, "w");
554214455Srpaulo#else
555214455Srpaulo		f = fopen(fname, "wb");
556214455Srpaulo#endif
557214455Srpaulo		if (f == NULL) {
558214455Srpaulo			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
559214455Srpaulo			    fname, pcap_strerror(errno));
560214455Srpaulo			return (NULL);
561214455Srpaulo		}
562214455Srpaulo	}
563214455Srpaulo	return (pcap_setup_dump(p, linktype, f, fname));
564214455Srpaulo}
565214455Srpaulo
566214455Srpaulo/*
567214455Srpaulo * Initialize so that sf_write() will output to the given stream.
568214455Srpaulo */
569214455Srpaulopcap_dumper_t *
570214455Srpaulopcap_dump_fopen(pcap_t *p, FILE *f)
571214455Srpaulo{
572214455Srpaulo	int linktype;
573214455Srpaulo
574214455Srpaulo	linktype = dlt_to_linktype(p->linktype);
575214455Srpaulo	if (linktype == -1) {
576214455Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
577214455Srpaulo		    "stream: link-layer type %d isn't supported in savefiles",
578214455Srpaulo		    p->linktype);
579214455Srpaulo		return (NULL);
580214455Srpaulo	}
581214455Srpaulo	linktype |= p->linktype_ext;
582214455Srpaulo
583214455Srpaulo	return (pcap_setup_dump(p, linktype, f, "stream"));
584214455Srpaulo}
585214455Srpaulo
586214455SrpauloFILE *
587214455Srpaulopcap_dump_file(pcap_dumper_t *p)
588214455Srpaulo{
589214455Srpaulo	return ((FILE *)p);
590214455Srpaulo}
591214455Srpaulo
592214455Srpaulolong
593214455Srpaulopcap_dump_ftell(pcap_dumper_t *p)
594214455Srpaulo{
595214455Srpaulo	return (ftell((FILE *)p));
596214455Srpaulo}
597214455Srpaulo
598214455Srpauloint
599214455Srpaulopcap_dump_flush(pcap_dumper_t *p)
600214455Srpaulo{
601214455Srpaulo
602214455Srpaulo	if (fflush((FILE *)p) == EOF)
603214455Srpaulo		return (-1);
604214455Srpaulo	else
605214455Srpaulo		return (0);
606214455Srpaulo}
607214455Srpaulo
608214455Srpaulovoid
609214455Srpaulopcap_dump_close(pcap_dumper_t *p)
610214455Srpaulo{
611214455Srpaulo
612214455Srpaulo#ifdef notyet
613214455Srpaulo	if (ferror((FILE *)p))
614214455Srpaulo		return-an-error;
615214455Srpaulo	/* XXX should check return from fclose() too */
616214455Srpaulo#endif
617214455Srpaulo	(void)fclose((FILE *)p);
618214455Srpaulo}
619