nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 1993, 1994, 1995, 1996, 1997 |
||
3 | * The Regents of the University of California. All rights reserved. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that: (1) source code distributions |
||
7 | * retain the above copyright notice and this paragraph in its entirety, (2) |
||
8 | * distributions including binary code include the above copyright notice and |
||
9 | * this paragraph in its entirety in the documentation or other materials |
||
10 | * provided with the distribution, and (3) all advertising materials mentioning |
||
11 | * features or use of this software display the following acknowledgement: |
||
12 | * ``This product includes software developed by the University of California, |
||
13 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
||
14 | * the University nor the names of its contributors may be used to endorse |
||
15 | * or promote products derived from this software without specific prior |
||
16 | * written permission. |
||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||
18 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
||
20 | * |
||
21 | * sf-pcap-ng.c - pcap-ng-file-format-specific code from savefile.c |
||
22 | */ |
||
23 | |||
24 | #ifndef lint |
||
25 | static const char rcsid[] _U_ = |
||
26 | "@(#) $Header$ (LBL)"; |
||
27 | #endif |
||
28 | |||
29 | #ifdef HAVE_CONFIG_H |
||
30 | #include "config.h" |
||
31 | #endif |
||
32 | |||
33 | #ifdef WIN32 |
||
34 | #include <pcap-stdinc.h> |
||
35 | #else /* WIN32 */ |
||
36 | #if HAVE_INTTYPES_H |
||
37 | #include <inttypes.h> |
||
38 | #elif HAVE_STDINT_H |
||
39 | #include <stdint.h> |
||
40 | #endif |
||
41 | #ifdef HAVE_SYS_BITYPES_H |
||
42 | #include <sys/bitypes.h> |
||
43 | #endif |
||
44 | #include <sys/types.h> |
||
45 | #endif /* WIN32 */ |
||
46 | |||
47 | #include <errno.h> |
||
48 | #include <memory.h> |
||
49 | #include <stdio.h> |
||
50 | #include <stdlib.h> |
||
51 | #include <string.h> |
||
52 | |||
53 | #include "pcap-int.h" |
||
54 | |||
55 | #include "pcap-common.h" |
||
56 | |||
57 | #ifdef HAVE_OS_PROTO_H |
||
58 | #include "os-proto.h" |
||
59 | #endif |
||
60 | |||
61 | #include "sf-pcap-ng.h" |
||
62 | |||
63 | /* |
||
64 | * Block types. |
||
65 | */ |
||
66 | |||
67 | /* |
||
68 | * Common part at the beginning of all blocks. |
||
69 | */ |
||
70 | struct block_header { |
||
71 | bpf_u_int32 block_type; |
||
72 | bpf_u_int32 total_length; |
||
73 | }; |
||
74 | |||
75 | /* |
||
76 | * Common trailer at the end of all blocks. |
||
77 | */ |
||
78 | struct block_trailer { |
||
79 | bpf_u_int32 total_length; |
||
80 | }; |
||
81 | |||
82 | /* |
||
83 | * Common options. |
||
84 | */ |
||
85 | #define OPT_ENDOFOPT 0 /* end of options */ |
||
86 | #define OPT_COMMENT 1 /* comment string */ |
||
87 | |||
88 | /* |
||
89 | * Option header. |
||
90 | */ |
||
91 | struct option_header { |
||
92 | u_short option_code; |
||
93 | u_short option_length; |
||
94 | }; |
||
95 | |||
96 | /* |
||
97 | * Structures for the part of each block type following the common |
||
98 | * part. |
||
99 | */ |
||
100 | |||
101 | /* |
||
102 | * Section Header Block. |
||
103 | */ |
||
104 | #define BT_SHB 0x0A0D0D0A |
||
105 | |||
106 | struct section_header_block { |
||
107 | bpf_u_int32 byte_order_magic; |
||
108 | u_short major_version; |
||
109 | u_short minor_version; |
||
110 | u_int64_t section_length; |
||
111 | /* followed by options and trailer */ |
||
112 | }; |
||
113 | |||
114 | /* |
||
115 | * Byte-order magic value. |
||
116 | */ |
||
117 | #define BYTE_ORDER_MAGIC 0x1A2B3C4D |
||
118 | |||
119 | /* |
||
120 | * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR, |
||
121 | * that means that this code can't read the file. |
||
122 | */ |
||
123 | #define PCAP_NG_VERSION_MAJOR 1 |
||
124 | |||
125 | /* |
||
126 | * Interface Description Block. |
||
127 | */ |
||
128 | #define BT_IDB 0x00000001 |
||
129 | |||
130 | struct interface_description_block { |
||
131 | u_short linktype; |
||
132 | u_short reserved; |
||
133 | bpf_u_int32 snaplen; |
||
134 | /* followed by options and trailer */ |
||
135 | }; |
||
136 | |||
137 | /* |
||
138 | * Options in the IDB. |
||
139 | */ |
||
140 | #define IF_NAME 2 /* interface name string */ |
||
141 | #define IF_DESCRIPTION 3 /* interface description string */ |
||
142 | #define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */ |
||
143 | #define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */ |
||
144 | #define IF_MACADDR 6 /* interface's MAC address */ |
||
145 | #define IF_EUIADDR 7 /* interface's EUI address */ |
||
146 | #define IF_SPEED 8 /* interface's speed, in bits/s */ |
||
147 | #define IF_TSRESOL 9 /* interface's time stamp resolution */ |
||
148 | #define IF_TZONE 10 /* interface's time zone */ |
||
149 | #define IF_FILTER 11 /* filter used when capturing on interface */ |
||
150 | #define IF_OS 12 /* string OS on which capture on this interface was done */ |
||
151 | #define IF_FCSLEN 13 /* FCS length for this interface */ |
||
152 | #define IF_TSOFFSET 14 /* time stamp offset for this interface */ |
||
153 | |||
154 | /* |
||
155 | * Enhanced Packet Block. |
||
156 | */ |
||
157 | #define BT_EPB 0x00000006 |
||
158 | |||
159 | struct enhanced_packet_block { |
||
160 | bpf_u_int32 interface_id; |
||
161 | bpf_u_int32 timestamp_high; |
||
162 | bpf_u_int32 timestamp_low; |
||
163 | bpf_u_int32 caplen; |
||
164 | bpf_u_int32 len; |
||
165 | /* followed by packet data, options, and trailer */ |
||
166 | }; |
||
167 | |||
168 | /* |
||
169 | * Simple Packet Block. |
||
170 | */ |
||
171 | #define BT_SPB 0x00000003 |
||
172 | |||
173 | struct simple_packet_block { |
||
174 | bpf_u_int32 len; |
||
175 | /* followed by packet data and trailer */ |
||
176 | }; |
||
177 | |||
178 | /* |
||
179 | * Packet Block. |
||
180 | */ |
||
181 | #define BT_PB 0x00000002 |
||
182 | |||
183 | struct packet_block { |
||
184 | u_short interface_id; |
||
185 | u_short drops_count; |
||
186 | bpf_u_int32 timestamp_high; |
||
187 | bpf_u_int32 timestamp_low; |
||
188 | bpf_u_int32 caplen; |
||
189 | bpf_u_int32 len; |
||
190 | /* followed by packet data, options, and trailer */ |
||
191 | }; |
||
192 | |||
193 | /* |
||
194 | * Block cursor - used when processing the contents of a block. |
||
195 | * Contains a pointer into the data being processed and a count |
||
196 | * of bytes remaining in the block. |
||
197 | */ |
||
198 | struct block_cursor { |
||
199 | u_char *data; |
||
200 | size_t data_remaining; |
||
201 | bpf_u_int32 block_type; |
||
202 | }; |
||
203 | |||
204 | typedef enum { |
||
205 | PASS_THROUGH, |
||
206 | SCALE_UP, |
||
207 | SCALE_DOWN |
||
208 | } tstamp_scale_type_t; |
||
209 | |||
210 | /* |
||
211 | * Per-interface information. |
||
212 | */ |
||
213 | struct pcap_ng_if { |
||
214 | u_int tsresol; /* time stamp resolution */ |
||
215 | u_int64_t tsoffset; /* time stamp offset */ |
||
216 | tstamp_scale_type_t scale_type; /* how to scale */ |
||
217 | }; |
||
218 | |||
219 | struct pcap_ng_sf { |
||
220 | u_int user_tsresol; /* time stamp resolution requested by the user */ |
||
221 | bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ |
||
222 | bpf_u_int32 ifaces_size; /* size of arrary below */ |
||
223 | struct pcap_ng_if *ifaces; /* array of interface information */ |
||
224 | }; |
||
225 | |||
226 | static void pcap_ng_cleanup(pcap_t *p); |
||
227 | static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, |
||
228 | u_char **data); |
||
229 | |||
230 | static int |
||
231 | read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, |
||
232 | char *errbuf) |
||
233 | { |
||
234 | size_t amt_read; |
||
235 | |||
236 | amt_read = fread(buf, 1, bytes_to_read, fp); |
||
237 | if (amt_read != bytes_to_read) { |
||
238 | if (ferror(fp)) { |
||
239 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
240 | "error reading dump file: %s", |
||
241 | pcap_strerror(errno)); |
||
242 | } else { |
||
243 | if (amt_read == 0 && !fail_on_eof) |
||
244 | return (0); /* EOF */ |
||
245 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
246 | "truncated dump file; tried to read %lu bytes, only got %lu", |
||
247 | (unsigned long)bytes_to_read, |
||
248 | (unsigned long)amt_read); |
||
249 | } |
||
250 | return (-1); |
||
251 | } |
||
252 | return (1); |
||
253 | } |
||
254 | |||
255 | static int |
||
256 | read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) |
||
257 | { |
||
258 | int status; |
||
259 | struct block_header bhdr; |
||
260 | |||
261 | status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf); |
||
262 | if (status <= 0) |
||
263 | return (status); /* error or EOF */ |
||
264 | |||
265 | if (p->swapped) { |
||
266 | bhdr.block_type = SWAPLONG(bhdr.block_type); |
||
267 | bhdr.total_length = SWAPLONG(bhdr.total_length); |
||
268 | } |
||
269 | |||
270 | /* |
||
271 | * Is this block "too big"? |
||
272 | * |
||
273 | * We choose 16MB as "too big", for now, so that we handle |
||
274 | * "reasonably" large buffers but don't chew up all the |
||
275 | * memory if we read a malformed file. |
||
276 | */ |
||
277 | if (bhdr.total_length > 16*1024*1024) { |
||
278 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
279 | "pcap-ng block size %u > maximum %u", |
||
280 | bhdr.total_length, 16*1024*1024); |
||
281 | return (-1); |
||
282 | } |
||
283 | |||
284 | /* |
||
285 | * Is this block "too small" - i.e., is it shorter than a block |
||
286 | * header plus a block trailer? |
||
287 | */ |
||
288 | if (bhdr.total_length < sizeof(struct block_header) + |
||
289 | sizeof(struct block_trailer)) { |
||
290 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
291 | "block in pcap-ng dump file has a length of %u < %lu", |
||
292 | bhdr.total_length, |
||
293 | (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); |
||
294 | return (-1); |
||
295 | } |
||
296 | |||
297 | /* |
||
298 | * Is the buffer big enough? |
||
299 | */ |
||
300 | if (p->bufsize < bhdr.total_length) { |
||
301 | /* |
||
302 | * No - make it big enough. |
||
303 | */ |
||
304 | p->buffer = realloc(p->buffer, bhdr.total_length); |
||
305 | if (p->buffer == NULL) { |
||
306 | snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); |
||
307 | return (-1); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | /* |
||
312 | * Copy the stuff we've read to the buffer, and read the rest |
||
313 | * of the block. |
||
314 | */ |
||
315 | memcpy(p->buffer, &bhdr, sizeof(bhdr)); |
||
316 | if (read_bytes(fp, p->buffer + sizeof(bhdr), |
||
317 | bhdr.total_length - sizeof(bhdr), 1, errbuf) == -1) |
||
318 | return (-1); |
||
319 | |||
320 | /* |
||
321 | * Initialize the cursor. |
||
322 | */ |
||
323 | cursor->data = p->buffer + sizeof(bhdr); |
||
324 | cursor->data_remaining = bhdr.total_length - sizeof(bhdr) - |
||
325 | sizeof(struct block_trailer); |
||
326 | cursor->block_type = bhdr.block_type; |
||
327 | return (1); |
||
328 | } |
||
329 | |||
330 | static void * |
||
331 | get_from_block_data(struct block_cursor *cursor, size_t chunk_size, |
||
332 | char *errbuf) |
||
333 | { |
||
334 | void *data; |
||
335 | |||
336 | /* |
||
337 | * Make sure we have the specified amount of data remaining in |
||
338 | * the block data. |
||
339 | */ |
||
340 | if (cursor->data_remaining < chunk_size) { |
||
341 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
342 | "block of type %u in pcap-ng dump file is too short", |
||
343 | cursor->block_type); |
||
344 | return (NULL); |
||
345 | } |
||
346 | |||
347 | /* |
||
348 | * Return the current pointer, and skip past the chunk. |
||
349 | */ |
||
350 | data = cursor->data; |
||
351 | cursor->data += chunk_size; |
||
352 | cursor->data_remaining -= chunk_size; |
||
353 | return (data); |
||
354 | } |
||
355 | |||
356 | static struct option_header * |
||
357 | get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) |
||
358 | { |
||
359 | struct option_header *opthdr; |
||
360 | |||
361 | opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf); |
||
362 | if (opthdr == NULL) { |
||
363 | /* |
||
364 | * Option header is cut short. |
||
365 | */ |
||
366 | return (NULL); |
||
367 | } |
||
368 | |||
369 | /* |
||
370 | * Byte-swap it if necessary. |
||
371 | */ |
||
372 | if (p->swapped) { |
||
373 | opthdr->option_code = SWAPSHORT(opthdr->option_code); |
||
374 | opthdr->option_length = SWAPSHORT(opthdr->option_length); |
||
375 | } |
||
376 | |||
377 | return (opthdr); |
||
378 | } |
||
379 | |||
380 | static void * |
||
381 | get_optvalue_from_block_data(struct block_cursor *cursor, |
||
382 | struct option_header *opthdr, char *errbuf) |
||
383 | { |
||
384 | size_t padded_option_len; |
||
385 | void *optvalue; |
||
386 | |||
387 | /* Pad option length to 4-byte boundary */ |
||
388 | padded_option_len = opthdr->option_length; |
||
389 | padded_option_len = ((padded_option_len + 3)/4)*4; |
||
390 | |||
391 | optvalue = get_from_block_data(cursor, padded_option_len, errbuf); |
||
392 | if (optvalue == NULL) { |
||
393 | /* |
||
394 | * Option value is cut short. |
||
395 | */ |
||
396 | return (NULL); |
||
397 | } |
||
398 | |||
399 | return (optvalue); |
||
400 | } |
||
401 | |||
402 | static int |
||
403 | process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, |
||
404 | u_int64_t *tsoffset, char *errbuf) |
||
405 | { |
||
406 | struct option_header *opthdr; |
||
407 | void *optvalue; |
||
408 | int saw_tsresol, saw_tsoffset; |
||
409 | u_char tsresol_opt; |
||
410 | u_int i; |
||
411 | |||
412 | saw_tsresol = 0; |
||
413 | saw_tsoffset = 0; |
||
414 | while (cursor->data_remaining != 0) { |
||
415 | /* |
||
416 | * Get the option header. |
||
417 | */ |
||
418 | opthdr = get_opthdr_from_block_data(p, cursor, errbuf); |
||
419 | if (opthdr == NULL) { |
||
420 | /* |
||
421 | * Option header is cut short. |
||
422 | */ |
||
423 | return (-1); |
||
424 | } |
||
425 | |||
426 | /* |
||
427 | * Get option value. |
||
428 | */ |
||
429 | optvalue = get_optvalue_from_block_data(cursor, opthdr, |
||
430 | errbuf); |
||
431 | if (optvalue == NULL) { |
||
432 | /* |
||
433 | * Option value is cut short. |
||
434 | */ |
||
435 | return (-1); |
||
436 | } |
||
437 | |||
438 | switch (opthdr->option_code) { |
||
439 | |||
440 | case OPT_ENDOFOPT: |
||
441 | if (opthdr->option_length != 0) { |
||
442 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
443 | "Interface Description Block has opt_endofopt option with length %u != 0", |
||
444 | opthdr->option_length); |
||
445 | return (-1); |
||
446 | } |
||
447 | goto done; |
||
448 | |||
449 | case IF_TSRESOL: |
||
450 | if (opthdr->option_length != 1) { |
||
451 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
452 | "Interface Description Block has if_tsresol option with length %u != 1", |
||
453 | opthdr->option_length); |
||
454 | return (-1); |
||
455 | } |
||
456 | if (saw_tsresol) { |
||
457 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
458 | "Interface Description Block has more than one if_tsresol option"); |
||
459 | return (-1); |
||
460 | } |
||
461 | saw_tsresol = 1; |
||
462 | memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); |
||
463 | if (tsresol_opt & 0x80) { |
||
464 | /* |
||
465 | * Resolution is negative power of 2. |
||
466 | */ |
||
467 | *tsresol = 1 << (tsresol_opt & 0x7F); |
||
468 | } else { |
||
469 | /* |
||
470 | * Resolution is negative power of 10. |
||
471 | */ |
||
472 | *tsresol = 1; |
||
473 | for (i = 0; i < tsresol_opt; i++) |
||
474 | *tsresol *= 10; |
||
475 | } |
||
476 | if (*tsresol == 0) { |
||
477 | /* |
||
478 | * Resolution is too high. |
||
479 | */ |
||
480 | if (tsresol_opt & 0x80) { |
||
481 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
482 | "Interface Description Block if_tsresol option resolution 2^-%u is too high", |
||
483 | tsresol_opt & 0x7F); |
||
484 | } else { |
||
485 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
486 | "Interface Description Block if_tsresol option resolution 10^-%u is too high", |
||
487 | tsresol_opt); |
||
488 | } |
||
489 | return (-1); |
||
490 | } |
||
491 | break; |
||
492 | |||
493 | case IF_TSOFFSET: |
||
494 | if (opthdr->option_length != 8) { |
||
495 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
496 | "Interface Description Block has if_tsoffset option with length %u != 8", |
||
497 | opthdr->option_length); |
||
498 | return (-1); |
||
499 | } |
||
500 | if (saw_tsoffset) { |
||
501 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
502 | "Interface Description Block has more than one if_tsoffset option"); |
||
503 | return (-1); |
||
504 | } |
||
505 | saw_tsoffset = 1; |
||
506 | memcpy(tsoffset, optvalue, sizeof(*tsoffset)); |
||
507 | if (p->swapped) |
||
508 | *tsoffset = SWAPLL(*tsoffset); |
||
509 | break; |
||
510 | |||
511 | default: |
||
512 | break; |
||
513 | } |
||
514 | } |
||
515 | |||
516 | done: |
||
517 | return (0); |
||
518 | } |
||
519 | |||
520 | static int |
||
521 | add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) |
||
522 | { |
||
523 | struct pcap_ng_sf *ps; |
||
524 | u_int tsresol; |
||
525 | u_int64_t tsoffset; |
||
526 | |||
527 | ps = p->priv; |
||
528 | |||
529 | /* |
||
530 | * Count this interface. |
||
531 | */ |
||
532 | ps->ifcount++; |
||
533 | |||
534 | /* |
||
535 | * Grow the array of per-interface information as necessary. |
||
536 | */ |
||
537 | if (ps->ifcount > ps->ifaces_size) { |
||
538 | /* |
||
539 | * We need to grow the array. |
||
540 | */ |
||
541 | if (ps->ifaces == NULL) { |
||
542 | /* |
||
543 | * It's currently empty. |
||
544 | */ |
||
545 | ps->ifaces_size = 1; |
||
546 | ps->ifaces = malloc(sizeof (struct pcap_ng_if)); |
||
547 | } else { |
||
548 | /* |
||
549 | * It's not currently empty; double its size. |
||
550 | * (Perhaps overkill once we have a lot of interfaces.) |
||
551 | */ |
||
552 | ps->ifaces_size *= 2; |
||
553 | ps->ifaces = realloc(ps->ifaces, ps->ifaces_size * sizeof (struct pcap_ng_if)); |
||
554 | } |
||
555 | if (ps->ifaces == NULL) { |
||
556 | /* |
||
557 | * We ran out of memory. |
||
558 | * Give up. |
||
559 | */ |
||
560 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
561 | "out of memory for per-interface information (%u interfaces)", |
||
562 | ps->ifcount); |
||
563 | return (0); |
||
564 | } |
||
565 | } |
||
566 | |||
567 | /* |
||
568 | * Set the default time stamp resolution and offset. |
||
569 | */ |
||
570 | tsresol = 1000000; /* microsecond resolution */ |
||
571 | tsoffset = 0; /* absolute timestamps */ |
||
572 | |||
573 | /* |
||
574 | * Now look for various time stamp options, so we know |
||
575 | * how to interpret the time stamps for this interface. |
||
576 | */ |
||
577 | if (process_idb_options(p, cursor, &tsresol, &tsoffset, errbuf) == -1) |
||
578 | return (0); |
||
579 | |||
580 | ps->ifaces[ps->ifcount - 1].tsresol = tsresol; |
||
581 | ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; |
||
582 | |||
583 | /* |
||
584 | * Determine whether we're scaling up or down or not |
||
585 | * at all for this interface. |
||
586 | */ |
||
587 | switch (p->opt.tstamp_precision) { |
||
588 | |||
589 | case PCAP_TSTAMP_PRECISION_MICRO: |
||
590 | if (tsresol == 1000000) { |
||
591 | /* |
||
592 | * The resolution is 1 microsecond, |
||
593 | * so we don't have to do scaling. |
||
594 | */ |
||
595 | ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; |
||
596 | } else if (tsresol > 1000000) { |
||
597 | /* |
||
598 | * The resolution is greater than |
||
599 | * 1 microsecond, so we have to |
||
600 | * scale the timestamps down. |
||
601 | */ |
||
602 | ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN; |
||
603 | } else { |
||
604 | /* |
||
605 | * The resolution is less than 1 |
||
606 | * microsecond, so we have to scale |
||
607 | * the timestamps up. |
||
608 | */ |
||
609 | ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; |
||
610 | } |
||
611 | break; |
||
612 | |||
613 | case PCAP_TSTAMP_PRECISION_NANO: |
||
614 | if (tsresol == 1000000000) { |
||
615 | /* |
||
616 | * The resolution is 1 nanosecond, |
||
617 | * so we don't have to do scaling. |
||
618 | */ |
||
619 | ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; |
||
620 | } else if (tsresol > 1000000000) { |
||
621 | /* |
||
622 | * The resolution is greater than |
||
623 | * 1 nanosecond, so we have to |
||
624 | * scale the timestamps down. |
||
625 | */ |
||
626 | ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN; |
||
627 | } else { |
||
628 | /* |
||
629 | * The resolution is less than 1 |
||
630 | * nanosecond, so we have to scale |
||
631 | * the timestamps up. |
||
632 | */ |
||
633 | ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; |
||
634 | } |
||
635 | break; |
||
636 | } |
||
637 | return (1); |
||
638 | } |
||
639 | |||
640 | /* |
||
641 | * Check whether this is a pcap-ng savefile and, if it is, extract the |
||
642 | * relevant information from the header. |
||
643 | */ |
||
644 | pcap_t * |
||
645 | pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, |
||
646 | int *err) |
||
647 | { |
||
648 | size_t amt_read; |
||
649 | bpf_u_int32 total_length; |
||
650 | bpf_u_int32 byte_order_magic; |
||
651 | struct block_header *bhdrp; |
||
652 | struct section_header_block *shbp; |
||
653 | pcap_t *p; |
||
654 | int swapped = 0; |
||
655 | struct pcap_ng_sf *ps; |
||
656 | int status; |
||
657 | struct block_cursor cursor; |
||
658 | struct interface_description_block *idbp; |
||
659 | |||
660 | /* |
||
661 | * Assume no read errors. |
||
662 | */ |
||
663 | *err = 0; |
||
664 | |||
665 | /* |
||
666 | * Check whether the first 4 bytes of the file are the block |
||
667 | * type for a pcap-ng savefile. |
||
668 | */ |
||
669 | if (magic != BT_SHB) { |
||
670 | /* |
||
671 | * XXX - check whether this looks like what the block |
||
672 | * type would be after being munged by mapping between |
||
673 | * UN*X and DOS/Windows text file format and, if it |
||
674 | * does, look for the byte-order magic number in |
||
675 | * the appropriate place and, if we find it, report |
||
676 | * this as possibly being a pcap-ng file transferred |
||
677 | * between UN*X and Windows in text file format? |
||
678 | */ |
||
679 | return (NULL); /* nope */ |
||
680 | } |
||
681 | |||
682 | /* |
||
683 | * OK, they are. However, that's just \n\r\r\n, so it could, |
||
684 | * conceivably, be an ordinary text file. |
||
685 | * |
||
686 | * It could not, however, conceivably be any other type of |
||
687 | * capture file, so we can read the rest of the putative |
||
688 | * Section Header Block; put the block type in the common |
||
689 | * header, read the rest of the common header and the |
||
690 | * fixed-length portion of the SHB, and look for the byte-order |
||
691 | * magic value. |
||
692 | */ |
||
693 | amt_read = fread(&total_length, 1, sizeof(total_length), fp); |
||
694 | if (amt_read < sizeof(total_length)) { |
||
695 | if (ferror(fp)) { |
||
696 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
697 | "error reading dump file: %s", |
||
698 | pcap_strerror(errno)); |
||
699 | *err = 1; |
||
700 | return (NULL); /* fail */ |
||
701 | } |
||
702 | |||
703 | /* |
||
704 | * Possibly a weird short text file, so just say |
||
705 | * "not pcap-ng". |
||
706 | */ |
||
707 | return (NULL); |
||
708 | } |
||
709 | amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp); |
||
710 | if (amt_read < sizeof(byte_order_magic)) { |
||
711 | if (ferror(fp)) { |
||
712 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
713 | "error reading dump file: %s", |
||
714 | pcap_strerror(errno)); |
||
715 | *err = 1; |
||
716 | return (NULL); /* fail */ |
||
717 | } |
||
718 | |||
719 | /* |
||
720 | * Possibly a weird short text file, so just say |
||
721 | * "not pcap-ng". |
||
722 | */ |
||
723 | return (NULL); |
||
724 | } |
||
725 | if (byte_order_magic != BYTE_ORDER_MAGIC) { |
||
726 | byte_order_magic = SWAPLONG(byte_order_magic); |
||
727 | if (byte_order_magic != BYTE_ORDER_MAGIC) { |
||
728 | /* |
||
729 | * Not a pcap-ng file. |
||
730 | */ |
||
731 | return (NULL); |
||
732 | } |
||
733 | swapped = 1; |
||
734 | total_length = SWAPLONG(total_length); |
||
735 | } |
||
736 | |||
737 | /* |
||
738 | * Check the sanity of the total length. |
||
739 | */ |
||
740 | if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { |
||
741 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
742 | "Section Header Block in pcap-ng dump file has a length of %u < %lu", |
||
743 | total_length, |
||
744 | (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); |
||
745 | *err = 1; |
||
746 | return (NULL); |
||
747 | } |
||
748 | |||
749 | /* |
||
750 | * OK, this is a good pcap-ng file. |
||
751 | * Allocate a pcap_t for it. |
||
752 | */ |
||
753 | p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf)); |
||
754 | if (p == NULL) { |
||
755 | /* Allocation failed. */ |
||
756 | *err = 1; |
||
757 | return (NULL); |
||
758 | } |
||
759 | p->swapped = swapped; |
||
760 | ps = p->priv; |
||
761 | |||
762 | /* |
||
763 | * What precision does the user want? |
||
764 | */ |
||
765 | switch (precision) { |
||
766 | |||
767 | case PCAP_TSTAMP_PRECISION_MICRO: |
||
768 | ps->user_tsresol = 1000000; |
||
769 | break; |
||
770 | |||
771 | case PCAP_TSTAMP_PRECISION_NANO: |
||
772 | ps->user_tsresol = 1000000000; |
||
773 | break; |
||
774 | |||
775 | default: |
||
776 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
777 | "unknown time stamp resolution %u", precision); |
||
778 | free(p); |
||
779 | *err = 1; |
||
780 | return (NULL); |
||
781 | } |
||
782 | |||
783 | p->opt.tstamp_precision = precision; |
||
784 | |||
785 | /* |
||
786 | * Allocate a buffer into which to read blocks. We default to |
||
787 | * the maximum of: |
||
788 | * |
||
789 | * the total length of the SHB for which we read the header; |
||
790 | * |
||
791 | * 2K, which should be more than large enough for an Enhanced |
||
792 | * Packet Block containing a full-size Ethernet frame, and |
||
793 | * leaving room for some options. |
||
794 | * |
||
795 | * If we find a bigger block, we reallocate the buffer. |
||
796 | */ |
||
797 | p->bufsize = 2048; |
||
798 | if (p->bufsize < total_length) |
||
799 | p->bufsize = total_length; |
||
800 | p->buffer = malloc(p->bufsize); |
||
801 | if (p->buffer == NULL) { |
||
802 | snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); |
||
803 | free(p); |
||
804 | *err = 1; |
||
805 | return (NULL); |
||
806 | } |
||
807 | |||
808 | /* |
||
809 | * Copy the stuff we've read to the buffer, and read the rest |
||
810 | * of the SHB. |
||
811 | */ |
||
812 | bhdrp = (struct block_header *)p->buffer; |
||
813 | shbp = (struct section_header_block *)(p->buffer + sizeof(struct block_header)); |
||
814 | bhdrp->block_type = magic; |
||
815 | bhdrp->total_length = total_length; |
||
816 | shbp->byte_order_magic = byte_order_magic; |
||
817 | if (read_bytes(fp, |
||
818 | p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), |
||
819 | total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), |
||
820 | 1, errbuf) == -1) |
||
821 | goto fail; |
||
822 | |||
823 | if (p->swapped) { |
||
824 | /* |
||
825 | * Byte-swap the fields we've read. |
||
826 | */ |
||
827 | shbp->major_version = SWAPSHORT(shbp->major_version); |
||
828 | shbp->minor_version = SWAPSHORT(shbp->minor_version); |
||
829 | |||
830 | /* |
||
831 | * XXX - we don't care about the section length. |
||
832 | */ |
||
833 | } |
||
834 | if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { |
||
835 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
836 | "unknown pcap-ng savefile major version number %u", |
||
837 | shbp->major_version); |
||
838 | goto fail; |
||
839 | } |
||
840 | p->version_major = shbp->major_version; |
||
841 | p->version_minor = shbp->minor_version; |
||
842 | |||
843 | /* |
||
844 | * Save the time stamp resolution the user requested. |
||
845 | */ |
||
846 | p->opt.tstamp_precision = precision; |
||
847 | |||
848 | /* |
||
849 | * Now start looking for an Interface Description Block. |
||
850 | */ |
||
851 | for (;;) { |
||
852 | /* |
||
853 | * Read the next block. |
||
854 | */ |
||
855 | status = read_block(fp, p, &cursor, errbuf); |
||
856 | if (status == 0) { |
||
857 | /* EOF - no IDB in this file */ |
||
858 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
859 | "the capture file has no Interface Description Blocks"); |
||
860 | goto fail; |
||
861 | } |
||
862 | if (status == -1) |
||
863 | goto fail; /* error */ |
||
864 | switch (cursor.block_type) { |
||
865 | |||
866 | case BT_IDB: |
||
867 | /* |
||
868 | * Get a pointer to the fixed-length portion of the |
||
869 | * IDB. |
||
870 | */ |
||
871 | idbp = get_from_block_data(&cursor, sizeof(*idbp), |
||
872 | errbuf); |
||
873 | if (idbp == NULL) |
||
874 | goto fail; /* error */ |
||
875 | |||
876 | /* |
||
877 | * Byte-swap it if necessary. |
||
878 | */ |
||
879 | if (p->swapped) { |
||
880 | idbp->linktype = SWAPSHORT(idbp->linktype); |
||
881 | idbp->snaplen = SWAPLONG(idbp->snaplen); |
||
882 | } |
||
883 | |||
884 | /* |
||
885 | * Try to add this interface. |
||
886 | */ |
||
887 | if (!add_interface(p, &cursor, errbuf)) |
||
888 | goto fail; |
||
889 | goto done; |
||
890 | |||
891 | case BT_EPB: |
||
892 | case BT_SPB: |
||
893 | case BT_PB: |
||
894 | /* |
||
895 | * Saw a packet before we saw any IDBs. That's |
||
896 | * not valid, as we don't know what link-layer |
||
897 | * encapsulation the packet has. |
||
898 | */ |
||
899 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
900 | "the capture file has a packet block before any Interface Description Blocks"); |
||
901 | goto fail; |
||
902 | |||
903 | default: |
||
904 | /* |
||
905 | * Just ignore it. |
||
906 | */ |
||
907 | break; |
||
908 | } |
||
909 | } |
||
910 | |||
911 | done: |
||
912 | p->tzoff = 0; /* XXX - not used in pcap */ |
||
913 | p->snapshot = idbp->snaplen; |
||
914 | p->linktype = linktype_to_dlt(idbp->linktype); |
||
915 | p->linktype_ext = 0; |
||
916 | |||
917 | p->next_packet_op = pcap_ng_next_packet; |
||
918 | p->cleanup_op = pcap_ng_cleanup; |
||
919 | |||
920 | return (p); |
||
921 | |||
922 | fail: |
||
923 | free(ps->ifaces); |
||
924 | free(p->buffer); |
||
925 | free(p); |
||
926 | *err = 1; |
||
927 | return (NULL); |
||
928 | } |
||
929 | |||
930 | static void |
||
931 | pcap_ng_cleanup(pcap_t *p) |
||
932 | { |
||
933 | struct pcap_ng_sf *ps = p->priv; |
||
934 | |||
935 | free(ps->ifaces); |
||
936 | sf_cleanup(p); |
||
937 | } |
||
938 | |||
939 | /* |
||
940 | * Read and return the next packet from the savefile. Return the header |
||
941 | * in hdr and a pointer to the contents in data. Return 0 on success, 1 |
||
942 | * if there were no more packets, and -1 on an error. |
||
943 | */ |
||
944 | static int |
||
945 | pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) |
||
946 | { |
||
947 | struct pcap_ng_sf *ps = p->priv; |
||
948 | struct block_cursor cursor; |
||
949 | int status; |
||
950 | struct enhanced_packet_block *epbp; |
||
951 | struct simple_packet_block *spbp; |
||
952 | struct packet_block *pbp; |
||
953 | bpf_u_int32 interface_id = 0xFFFFFFFF; |
||
954 | struct interface_description_block *idbp; |
||
955 | struct section_header_block *shbp; |
||
956 | FILE *fp = p->rfile; |
||
957 | u_int64_t t, sec, frac; |
||
958 | |||
959 | /* |
||
960 | * Look for an Enhanced Packet Block, a Simple Packet Block, |
||
961 | * or a Packet Block. |
||
962 | */ |
||
963 | for (;;) { |
||
964 | /* |
||
965 | * Read the block type and length; those are common |
||
966 | * to all blocks. |
||
967 | */ |
||
968 | status = read_block(fp, p, &cursor, p->errbuf); |
||
969 | if (status == 0) |
||
970 | return (1); /* EOF */ |
||
971 | if (status == -1) |
||
972 | return (-1); /* error */ |
||
973 | switch (cursor.block_type) { |
||
974 | |||
975 | case BT_EPB: |
||
976 | /* |
||
977 | * Get a pointer to the fixed-length portion of the |
||
978 | * EPB. |
||
979 | */ |
||
980 | epbp = get_from_block_data(&cursor, sizeof(*epbp), |
||
981 | p->errbuf); |
||
982 | if (epbp == NULL) |
||
983 | return (-1); /* error */ |
||
984 | |||
985 | /* |
||
986 | * Byte-swap it if necessary. |
||
987 | */ |
||
988 | if (p->swapped) { |
||
989 | /* these were written in opposite byte order */ |
||
990 | interface_id = SWAPLONG(epbp->interface_id); |
||
991 | hdr->caplen = SWAPLONG(epbp->caplen); |
||
992 | hdr->len = SWAPLONG(epbp->len); |
||
993 | t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 | |
||
994 | SWAPLONG(epbp->timestamp_low); |
||
995 | } else { |
||
996 | interface_id = epbp->interface_id; |
||
997 | hdr->caplen = epbp->caplen; |
||
998 | hdr->len = epbp->len; |
||
999 | t = ((u_int64_t)epbp->timestamp_high) << 32 | |
||
1000 | epbp->timestamp_low; |
||
1001 | } |
||
1002 | goto found; |
||
1003 | |||
1004 | case BT_SPB: |
||
1005 | /* |
||
1006 | * Get a pointer to the fixed-length portion of the |
||
1007 | * SPB. |
||
1008 | */ |
||
1009 | spbp = get_from_block_data(&cursor, sizeof(*spbp), |
||
1010 | p->errbuf); |
||
1011 | if (spbp == NULL) |
||
1012 | return (-1); /* error */ |
||
1013 | |||
1014 | /* |
||
1015 | * SPB packets are assumed to have arrived on |
||
1016 | * the first interface. |
||
1017 | */ |
||
1018 | interface_id = 0; |
||
1019 | |||
1020 | /* |
||
1021 | * Byte-swap it if necessary. |
||
1022 | */ |
||
1023 | if (p->swapped) { |
||
1024 | /* these were written in opposite byte order */ |
||
1025 | hdr->len = SWAPLONG(spbp->len); |
||
1026 | } else |
||
1027 | hdr->len = spbp->len; |
||
1028 | |||
1029 | /* |
||
1030 | * The SPB doesn't give the captured length; |
||
1031 | * it's the minimum of the snapshot length |
||
1032 | * and the packet length. |
||
1033 | */ |
||
1034 | hdr->caplen = hdr->len; |
||
1035 | if (hdr->caplen > p->snapshot) |
||
1036 | hdr->caplen = p->snapshot; |
||
1037 | t = 0; /* no time stamps */ |
||
1038 | goto found; |
||
1039 | |||
1040 | case BT_PB: |
||
1041 | /* |
||
1042 | * Get a pointer to the fixed-length portion of the |
||
1043 | * PB. |
||
1044 | */ |
||
1045 | pbp = get_from_block_data(&cursor, sizeof(*pbp), |
||
1046 | p->errbuf); |
||
1047 | if (pbp == NULL) |
||
1048 | return (-1); /* error */ |
||
1049 | |||
1050 | /* |
||
1051 | * Byte-swap it if necessary. |
||
1052 | */ |
||
1053 | if (p->swapped) { |
||
1054 | /* these were written in opposite byte order */ |
||
1055 | interface_id = SWAPSHORT(pbp->interface_id); |
||
1056 | hdr->caplen = SWAPLONG(pbp->caplen); |
||
1057 | hdr->len = SWAPLONG(pbp->len); |
||
1058 | t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 | |
||
1059 | SWAPLONG(pbp->timestamp_low); |
||
1060 | } else { |
||
1061 | interface_id = pbp->interface_id; |
||
1062 | hdr->caplen = pbp->caplen; |
||
1063 | hdr->len = pbp->len; |
||
1064 | t = ((u_int64_t)pbp->timestamp_high) << 32 | |
||
1065 | pbp->timestamp_low; |
||
1066 | } |
||
1067 | goto found; |
||
1068 | |||
1069 | case BT_IDB: |
||
1070 | /* |
||
1071 | * Interface Description Block. Get a pointer |
||
1072 | * to its fixed-length portion. |
||
1073 | */ |
||
1074 | idbp = get_from_block_data(&cursor, sizeof(*idbp), |
||
1075 | p->errbuf); |
||
1076 | if (idbp == NULL) |
||
1077 | return (-1); /* error */ |
||
1078 | |||
1079 | /* |
||
1080 | * Byte-swap it if necessary. |
||
1081 | */ |
||
1082 | if (p->swapped) { |
||
1083 | idbp->linktype = SWAPSHORT(idbp->linktype); |
||
1084 | idbp->snaplen = SWAPLONG(idbp->snaplen); |
||
1085 | } |
||
1086 | |||
1087 | /* |
||
1088 | * If the link-layer type or snapshot length |
||
1089 | * differ from the ones for the first IDB we |
||
1090 | * saw, quit. |
||
1091 | * |
||
1092 | * XXX - just discard packets from those |
||
1093 | * interfaces? |
||
1094 | */ |
||
1095 | if (p->linktype != idbp->linktype) { |
||
1096 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1097 | "an interface has a type %u different from the type of the first interface", |
||
1098 | idbp->linktype); |
||
1099 | return (-1); |
||
1100 | } |
||
1101 | if (p->snapshot != idbp->snaplen) { |
||
1102 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1103 | "an interface has a snapshot length %u different from the type of the first interface", |
||
1104 | idbp->snaplen); |
||
1105 | return (-1); |
||
1106 | } |
||
1107 | |||
1108 | /* |
||
1109 | * Try to add this interface. |
||
1110 | */ |
||
1111 | if (!add_interface(p, &cursor, p->errbuf)) |
||
1112 | return (-1); |
||
1113 | break; |
||
1114 | |||
1115 | case BT_SHB: |
||
1116 | /* |
||
1117 | * Section Header Block. Get a pointer |
||
1118 | * to its fixed-length portion. |
||
1119 | */ |
||
1120 | shbp = get_from_block_data(&cursor, sizeof(*shbp), |
||
1121 | p->errbuf); |
||
1122 | if (shbp == NULL) |
||
1123 | return (-1); /* error */ |
||
1124 | |||
1125 | /* |
||
1126 | * Assume the byte order of this section is |
||
1127 | * the same as that of the previous section. |
||
1128 | * We'll check for that later. |
||
1129 | */ |
||
1130 | if (p->swapped) { |
||
1131 | shbp->byte_order_magic = |
||
1132 | SWAPLONG(shbp->byte_order_magic); |
||
1133 | shbp->major_version = |
||
1134 | SWAPSHORT(shbp->major_version); |
||
1135 | } |
||
1136 | |||
1137 | /* |
||
1138 | * Make sure the byte order doesn't change; |
||
1139 | * pcap_is_swapped() shouldn't change its |
||
1140 | * return value in the middle of reading a capture. |
||
1141 | */ |
||
1142 | switch (shbp->byte_order_magic) { |
||
1143 | |||
1144 | case BYTE_ORDER_MAGIC: |
||
1145 | /* |
||
1146 | * OK. |
||
1147 | */ |
||
1148 | break; |
||
1149 | |||
1150 | case SWAPLONG(BYTE_ORDER_MAGIC): |
||
1151 | /* |
||
1152 | * Byte order changes. |
||
1153 | */ |
||
1154 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1155 | "the file has sections with different byte orders"); |
||
1156 | return (-1); |
||
1157 | |||
1158 | default: |
||
1159 | /* |
||
1160 | * Not a valid SHB. |
||
1161 | */ |
||
1162 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1163 | "the file has a section with a bad byte order magic field"); |
||
1164 | return (-1); |
||
1165 | } |
||
1166 | |||
1167 | /* |
||
1168 | * Make sure the major version is the version |
||
1169 | * we handle. |
||
1170 | */ |
||
1171 | if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { |
||
1172 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1173 | "unknown pcap-ng savefile major version number %u", |
||
1174 | shbp->major_version); |
||
1175 | return (-1); |
||
1176 | } |
||
1177 | |||
1178 | /* |
||
1179 | * Reset the interface count; this section should |
||
1180 | * have its own set of IDBs. If any of them |
||
1181 | * don't have the same interface type, snapshot |
||
1182 | * length, or resolution as the first interface |
||
1183 | * we saw, we'll fail. (And if we don't see |
||
1184 | * any IDBs, we'll fail when we see a packet |
||
1185 | * block.) |
||
1186 | */ |
||
1187 | ps->ifcount = 0; |
||
1188 | break; |
||
1189 | |||
1190 | default: |
||
1191 | /* |
||
1192 | * Not a packet block, IDB, or SHB; ignore it. |
||
1193 | */ |
||
1194 | break; |
||
1195 | } |
||
1196 | } |
||
1197 | |||
1198 | found: |
||
1199 | /* |
||
1200 | * Is the interface ID an interface we know? |
||
1201 | */ |
||
1202 | if (interface_id >= ps->ifcount) { |
||
1203 | /* |
||
1204 | * Yes. Fail. |
||
1205 | */ |
||
1206 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
||
1207 | "a packet arrived on interface %u, but there's no Interface Description Block for that interface", |
||
1208 | interface_id); |
||
1209 | return (-1); |
||
1210 | } |
||
1211 | |||
1212 | /* |
||
1213 | * Convert the time stamp to seconds and fractions of a second, |
||
1214 | * with the fractions being in units of the file-supplied resolution. |
||
1215 | */ |
||
1216 | sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; |
||
1217 | frac = t % ps->ifaces[interface_id].tsresol; |
||
1218 | |||
1219 | /* |
||
1220 | * Convert the fractions from units of the file-supplied resolution |
||
1221 | * to units of the user-requested resolution. |
||
1222 | */ |
||
1223 | switch (ps->ifaces[interface_id].scale_type) { |
||
1224 | |||
1225 | case PASS_THROUGH: |
||
1226 | /* |
||
1227 | * The interface resolution is what the user wants, |
||
1228 | * so we're done. |
||
1229 | */ |
||
1230 | break; |
||
1231 | |||
1232 | case SCALE_UP: |
||
1233 | case SCALE_DOWN: |
||
1234 | /* |
||
1235 | * The interface resolution is different from what the |
||
1236 | * user wants; convert the fractions to units of the |
||
1237 | * resolution the user requested by multiplying by the |
||
1238 | * quotient of the user-requested resolution and the |
||
1239 | * file-supplied resolution. We do that by multiplying |
||
1240 | * by the user-requested resolution and dividing by the |
||
1241 | * file-supplied resolution, as the quotient might not |
||
1242 | * fit in an integer. |
||
1243 | * |
||
1244 | * XXX - if ps->ifaces[interface_id].tsresol is a power |
||
1245 | * of 10, we could just multiply by the quotient of |
||
1246 | * ps->user_tsresol and ps->ifaces[interface_id].tsresol |
||
1247 | * in the scale-up case, and divide by the quotient of |
||
1248 | * ps->ifaces[interface_id].tsresol and ps->user_tsresol |
||
1249 | * in the scale-down case, as we know those will be integers. |
||
1250 | * That would involve fewer arithmetic operations, and |
||
1251 | * would run less risk of overflow. |
||
1252 | * |
||
1253 | * Is there something clever we could do if |
||
1254 | * ps->ifaces[interface_id].tsresol is a power of 2? |
||
1255 | */ |
||
1256 | frac *= ps->user_tsresol; |
||
1257 | frac /= ps->ifaces[interface_id].tsresol; |
||
1258 | break; |
||
1259 | } |
||
1260 | hdr->ts.tv_sec = sec; |
||
1261 | hdr->ts.tv_usec = frac; |
||
1262 | |||
1263 | /* |
||
1264 | * Get a pointer to the packet data. |
||
1265 | */ |
||
1266 | *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf); |
||
1267 | if (*data == NULL) |
||
1268 | return (-1); |
||
1269 | |||
1270 | if (p->swapped) |
||
1271 | swap_pseudo_headers(p->linktype, hdr, *data); |
||
1272 | |||
1273 | return (0); |
||
1274 | } |