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