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-ng.c - pcap-ng-file-format-specific code from savefile.c
22214455Srpaulo */
23214455Srpaulo
24214455Srpaulo#ifndef lint
25214455Srpaulostatic const char rcsid[] _U_ =
26214455Srpaulo    "@(#) $Header$ (LBL)";
27214455Srpaulo#endif
28214455Srpaulo
29214455Srpaulo#ifdef HAVE_CONFIG_H
30214455Srpaulo#include "config.h"
31214455Srpaulo#endif
32214455Srpaulo
33214455Srpaulo#ifdef WIN32
34214455Srpaulo#include <pcap-stdinc.h>
35214455Srpaulo#else /* WIN32 */
36214455Srpaulo#if HAVE_INTTYPES_H
37214455Srpaulo#include <inttypes.h>
38214455Srpaulo#elif HAVE_STDINT_H
39214455Srpaulo#include <stdint.h>
40214455Srpaulo#endif
41214455Srpaulo#ifdef HAVE_SYS_BITYPES_H
42214455Srpaulo#include <sys/bitypes.h>
43214455Srpaulo#endif
44214455Srpaulo#include <sys/types.h>
45214455Srpaulo#endif /* WIN32 */
46214455Srpaulo
47214455Srpaulo#include <errno.h>
48214455Srpaulo#include <memory.h>
49214455Srpaulo#include <stdio.h>
50214455Srpaulo#include <stdlib.h>
51214455Srpaulo#include <string.h>
52214455Srpaulo
53214455Srpaulo#include "pcap-int.h"
54214455Srpaulo
55214455Srpaulo#include "pcap-common.h"
56214455Srpaulo
57214455Srpaulo#ifdef HAVE_OS_PROTO_H
58214455Srpaulo#include "os-proto.h"
59214455Srpaulo#endif
60214455Srpaulo
61214455Srpaulo#include "sf-pcap-ng.h"
62214455Srpaulo
63214455Srpaulo/*
64214455Srpaulo * Block types.
65214455Srpaulo */
66214455Srpaulo
67214455Srpaulo/*
68214455Srpaulo * Common part at the beginning of all blocks.
69214455Srpaulo */
70214455Srpaulostruct block_header {
71214455Srpaulo	bpf_u_int32	block_type;
72214455Srpaulo	bpf_u_int32	total_length;
73214455Srpaulo};
74214455Srpaulo
75214455Srpaulo/*
76214455Srpaulo * Common trailer at the end of all blocks.
77214455Srpaulo */
78214455Srpaulostruct block_trailer {
79214455Srpaulo	bpf_u_int32	total_length;
80214455Srpaulo};
81214455Srpaulo
82214455Srpaulo/*
83214455Srpaulo * Common options.
84214455Srpaulo */
85214455Srpaulo#define OPT_ENDOFOPT	0	/* end of options */
86214455Srpaulo#define OPT_COMMENT	1	/* comment string */
87214455Srpaulo
88214455Srpaulo/*
89214455Srpaulo * Option header.
90214455Srpaulo */
91214455Srpaulostruct option_header {
92214455Srpaulo	u_short		option_code;
93214455Srpaulo	u_short		option_length;
94214455Srpaulo};
95214455Srpaulo
96214455Srpaulo/*
97214455Srpaulo * Structures for the part of each block type following the common
98214455Srpaulo * part.
99214455Srpaulo */
100214455Srpaulo
101214455Srpaulo/*
102214455Srpaulo * Section Header Block.
103214455Srpaulo */
104214455Srpaulo#define BT_SHB			0x0A0D0D0A
105214455Srpaulo
106214455Srpaulostruct section_header_block {
107214455Srpaulo	bpf_u_int32	byte_order_magic;
108214455Srpaulo	u_short		major_version;
109214455Srpaulo	u_short		minor_version;
110214455Srpaulo	u_int64_t	section_length;
111214455Srpaulo	/* followed by options and trailer */
112214455Srpaulo};
113214455Srpaulo
114214455Srpaulo/*
115214455Srpaulo * Byte-order magic value.
116214455Srpaulo */
117214455Srpaulo#define BYTE_ORDER_MAGIC	0x1A2B3C4D
118214455Srpaulo
119214455Srpaulo/*
120214455Srpaulo * Current version number.  If major_version isn't PCAP_NG_VERSION_MAJOR,
121214455Srpaulo * that means that this code can't read the file.
122214455Srpaulo */
123214455Srpaulo#define PCAP_NG_VERSION_MAJOR	1
124214455Srpaulo
125214455Srpaulo/*
126214455Srpaulo * Interface Description Block.
127214455Srpaulo */
128214455Srpaulo#define BT_IDB			0x00000001
129214455Srpaulo
130214455Srpaulostruct interface_description_block {
131214455Srpaulo	u_short		linktype;
132214455Srpaulo	u_short		reserved;
133214455Srpaulo	bpf_u_int32	snaplen;
134214455Srpaulo	/* followed by options and trailer */
135214455Srpaulo};
136214455Srpaulo
137214455Srpaulo/*
138214455Srpaulo * Options in the IDB.
139214455Srpaulo */
140214455Srpaulo#define IF_NAME		2	/* interface name string */
141214455Srpaulo#define IF_DESCRIPTION	3	/* interface description string */
142214455Srpaulo#define IF_IPV4ADDR	4	/* interface's IPv4 address and netmask */
143214455Srpaulo#define IF_IPV6ADDR	5	/* interface's IPv6 address and prefix length */
144214455Srpaulo#define IF_MACADDR	6	/* interface's MAC address */
145214455Srpaulo#define IF_EUIADDR	7	/* interface's EUI address */
146214455Srpaulo#define IF_SPEED	8	/* interface's speed, in bits/s */
147214455Srpaulo#define IF_TSRESOL	9	/* interface's time stamp resolution */
148214455Srpaulo#define IF_TZONE	10	/* interface's time zone */
149214455Srpaulo#define IF_FILTER	11	/* filter used when capturing on interface */
150214455Srpaulo#define IF_OS		12	/* string OS on which capture on this interface was done */
151214455Srpaulo#define IF_FCSLEN	13	/* FCS length for this interface */
152214455Srpaulo#define IF_TSOFFSET	14	/* time stamp offset for this interface */
153214455Srpaulo
154214455Srpaulo/*
155214455Srpaulo * Enhanced Packet Block.
156214455Srpaulo */
157214455Srpaulo#define BT_EPB			0x00000006
158214455Srpaulo
159214455Srpaulostruct enhanced_packet_block {
160214455Srpaulo	bpf_u_int32	interface_id;
161214455Srpaulo	bpf_u_int32	timestamp_high;
162214455Srpaulo	bpf_u_int32	timestamp_low;
163214455Srpaulo	bpf_u_int32	caplen;
164214455Srpaulo	bpf_u_int32	len;
165214455Srpaulo	/* followed by packet data, options, and trailer */
166214455Srpaulo};
167214455Srpaulo
168214455Srpaulo/*
169214455Srpaulo * Simple Packet Block.
170214455Srpaulo */
171214455Srpaulo#define BT_SPB			0x00000003
172214455Srpaulo
173214455Srpaulostruct simple_packet_block {
174214455Srpaulo	bpf_u_int32	len;
175214455Srpaulo	/* followed by packet data and trailer */
176214455Srpaulo};
177214455Srpaulo
178214455Srpaulo/*
179214455Srpaulo * Packet Block.
180214455Srpaulo */
181214455Srpaulo#define BT_PB			0x00000002
182214455Srpaulo
183214455Srpaulostruct packet_block {
184214455Srpaulo	u_short		interface_id;
185214455Srpaulo	u_short		drops_count;
186214455Srpaulo	bpf_u_int32	timestamp_high;
187214455Srpaulo	bpf_u_int32	timestamp_low;
188214455Srpaulo	bpf_u_int32	caplen;
189214455Srpaulo	bpf_u_int32	len;
190214455Srpaulo	/* followed by packet data, options, and trailer */
191214455Srpaulo};
192214455Srpaulo
193214455Srpaulo/*
194214455Srpaulo * Block cursor - used when processing the contents of a block.
195214455Srpaulo * Contains a pointer into the data being processed and a count
196214455Srpaulo * of bytes remaining in the block.
197214455Srpaulo */
198214455Srpaulostruct block_cursor {
199214455Srpaulo	u_char		*data;
200214455Srpaulo	size_t		data_remaining;
201214455Srpaulo	bpf_u_int32	block_type;
202214455Srpaulo};
203214455Srpaulo
204214455Srpaulostatic int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
205214455Srpaulo    u_char **data);
206214455Srpaulo
207214455Srpaulostatic int
208214455Srpauloread_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
209214455Srpaulo    char *errbuf)
210214455Srpaulo{
211214455Srpaulo	size_t amt_read;
212214455Srpaulo
213214455Srpaulo	amt_read = fread(buf, 1, bytes_to_read, fp);
214214455Srpaulo	if (amt_read != bytes_to_read) {
215214455Srpaulo		if (ferror(fp)) {
216214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
217214455Srpaulo			    "error reading dump file: %s",
218214455Srpaulo			    pcap_strerror(errno));
219214455Srpaulo		} else {
220214455Srpaulo			if (amt_read == 0 && !fail_on_eof)
221214455Srpaulo				return (0);	/* EOF */
222214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
223214455Srpaulo			    "truncated dump file; tried to read %lu bytes, only got %lu",
224214455Srpaulo			    (unsigned long)bytes_to_read,
225214455Srpaulo			    (unsigned long)amt_read);
226214455Srpaulo		}
227214455Srpaulo		return (-1);
228214455Srpaulo	}
229214455Srpaulo	return (1);
230214455Srpaulo}
231214455Srpaulo
232214455Srpaulostatic int
233214455Srpauloread_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
234214455Srpaulo{
235214455Srpaulo	int status;
236214455Srpaulo	struct block_header bhdr;
237214455Srpaulo
238214455Srpaulo	status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf);
239214455Srpaulo	if (status <= 0)
240214455Srpaulo		return (status);	/* error or EOF */
241214455Srpaulo
242214455Srpaulo	if (p->sf.swapped) {
243214455Srpaulo		bhdr.block_type = SWAPLONG(bhdr.block_type);
244214455Srpaulo		bhdr.total_length = SWAPLONG(bhdr.total_length);
245214455Srpaulo	}
246214455Srpaulo
247214455Srpaulo	/*
248214455Srpaulo	 * Is this block "too big"?
249214455Srpaulo	 *
250214455Srpaulo	 * We choose 16MB as "too big", for now, so that we handle
251214455Srpaulo	 * "reasonably" large buffers but don't chew up all the
252214455Srpaulo	 * memory if we read a malformed file.
253214455Srpaulo	 */
254214455Srpaulo	if (bhdr.total_length > 16*1024*1024) {
255214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
256214455Srpaulo		    "pcap-ng block size %u > maximum %u",
257214455Srpaulo		    bhdr.total_length, 16*1024*1024);
258214455Srpaulo		    return (-1);
259214455Srpaulo	}
260214455Srpaulo
261214455Srpaulo	/*
262214455Srpaulo	 * Is this block "too small" - i.e., is it shorter than a block
263214455Srpaulo	 * header plus a block trailer?
264214455Srpaulo	 */
265214455Srpaulo	if (bhdr.total_length < sizeof(struct block_header) +
266214455Srpaulo	    sizeof(struct block_trailer)) {
267214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
268214455Srpaulo		    "block in pcap-ng dump file has a length of %u < %lu",
269214455Srpaulo		    bhdr.total_length,
270214455Srpaulo		    (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer)));
271214455Srpaulo		return (-1);
272214455Srpaulo	}
273214455Srpaulo
274214455Srpaulo	/*
275214455Srpaulo	 * Is the buffer big enough?
276214455Srpaulo	 */
277214455Srpaulo	if (p->bufsize < bhdr.total_length) {
278214455Srpaulo		/*
279214455Srpaulo		 * No - make it big enough.
280214455Srpaulo		 */
281214455Srpaulo		p->buffer = realloc(p->buffer, bhdr.total_length);
282214455Srpaulo		if (p->buffer == NULL) {
283214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
284214455Srpaulo			return (-1);
285214455Srpaulo		}
286214455Srpaulo	}
287214455Srpaulo
288214455Srpaulo	/*
289214455Srpaulo	 * Copy the stuff we've read to the buffer, and read the rest
290214455Srpaulo	 * of the block.
291214455Srpaulo	 */
292214455Srpaulo	memcpy(p->buffer, &bhdr, sizeof(bhdr));
293214455Srpaulo	if (read_bytes(fp, p->buffer + sizeof(bhdr),
294214455Srpaulo	    bhdr.total_length - sizeof(bhdr), 1, errbuf) == -1)
295214455Srpaulo		return (-1);
296214455Srpaulo
297214455Srpaulo	/*
298214455Srpaulo	 * Initialize the cursor.
299214455Srpaulo	 */
300214455Srpaulo	cursor->data = p->buffer + sizeof(bhdr);
301214455Srpaulo	cursor->data_remaining = bhdr.total_length - sizeof(bhdr) -
302214455Srpaulo	    sizeof(struct block_trailer);
303214455Srpaulo	cursor->block_type = bhdr.block_type;
304214455Srpaulo	return (1);
305214455Srpaulo}
306214455Srpaulo
307214455Srpaulostatic void *
308214455Srpauloget_from_block_data(struct block_cursor *cursor, size_t chunk_size,
309214455Srpaulo    char *errbuf)
310214455Srpaulo{
311214455Srpaulo	void *data;
312214455Srpaulo
313214455Srpaulo	/*
314214455Srpaulo	 * Make sure we have the specified amount of data remaining in
315214455Srpaulo	 * the block data.
316214455Srpaulo	 */
317214455Srpaulo	if (cursor->data_remaining < chunk_size) {
318214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
319214455Srpaulo		    "block of type %u in pcap-ng dump file is too short",
320214455Srpaulo		    cursor->block_type);
321214455Srpaulo		return (NULL);
322214455Srpaulo	}
323214455Srpaulo
324214455Srpaulo	/*
325214455Srpaulo	 * Return the current pointer, and skip past the chunk.
326214455Srpaulo	 */
327214455Srpaulo	data = cursor->data;
328214455Srpaulo	cursor->data += chunk_size;
329214455Srpaulo	cursor->data_remaining -= chunk_size;
330214455Srpaulo	return (data);
331214455Srpaulo}
332214455Srpaulo
333214455Srpaulostatic struct option_header *
334214455Srpauloget_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf)
335214455Srpaulo{
336214455Srpaulo	struct option_header *opthdr;
337214455Srpaulo
338214455Srpaulo	opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf);
339214455Srpaulo	if (opthdr == NULL) {
340214455Srpaulo		/*
341214455Srpaulo		 * Option header is cut short.
342214455Srpaulo		 */
343214455Srpaulo		return (NULL);
344214455Srpaulo	}
345214455Srpaulo
346214455Srpaulo	/*
347214455Srpaulo	 * Byte-swap it if necessary.
348214455Srpaulo	 */
349214455Srpaulo	if (p->sf.swapped) {
350214455Srpaulo		opthdr->option_code = SWAPSHORT(opthdr->option_code);
351214455Srpaulo		opthdr->option_length = SWAPSHORT(opthdr->option_length);
352214455Srpaulo	}
353214455Srpaulo
354214455Srpaulo	return (opthdr);
355214455Srpaulo}
356214455Srpaulo
357214455Srpaulostatic void *
358214455Srpauloget_optvalue_from_block_data(struct block_cursor *cursor,
359214455Srpaulo    struct option_header *opthdr, char *errbuf)
360214455Srpaulo{
361214455Srpaulo	size_t padded_option_len;
362214455Srpaulo	void *optvalue;
363214455Srpaulo
364214455Srpaulo	/* Pad option length to 4-byte boundary */
365214455Srpaulo	padded_option_len = opthdr->option_length;
366214455Srpaulo	padded_option_len = ((padded_option_len + 3)/4)*4;
367214455Srpaulo
368214455Srpaulo	optvalue = get_from_block_data(cursor, padded_option_len, errbuf);
369214455Srpaulo	if (optvalue == NULL) {
370214455Srpaulo		/*
371214455Srpaulo		 * Option value is cut short.
372214455Srpaulo		 */
373214455Srpaulo		return (NULL);
374214455Srpaulo	}
375214455Srpaulo
376214455Srpaulo	return (optvalue);
377214455Srpaulo}
378214455Srpaulo
379214455Srpaulostatic int
380214455Srpauloprocess_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
381214455Srpaulo    u_int64_t *tsoffset, char *errbuf)
382214455Srpaulo{
383214455Srpaulo	struct option_header *opthdr;
384214455Srpaulo	void *optvalue;
385214455Srpaulo	int saw_tsresol, saw_tsoffset;
386214455Srpaulo	u_char tsresol_opt;
387214455Srpaulo	u_int i;
388214455Srpaulo
389214455Srpaulo	saw_tsresol = 0;
390214455Srpaulo	saw_tsoffset = 0;
391214455Srpaulo	while (cursor->data_remaining != 0) {
392214455Srpaulo		/*
393214455Srpaulo		 * Get the option header.
394214455Srpaulo		 */
395214455Srpaulo		opthdr = get_opthdr_from_block_data(p, cursor, errbuf);
396214455Srpaulo		if (opthdr == NULL) {
397214455Srpaulo			/*
398214455Srpaulo			 * Option header is cut short.
399214455Srpaulo			 */
400214455Srpaulo			return (-1);
401214455Srpaulo		}
402214455Srpaulo
403214455Srpaulo		/*
404214455Srpaulo		 * Get option value.
405214455Srpaulo		 */
406214455Srpaulo		optvalue = get_optvalue_from_block_data(cursor, opthdr,
407214455Srpaulo		    errbuf);
408214455Srpaulo		if (optvalue == NULL) {
409214455Srpaulo			/*
410214455Srpaulo			 * Option value is cut short.
411214455Srpaulo			 */
412214455Srpaulo			return (-1);
413214455Srpaulo		}
414214455Srpaulo
415214455Srpaulo		switch (opthdr->option_code) {
416214455Srpaulo
417214455Srpaulo		case OPT_ENDOFOPT:
418214455Srpaulo			if (opthdr->option_length != 0) {
419214455Srpaulo				snprintf(errbuf, PCAP_ERRBUF_SIZE,
420214455Srpaulo				    "Interface Description Block has opt_endofopt option with length %u != 0",
421214455Srpaulo				    opthdr->option_length);
422214455Srpaulo				return (-1);
423214455Srpaulo			}
424214455Srpaulo			goto done;
425214455Srpaulo
426214455Srpaulo		case IF_TSRESOL:
427214455Srpaulo			if (opthdr->option_length != 1) {
428214455Srpaulo				snprintf(errbuf, PCAP_ERRBUF_SIZE,
429214455Srpaulo				    "Interface Description Block has if_tsresol option with length %u != 1",
430214455Srpaulo				    opthdr->option_length);
431214455Srpaulo				return (-1);
432214455Srpaulo			}
433214455Srpaulo			if (saw_tsresol) {
434214455Srpaulo				snprintf(errbuf, PCAP_ERRBUF_SIZE,
435214455Srpaulo				    "Interface Description Block has more than one if_tsresol option");
436214455Srpaulo				return (-1);
437214455Srpaulo			}
438214455Srpaulo			saw_tsresol = 1;
439214455Srpaulo			tsresol_opt = *(u_int *)optvalue;
440214455Srpaulo			if (tsresol_opt & 0x80) {
441214455Srpaulo				/*
442214455Srpaulo				 * Resolution is negative power of 2.
443214455Srpaulo				 */
444214455Srpaulo				*tsresol = 1 << (tsresol_opt & 0x7F);
445214455Srpaulo			} else {
446214455Srpaulo				/*
447214455Srpaulo				 * Resolution is negative power of 10.
448214455Srpaulo				 */
449214455Srpaulo				*tsresol = 1;
450214455Srpaulo				for (i = 0; i < tsresol_opt; i++)
451214455Srpaulo					*tsresol *= 10;
452214455Srpaulo			}
453214455Srpaulo			if (*tsresol == 0) {
454214455Srpaulo				/*
455214455Srpaulo				 * Resolution is too high.
456214455Srpaulo				 */
457214455Srpaulo				if (tsresol_opt & 0x80) {
458214455Srpaulo					snprintf(errbuf, PCAP_ERRBUF_SIZE,
459214455Srpaulo					    "Interface Description Block if_tsresol option resolution 2^-%u is too high",
460214455Srpaulo					    tsresol_opt & 0x7F);
461214455Srpaulo				} else {
462214455Srpaulo					snprintf(errbuf, PCAP_ERRBUF_SIZE,
463214455Srpaulo					    "Interface Description Block if_tsresol option resolution 10^-%u is too high",
464214455Srpaulo					    tsresol_opt);
465214455Srpaulo				}
466214455Srpaulo				return (-1);
467214455Srpaulo			}
468214455Srpaulo			break;
469214455Srpaulo
470214455Srpaulo		case IF_TSOFFSET:
471214455Srpaulo			if (opthdr->option_length != 8) {
472214455Srpaulo				snprintf(errbuf, PCAP_ERRBUF_SIZE,
473214455Srpaulo				    "Interface Description Block has if_tsoffset option with length %u != 8",
474214455Srpaulo				    opthdr->option_length);
475214455Srpaulo				return (-1);
476214455Srpaulo			}
477214455Srpaulo			if (saw_tsoffset) {
478214455Srpaulo				snprintf(errbuf, PCAP_ERRBUF_SIZE,
479214455Srpaulo				    "Interface Description Block has more than one if_tsoffset option");
480214455Srpaulo				return (-1);
481214455Srpaulo			}
482214455Srpaulo			saw_tsoffset = 1;
483214455Srpaulo			memcpy(tsoffset, optvalue, sizeof(*tsoffset));
484214455Srpaulo			if (p->sf.swapped)
485214455Srpaulo				*tsoffset = SWAPLL(*tsoffset);
486214455Srpaulo			break;
487214455Srpaulo
488214455Srpaulo		default:
489214455Srpaulo			break;
490214455Srpaulo		}
491214455Srpaulo	}
492214455Srpaulo
493214455Srpaulodone:
494214455Srpaulo	return (0);
495214455Srpaulo}
496214455Srpaulo
497214455Srpaulo/*
498214455Srpaulo * Check whether this is a pcap-ng savefile and, if it is, extract the
499214455Srpaulo * relevant information from the header.
500214455Srpaulo */
501214455Srpauloint
502214455Srpaulopcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
503214455Srpaulo{
504214455Srpaulo	size_t amt_read;
505214455Srpaulo	bpf_u_int32 total_length;
506214455Srpaulo	bpf_u_int32 byte_order_magic;
507214455Srpaulo	struct block_header *bhdrp;
508214455Srpaulo	struct section_header_block *shbp;
509214455Srpaulo	int status;
510214455Srpaulo	struct block_cursor cursor;
511214455Srpaulo	struct interface_description_block *idbp;
512214455Srpaulo
513214455Srpaulo	/*
514214455Srpaulo	 * Check whether the first 4 bytes of the file are the block
515214455Srpaulo	 * type for a pcap-ng savefile.
516214455Srpaulo	 */
517214455Srpaulo	if (magic != BT_SHB) {
518214455Srpaulo		/*
519214455Srpaulo		 * XXX - check whether this looks like what the block
520214455Srpaulo		 * type would be after being munged by mapping between
521214455Srpaulo		 * UN*X and DOS/Windows text file format and, if it
522214455Srpaulo		 * does, look for the byte-order magic number in
523214455Srpaulo		 * the appropriate place and, if we find it, report
524214455Srpaulo		 * this as possibly being a pcap-ng file transferred
525214455Srpaulo		 * between UN*X and Windows in text file format?
526214455Srpaulo		 */
527214455Srpaulo		return (0);	/* nope */
528214455Srpaulo	}
529214455Srpaulo
530214455Srpaulo	/*
531214455Srpaulo	 * OK, they are.  However, that's just \n\r\r\n, so it could,
532214455Srpaulo	 * conceivably, be an ordinary text file.
533214455Srpaulo	 *
534214455Srpaulo	 * It could not, however, conceivably be any other type of
535214455Srpaulo	 * capture file, so we can read the rest of the putative
536214455Srpaulo	 * Section Header Block; put the block type in the common
537214455Srpaulo	 * header, read the rest of the common header and the
538214455Srpaulo	 * fixed-length portion of the SHB, and look for the byte-order
539214455Srpaulo	 * magic value.
540214455Srpaulo	 */
541214455Srpaulo	amt_read = fread(&total_length, 1, sizeof(total_length), fp);
542214455Srpaulo	if (amt_read < sizeof(total_length)) {
543214455Srpaulo		if (ferror(fp)) {
544214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
545214455Srpaulo			    "error reading dump file: %s",
546214455Srpaulo			    pcap_strerror(errno));
547214455Srpaulo			return (-1);	/* fail */
548214455Srpaulo		}
549214455Srpaulo
550214455Srpaulo		/*
551214455Srpaulo		 * Possibly a weird short text file, so just say
552214455Srpaulo		 * "not pcap-ng".
553214455Srpaulo		 */
554214455Srpaulo		return (0);
555214455Srpaulo	}
556214455Srpaulo	amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp);
557214455Srpaulo	if (amt_read < sizeof(byte_order_magic)) {
558214455Srpaulo		if (ferror(fp)) {
559214455Srpaulo			snprintf(errbuf, PCAP_ERRBUF_SIZE,
560214455Srpaulo			    "error reading dump file: %s",
561214455Srpaulo			    pcap_strerror(errno));
562214455Srpaulo			return (-1);	/* fail */
563214455Srpaulo		}
564214455Srpaulo
565214455Srpaulo		/*
566214455Srpaulo		 * Possibly a weird short text file, so just say
567214455Srpaulo		 * "not pcap-ng".
568214455Srpaulo		 */
569214455Srpaulo		return (0);
570214455Srpaulo	}
571214455Srpaulo	if (byte_order_magic != BYTE_ORDER_MAGIC) {
572214455Srpaulo		byte_order_magic = SWAPLONG(byte_order_magic);
573214455Srpaulo		if (byte_order_magic != BYTE_ORDER_MAGIC) {
574214455Srpaulo			/*
575214455Srpaulo			 * Not a pcap-ng file.
576214455Srpaulo			 */
577214455Srpaulo			return (0);
578214455Srpaulo		}
579214455Srpaulo		p->sf.swapped = 1;
580214455Srpaulo		total_length = SWAPLONG(total_length);
581214455Srpaulo	}
582214455Srpaulo
583214455Srpaulo	/*
584214455Srpaulo	 * Check the sanity of the total length.
585214455Srpaulo	 */
586214455Srpaulo	if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) {
587214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
588214455Srpaulo		    "Section Header Block in pcap-ng dump file has a length of %u < %lu",
589214455Srpaulo		    total_length,
590214455Srpaulo		    (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)));
591214455Srpaulo		return (-1);
592214455Srpaulo	}
593214455Srpaulo
594214455Srpaulo	/*
595214455Srpaulo	 * Allocate a buffer into which to read blocks.  We default to
596214455Srpaulo	 * the maximum of:
597214455Srpaulo	 *
598214455Srpaulo	 *	the total length of the SHB for which we read the header;
599214455Srpaulo	 *
600214455Srpaulo	 *	2K, which should be more than large enough for an Enhanced
601214455Srpaulo	 *	Packet Block containing a full-size Ethernet frame, and
602214455Srpaulo	 *	leaving room for some options.
603214455Srpaulo	 *
604214455Srpaulo	 * If we find a bigger block, we reallocate the buffer.
605214455Srpaulo	 */
606214455Srpaulo	p->bufsize = 2048;
607214455Srpaulo	if (p->bufsize < total_length)
608214455Srpaulo		p->bufsize = total_length;
609214455Srpaulo	p->buffer = malloc(p->bufsize);
610214455Srpaulo	if (p->buffer == NULL) {
611214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
612214455Srpaulo		return (-1);
613214455Srpaulo	}
614214455Srpaulo
615214455Srpaulo	/*
616214455Srpaulo	 * Copy the stuff we've read to the buffer, and read the rest
617214455Srpaulo	 * of the SHB.
618214455Srpaulo	 */
619214455Srpaulo	bhdrp = (struct block_header *)p->buffer;
620214455Srpaulo	shbp = (struct section_header_block *)(p->buffer + sizeof(struct block_header));
621214455Srpaulo	bhdrp->block_type = magic;
622214455Srpaulo	bhdrp->total_length = total_length;
623214455Srpaulo	shbp->byte_order_magic = byte_order_magic;
624214455Srpaulo	if (read_bytes(fp,
625214455Srpaulo	    p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
626214455Srpaulo	    total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
627214455Srpaulo	    1, errbuf) == -1)
628214455Srpaulo		goto fail;
629214455Srpaulo
630214455Srpaulo	if (p->sf.swapped) {
631214455Srpaulo		/*
632214455Srpaulo		 * Byte-swap the fields we've read.
633214455Srpaulo		 */
634214455Srpaulo		shbp->major_version = SWAPSHORT(shbp->major_version);
635214455Srpaulo		shbp->minor_version = SWAPSHORT(shbp->minor_version);
636214455Srpaulo
637214455Srpaulo		/*
638214455Srpaulo		 * XXX - we don't care about the section length.
639214455Srpaulo		 */
640214455Srpaulo	}
641214455Srpaulo	if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
642214455Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE,
643214455Srpaulo		    "unknown pcap-ng savefile major version number %u",
644214455Srpaulo		    shbp->major_version);
645214455Srpaulo		goto fail;
646214455Srpaulo	}
647214455Srpaulo	p->sf.version_major = shbp->major_version;
648214455Srpaulo	p->sf.version_minor = shbp->minor_version;
649214455Srpaulo
650214455Srpaulo	/*
651214455Srpaulo	 * Set the default time stamp resolution and offset.
652214455Srpaulo	 */
653214455Srpaulo	p->sf.tsresol = 1000000;	/* microsecond resolution */
654214455Srpaulo	p->sf.tsscale = 1;		/* multiply by 1 to scale to microseconds */
655214455Srpaulo	p->sf.tsoffset = 0;		/* absolute timestamps */
656214455Srpaulo
657214455Srpaulo	/*
658214455Srpaulo	 * Now start looking for an Interface Description Block.
659214455Srpaulo	 */
660214455Srpaulo	for (;;) {
661214455Srpaulo		/*
662214455Srpaulo		 * Read the next block.
663214455Srpaulo		 */
664214455Srpaulo		status = read_block(fp, p, &cursor, errbuf);
665214455Srpaulo		if (status == 0) {
666214455Srpaulo			/* EOF - no IDB in this file */
667214455Srpaulo			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
668214455Srpaulo			    "the capture file has no Interface Description Blocks");
669214455Srpaulo			goto fail;
670214455Srpaulo		}
671214455Srpaulo		if (status == -1)
672214455Srpaulo			goto fail;	/* error */
673214455Srpaulo		switch (cursor.block_type) {
674214455Srpaulo
675214455Srpaulo		case BT_IDB:
676214455Srpaulo			/*
677214455Srpaulo			 * Get a pointer to the fixed-length portion of the
678214455Srpaulo			 * IDB.
679214455Srpaulo			 */
680214455Srpaulo			idbp = get_from_block_data(&cursor, sizeof(*idbp),
681214455Srpaulo			    errbuf);
682214455Srpaulo			if (idbp == NULL)
683214455Srpaulo				goto fail;	/* error */
684214455Srpaulo
685214455Srpaulo			/*
686214455Srpaulo			 * Byte-swap it if necessary.
687214455Srpaulo			 */
688214455Srpaulo			if (p->sf.swapped) {
689214455Srpaulo				idbp->linktype = SWAPSHORT(idbp->linktype);
690214455Srpaulo				idbp->snaplen = SWAPLONG(idbp->snaplen);
691214455Srpaulo			}
692214455Srpaulo
693214455Srpaulo			/*
694214455Srpaulo			 * Count this interface.
695214455Srpaulo			 */
696214455Srpaulo			p->sf.ifcount++;
697214455Srpaulo
698214455Srpaulo			/*
699214455Srpaulo			 * Now look for various time stamp options, so
700214455Srpaulo			 * we know how to interpret the time stamps.
701214455Srpaulo			 */
702214455Srpaulo			if (process_idb_options(p, &cursor, &p->sf.tsresol,
703214455Srpaulo			    &p->sf.tsoffset, errbuf) == -1)
704214455Srpaulo				goto fail;
705214455Srpaulo
706214455Srpaulo			/*
707214455Srpaulo			 * Compute the scaling factor to convert the
708214455Srpaulo			 * sub-second part of the time stamp to
709214455Srpaulo			 * microseconds.
710214455Srpaulo			 */
711214455Srpaulo			if (p->sf.tsresol > 1000000) {
712214455Srpaulo				/*
713214455Srpaulo				 * Higher than microsecond resolution;
714214455Srpaulo				 * scale down to microseconds.
715214455Srpaulo				 */
716214455Srpaulo				p->sf.tsscale = (p->sf.tsresol / 1000000);
717214455Srpaulo			} else {
718214455Srpaulo				/*
719214455Srpaulo				 * Lower than microsecond resolution;
720214455Srpaulo				 * scale up to microseconds.
721214455Srpaulo				 */
722214455Srpaulo				p->sf.tsscale = (1000000 / p->sf.tsresol);
723214455Srpaulo			}
724214455Srpaulo			goto done;
725214455Srpaulo
726214455Srpaulo		case BT_EPB:
727214455Srpaulo		case BT_SPB:
728214455Srpaulo		case BT_PB:
729214455Srpaulo			/*
730214455Srpaulo			 * Saw a packet before we saw any IDBs.  That's
731214455Srpaulo			 * not valid, as we don't know what link-layer
732214455Srpaulo			 * encapsulation the packet has.
733214455Srpaulo			 */
734214455Srpaulo			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
735214455Srpaulo			    "the capture file has a packet block before any Interface Description Blocks");
736214455Srpaulo			goto fail;
737214455Srpaulo
738214455Srpaulo		default:
739214455Srpaulo			/*
740214455Srpaulo			 * Just ignore it.
741214455Srpaulo			 */
742214455Srpaulo			break;
743214455Srpaulo		}
744214455Srpaulo	}
745214455Srpaulo
746214455Srpaulodone:
747214455Srpaulo	p->tzoff = 0;	/* XXX - not used in pcap */
748214455Srpaulo	p->snapshot = idbp->snaplen;
749236167Sdelphij	p->linktype = linktype_to_dlt(idbp->linktype);
750214455Srpaulo	p->linktype_ext = 0;
751214455Srpaulo
752214455Srpaulo	p->sf.next_packet_op = pcap_ng_next_packet;
753214455Srpaulo
754214455Srpaulo	return (1);
755214455Srpaulo
756214455Srpaulofail:
757214455Srpaulo	free(p->buffer);
758214455Srpaulo	return (-1);
759214455Srpaulo}
760214455Srpaulo
761214455Srpaulo/*
762214455Srpaulo * Read and return the next packet from the savefile.  Return the header
763214455Srpaulo * in hdr and a pointer to the contents in data.  Return 0 on success, 1
764214455Srpaulo * if there were no more packets, and -1 on an error.
765214455Srpaulo */
766214455Srpaulostatic int
767214455Srpaulopcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
768214455Srpaulo{
769214455Srpaulo	struct block_cursor cursor;
770214455Srpaulo	int status;
771214455Srpaulo	struct enhanced_packet_block *epbp;
772214455Srpaulo	struct simple_packet_block *spbp;
773214455Srpaulo	struct packet_block *pbp;
774214455Srpaulo	bpf_u_int32 interface_id = 0xFFFFFFFF;
775214455Srpaulo	struct interface_description_block *idbp;
776214455Srpaulo	struct section_header_block *shbp;
777214455Srpaulo	FILE *fp = p->sf.rfile;
778214455Srpaulo	u_int tsresol;
779214455Srpaulo	u_int64_t tsoffset;
780214455Srpaulo	u_int64_t t, sec, frac;
781214455Srpaulo
782214455Srpaulo	/*
783214455Srpaulo	 * Look for an Enhanced Packet Block, a Simple Packet Block,
784214455Srpaulo	 * or a Packet Block.
785214455Srpaulo	 */
786214455Srpaulo	for (;;) {
787214455Srpaulo		/*
788214455Srpaulo		 * Read the block type and length; those are common
789214455Srpaulo		 * to all blocks.
790214455Srpaulo		 */
791214455Srpaulo		status = read_block(fp, p, &cursor, p->errbuf);
792214455Srpaulo		if (status == 0)
793214455Srpaulo			return (1);	/* EOF */
794214455Srpaulo		if (status == -1)
795214455Srpaulo			return (-1);	/* error */
796214455Srpaulo		switch (cursor.block_type) {
797214455Srpaulo
798214455Srpaulo		case BT_EPB:
799214455Srpaulo			/*
800214455Srpaulo			 * Get a pointer to the fixed-length portion of the
801214455Srpaulo			 * EPB.
802214455Srpaulo			 */
803214455Srpaulo			epbp = get_from_block_data(&cursor, sizeof(*epbp),
804214455Srpaulo			    p->errbuf);
805214455Srpaulo			if (epbp == NULL)
806214455Srpaulo				return (-1);	/* error */
807214455Srpaulo
808214455Srpaulo			/*
809214455Srpaulo			 * Byte-swap it if necessary.
810214455Srpaulo			 */
811214455Srpaulo			if (p->sf.swapped) {
812214455Srpaulo				/* these were written in opposite byte order */
813214455Srpaulo				interface_id = SWAPLONG(epbp->interface_id);
814214455Srpaulo				hdr->caplen = SWAPLONG(epbp->caplen);
815214455Srpaulo				hdr->len = SWAPLONG(epbp->len);
816214455Srpaulo				t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 |
817214455Srpaulo				    SWAPLONG(epbp->timestamp_low);
818214455Srpaulo			} else {
819214455Srpaulo				interface_id = epbp->interface_id;
820214455Srpaulo				hdr->caplen = epbp->caplen;
821214455Srpaulo				hdr->len = epbp->len;
822214455Srpaulo				t = ((u_int64_t)epbp->timestamp_high) << 32 |
823214455Srpaulo				    epbp->timestamp_low;
824214455Srpaulo			}
825214455Srpaulo			goto found;
826214455Srpaulo
827214455Srpaulo		case BT_SPB:
828214455Srpaulo			/*
829214455Srpaulo			 * Get a pointer to the fixed-length portion of the
830214455Srpaulo			 * SPB.
831214455Srpaulo			 */
832214455Srpaulo			spbp = get_from_block_data(&cursor, sizeof(*spbp),
833214455Srpaulo			    p->errbuf);
834214455Srpaulo			if (spbp == NULL)
835214455Srpaulo				return (-1);	/* error */
836214455Srpaulo
837214455Srpaulo			/*
838214455Srpaulo			 * SPB packets are assumed to have arrived on
839214455Srpaulo			 * the first interface.
840214455Srpaulo			 */
841214455Srpaulo			interface_id = 0;
842214455Srpaulo
843214455Srpaulo			/*
844214455Srpaulo			 * Byte-swap it if necessary.
845214455Srpaulo			 */
846214455Srpaulo			if (p->sf.swapped) {
847214455Srpaulo				/* these were written in opposite byte order */
848214455Srpaulo				hdr->len = SWAPLONG(spbp->len);
849214455Srpaulo			} else
850214455Srpaulo				hdr->len = spbp->len;
851214455Srpaulo
852214455Srpaulo			/*
853214455Srpaulo			 * The SPB doesn't give the captured length;
854214455Srpaulo			 * it's the minimum of the snapshot length
855214455Srpaulo			 * and the packet length.
856214455Srpaulo			 */
857214455Srpaulo			hdr->caplen = hdr->len;
858214455Srpaulo			if (hdr->caplen > p->snapshot)
859214455Srpaulo				hdr->caplen = p->snapshot;
860214455Srpaulo			t = 0;	/* no time stamps */
861214455Srpaulo			goto found;
862214455Srpaulo
863214455Srpaulo		case BT_PB:
864214455Srpaulo			/*
865214455Srpaulo			 * Get a pointer to the fixed-length portion of the
866214455Srpaulo			 * PB.
867214455Srpaulo			 */
868214455Srpaulo			pbp = get_from_block_data(&cursor, sizeof(*pbp),
869214455Srpaulo			    p->errbuf);
870214455Srpaulo			if (pbp == NULL)
871214455Srpaulo				return (-1);	/* error */
872214455Srpaulo
873214455Srpaulo			/*
874214455Srpaulo			 * Byte-swap it if necessary.
875214455Srpaulo			 */
876214455Srpaulo			if (p->sf.swapped) {
877214455Srpaulo				/* these were written in opposite byte order */
878214455Srpaulo				interface_id = SWAPSHORT(pbp->interface_id);
879214455Srpaulo				hdr->caplen = SWAPLONG(pbp->caplen);
880214455Srpaulo				hdr->len = SWAPLONG(pbp->len);
881214455Srpaulo				t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 |
882214455Srpaulo				    SWAPLONG(pbp->timestamp_low);
883214455Srpaulo			} else {
884214455Srpaulo				interface_id = pbp->interface_id;
885214455Srpaulo				hdr->caplen = pbp->caplen;
886214455Srpaulo				hdr->len = pbp->len;
887214455Srpaulo				t = ((u_int64_t)pbp->timestamp_high) << 32 |
888214455Srpaulo				    pbp->timestamp_low;
889214455Srpaulo			}
890214455Srpaulo			goto found;
891214455Srpaulo
892214455Srpaulo		case BT_IDB:
893214455Srpaulo			/*
894214455Srpaulo			 * Interface Description Block.  Get a pointer
895214455Srpaulo			 * to its fixed-length portion.
896214455Srpaulo			 */
897214455Srpaulo			idbp = get_from_block_data(&cursor, sizeof(*idbp),
898214455Srpaulo			    p->errbuf);
899214455Srpaulo			if (idbp == NULL)
900214455Srpaulo				return (-1);	/* error */
901214455Srpaulo
902214455Srpaulo			/*
903214455Srpaulo			 * Byte-swap it if necessary.
904214455Srpaulo			 */
905214455Srpaulo			if (p->sf.swapped) {
906214455Srpaulo				idbp->linktype = SWAPSHORT(idbp->linktype);
907214455Srpaulo				idbp->snaplen = SWAPLONG(idbp->snaplen);
908214455Srpaulo			}
909214455Srpaulo
910214455Srpaulo			/*
911214455Srpaulo			 * If the link-layer type or snapshot length
912214455Srpaulo			 * differ from the ones for the first IDB we
913214455Srpaulo			 * saw, quit.
914214455Srpaulo			 *
915214455Srpaulo			 * XXX - just discard packets from those
916214455Srpaulo			 * interfaces?
917214455Srpaulo			 */
918214455Srpaulo			if (p->linktype != idbp->linktype) {
919214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
920214455Srpaulo				    "an interface has a type %u different from the type of the first interface",
921214455Srpaulo				    idbp->linktype);
922214455Srpaulo				return (-1);
923214455Srpaulo			}
924214455Srpaulo			if (p->snapshot != idbp->snaplen) {
925214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
926214455Srpaulo				    "an interface has a snapshot length %u different from the type of the first interface",
927214455Srpaulo				    idbp->snaplen);
928214455Srpaulo				return (-1);
929214455Srpaulo			}
930214455Srpaulo
931214455Srpaulo			/*
932214455Srpaulo			 * Count this interface.
933214455Srpaulo			 */
934214455Srpaulo			p->sf.ifcount++;
935214455Srpaulo
936214455Srpaulo			/*
937214455Srpaulo			 * Set the default time stamp resolution and offset.
938214455Srpaulo			 */
939214455Srpaulo			tsresol = 1000000;	/* microsecond resolution */
940214455Srpaulo			tsoffset = 0;		/* absolute timestamps */
941214455Srpaulo
942214455Srpaulo			/*
943214455Srpaulo			 * Now look for various time stamp options, to
944214455Srpaulo			 * make sure they're the same.
945214455Srpaulo			 *
946214455Srpaulo			 * XXX - we could, in theory, handle multiple
947214455Srpaulo			 * different resolutions and offsets, but we
948214455Srpaulo			 * don't do so for now.
949214455Srpaulo			 */
950214455Srpaulo			if (process_idb_options(p, &cursor, &tsresol, &tsoffset,
951214455Srpaulo			    p->errbuf) == -1)
952214455Srpaulo				return (-1);
953214455Srpaulo			if (tsresol != p->sf.tsresol) {
954214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
955214455Srpaulo				    "an interface has a time stamp resolution different from the time stamp resolution of the first interface");
956214455Srpaulo				return (-1);
957214455Srpaulo			}
958214455Srpaulo			if (tsoffset != p->sf.tsoffset) {
959214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
960214455Srpaulo				    "an interface has a time stamp offset different from the time stamp offset of the first interface");
961214455Srpaulo				return (-1);
962214455Srpaulo			}
963214455Srpaulo			break;
964214455Srpaulo
965214455Srpaulo		case BT_SHB:
966214455Srpaulo			/*
967214455Srpaulo			 * Section Header Block.  Get a pointer
968214455Srpaulo			 * to its fixed-length portion.
969214455Srpaulo			 */
970214455Srpaulo			shbp = get_from_block_data(&cursor, sizeof(*shbp),
971214455Srpaulo			    p->errbuf);
972214455Srpaulo			if (shbp == NULL)
973214455Srpaulo				return (-1);	/* error */
974214455Srpaulo
975214455Srpaulo			/*
976214455Srpaulo			 * Assume the byte order of this section is
977214455Srpaulo			 * the same as that of the previous section.
978214455Srpaulo			 * We'll check for that later.
979214455Srpaulo			 */
980214455Srpaulo			if (p->sf.swapped) {
981214455Srpaulo				shbp->byte_order_magic =
982214455Srpaulo				    SWAPLONG(shbp->byte_order_magic);
983214455Srpaulo				shbp->major_version =
984214455Srpaulo				    SWAPSHORT(shbp->major_version);
985214455Srpaulo			}
986214455Srpaulo
987214455Srpaulo			/*
988214455Srpaulo			 * Make sure the byte order doesn't change;
989214455Srpaulo			 * pcap_is_swapped() shouldn't change its
990214455Srpaulo			 * return value in the middle of reading a capture.
991214455Srpaulo			 */
992214455Srpaulo			switch (shbp->byte_order_magic) {
993214455Srpaulo
994214455Srpaulo			case BYTE_ORDER_MAGIC:
995214455Srpaulo				/*
996214455Srpaulo				 * OK.
997214455Srpaulo				 */
998214455Srpaulo				break;
999214455Srpaulo
1000214455Srpaulo			case SWAPLONG(BYTE_ORDER_MAGIC):
1001214455Srpaulo				/*
1002214455Srpaulo				 * Byte order changes.
1003214455Srpaulo				 */
1004214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1005214455Srpaulo				    "the file has sections with different byte orders");
1006214455Srpaulo				return (-1);
1007214455Srpaulo
1008214455Srpaulo			default:
1009214455Srpaulo				/*
1010214455Srpaulo				 * Not a valid SHB.
1011214455Srpaulo				 */
1012214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1013214455Srpaulo				    "the file has a section with a bad byte order magic field");
1014214455Srpaulo				return (-1);
1015214455Srpaulo			}
1016214455Srpaulo
1017214455Srpaulo			/*
1018214455Srpaulo			 * Make sure the major version is the version
1019214455Srpaulo			 * we handle.
1020214455Srpaulo			 */
1021214455Srpaulo			if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
1022214455Srpaulo				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1023214455Srpaulo				    "unknown pcap-ng savefile major version number %u",
1024214455Srpaulo				    shbp->major_version);
1025214455Srpaulo				return (-1);
1026214455Srpaulo			}
1027214455Srpaulo
1028214455Srpaulo			/*
1029214455Srpaulo			 * Reset the interface count; this section should
1030214455Srpaulo			 * have its own set of IDBs.  If any of them
1031214455Srpaulo			 * don't have the same interface type, snapshot
1032214455Srpaulo			 * length, or resolution as the first interface
1033214455Srpaulo			 * we saw, we'll fail.  (And if we don't see
1034214455Srpaulo			 * any IDBs, we'll fail when we see a packet
1035214455Srpaulo			 * block.)
1036214455Srpaulo			 */
1037214455Srpaulo			p->sf.ifcount = 0;
1038214455Srpaulo			break;
1039214455Srpaulo
1040214455Srpaulo		default:
1041214455Srpaulo			/*
1042214455Srpaulo			 * Not a packet block, IDB, or SHB; ignore it.
1043214455Srpaulo			 */
1044214455Srpaulo			break;
1045214455Srpaulo		}
1046214455Srpaulo	}
1047214455Srpaulo
1048214455Srpaulofound:
1049214455Srpaulo	/*
1050214455Srpaulo	 * Is the interface ID an interface we know?
1051214455Srpaulo	 */
1052236167Sdelphij	if (interface_id >= p->sf.ifcount) {
1053214455Srpaulo		/*
1054214455Srpaulo		 * Yes.  Fail.
1055214455Srpaulo		 */
1056214455Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1057214455Srpaulo		    "a packet arrived on interface %u, but there's no Interface Description Block for that interface",
1058214455Srpaulo		    interface_id);
1059214455Srpaulo		return (-1);
1060214455Srpaulo	}
1061214455Srpaulo
1062214455Srpaulo	/*
1063214455Srpaulo	 * Convert the time stamp to a struct timeval.
1064214455Srpaulo	 */
1065214455Srpaulo	sec = t / p->sf.tsresol + p->sf.tsoffset;
1066214455Srpaulo	frac = t % p->sf.tsresol;
1067214455Srpaulo	if (p->sf.tsresol > 1000000) {
1068214455Srpaulo		/*
1069214455Srpaulo		 * Higher than microsecond resolution; scale down to
1070214455Srpaulo		 * microseconds.
1071214455Srpaulo		 */
1072214455Srpaulo		frac /= p->sf.tsscale;
1073214455Srpaulo	} else {
1074214455Srpaulo		/*
1075214455Srpaulo		 * Lower than microsecond resolution; scale up to
1076214455Srpaulo		 * microseconds.
1077214455Srpaulo		 */
1078214455Srpaulo		frac *= p->sf.tsscale;
1079214455Srpaulo	}
1080214455Srpaulo	hdr->ts.tv_sec = sec;
1081214455Srpaulo	hdr->ts.tv_usec = frac;
1082214455Srpaulo
1083214455Srpaulo	/*
1084214455Srpaulo	 * Get a pointer to the packet data.
1085214455Srpaulo	 */
1086214455Srpaulo	*data = get_from_block_data(&cursor, hdr->caplen, p->errbuf);
1087214455Srpaulo	if (*data == NULL)
1088214455Srpaulo		return (-1);
1089214455Srpaulo
1090214455Srpaulo	if (p->sf.swapped) {
1091214455Srpaulo		/*
1092214455Srpaulo		 * Convert pseudo-headers from the byte order of
1093214455Srpaulo		 * the host on which the file was saved to our
1094214455Srpaulo		 * byte order, as necessary.
1095214455Srpaulo		 */
1096214455Srpaulo		switch (p->linktype) {
1097214455Srpaulo
1098214455Srpaulo		case DLT_USB_LINUX:
1099214455Srpaulo			swap_linux_usb_header(hdr, *data, 0);
1100214455Srpaulo			break;
1101214455Srpaulo
1102214455Srpaulo		case DLT_USB_LINUX_MMAPPED:
1103214455Srpaulo			swap_linux_usb_header(hdr, *data, 1);
1104214455Srpaulo			break;
1105214455Srpaulo		}
1106214455Srpaulo	}
1107214455Srpaulo
1108214455Srpaulo	return (0);
1109214455Srpaulo}
1110