2 * Our own private code for writing libpcap files when capturing.
4 * We have these because we want a way to open a stream for output given
5 * only a file descriptor. libpcap 0.9[.x] has "pcap_dump_fopen()", which
8 * 1) earlier versions of libpcap doesn't have it
12 * 2) WinPcap/Npcap don't have it, because a file descriptor opened
13 * by code built for one version of the MSVC++ C library
14 * can't be used by library routines built for another version
15 * (e.g., threaded vs. unthreaded).
17 * Libpcap's pcap_dump() also doesn't return any error indications.
19 * Wireshark - Network traffic analyzer
20 * By Gerald Combs <gerald@wireshark.org>
21 * Copyright 1998 Gerald Combs
23 * Derived from code in the Wiretap Library
24 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
26 * SPDX-License-Identifier: GPL-2.0-or-later
37 #ifdef HAVE_SYS_TIME_H
46 #include <wsutil/epochs.h>
50 /* Magic numbers in "libpcap" files.
52 "libpcap" file records are written in the byte order of the host that
53 writes them, and the reader is expected to fix this up.
55 PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
56 is a byte-swapped version of that.
58 PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format,
59 which uses the same common file format as PCAP_MAGIC, but the
60 timestamps are saved in nanosecond resolution instead of microseconds.
61 PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */
62 #define PCAP_MAGIC 0xa1b2c3d4
63 #define PCAP_SWAPPED_MAGIC 0xd4c3b2a1
64 #define PCAP_NSEC_MAGIC 0xa1b23c4d
65 #define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1
67 /* "libpcap" file header. */
69 uint32_t magic
; /* magic number */
70 uint16_t version_major
; /* major version number */
71 uint16_t version_minor
; /* minor version number */
72 int32_t thiszone
; /* GMT to local correction */
73 uint32_t sigfigs
; /* accuracy of timestamps */
74 uint32_t snaplen
; /* max length of captured packets, in octets */
75 uint32_t network
; /* data link type */
78 /* "libpcap" record header. */
80 uint32_t ts_sec
; /* timestamp seconds */
81 uint32_t ts_usec
; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
82 uint32_t incl_len
; /* number of octets of packet saved in file */
83 uint32_t orig_len
; /* actual length of packet */
86 /* Magic numbers in ".pcapng" files.
88 * .pcapng file records are written in the byte order of the host that
89 * writes them, and the reader is expected to fix this up.
90 * PCAPNG_MAGIC is the magic number, in host byte order;
91 * PCAPNG_SWAPPED_MAGIC is a byte-swapped version of that.
93 #define PCAPNG_MAGIC 0x1A2B3C4D
94 #define PCAPNG_SWAPPED_MAGIC 0x4D3C2B1A
96 /* Currently we are only supporting the initial version of
98 #define PCAPNG_MAJOR_VERSION 1
99 #define PCAPNG_MINOR_VERSION 0
101 /* Section Header Block without options and trailing Block Total Length */
104 uint32_t block_total_length
;
105 uint32_t byte_order_magic
;
106 uint16_t major_version
;
107 uint16_t minor_version
;
108 uint64_t section_length
;
110 #define SECTION_HEADER_BLOCK_TYPE 0x0A0D0D0A
112 /* Interface Description Block without options and trailing Block Total Length */
115 uint32_t block_total_length
;
120 #define INTERFACE_DESCRIPTION_BLOCK_TYPE 0x00000001
122 /* Interface Statistics Block without actual packet, options, and trailing
123 Block Total Length */
126 uint32_t block_total_length
;
127 uint32_t interface_id
;
128 uint32_t timestamp_high
;
129 uint32_t timestamp_low
;
131 #define INTERFACE_STATISTICS_BLOCK_TYPE 0x00000005
133 /* Enhanced Packet Block without actual packet, options, and trailing
134 Block Total Length */
137 uint32_t block_total_length
;
138 uint32_t interface_id
;
139 uint32_t timestamp_high
;
140 uint32_t timestamp_low
;
141 uint32_t captured_len
;
144 #define ENHANCED_PACKET_BLOCK_TYPE 0x00000006
148 uint16_t value_length
;
150 #define OPT_ENDOFOPT 0
151 #define OPT_COMMENT 1
153 #define SHB_HARDWARE 2 /* currently not used */
155 #define SHB_USERAPPL 4
157 #define IDB_DESCRIPTION 3
158 #define IDB_IF_SPEED 8
159 #define IDB_TSRESOL 9
160 #define IDB_FILTER 11
162 #define IDB_HARDWARE 15
163 #define ISB_STARTTIME 2
164 #define ISB_ENDTIME 3
167 #define ISB_FILTERACCEPT 6
169 #define ISB_USRDELIV 8
170 #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
172 /* Write to capture file */
174 write_to_file(FILE* pfile
, const uint8_t* data
, size_t data_length
,
175 uint64_t *bytes_written
, int *err
)
179 nwritten
= fwrite(data
, data_length
, 1, pfile
);
189 (*bytes_written
) += data_length
;
193 /* Writing pcap files */
195 /* Write the file header to a dump file.
196 Returns true on success, false on failure.
197 Sets "*err" to an error code, or 0 for a short write, on failure*/
199 libpcap_write_file_header(FILE* pfile
, int linktype
, int snaplen
, bool ts_nsecs
, uint64_t *bytes_written
, int *err
)
201 struct pcap_hdr file_hdr
;
203 file_hdr
.magic
= ts_nsecs
? PCAP_NSEC_MAGIC
: PCAP_MAGIC
;
204 /* current "libpcap" format is 2.4 */
205 file_hdr
.version_major
= 2;
206 file_hdr
.version_minor
= 4;
207 file_hdr
.thiszone
= 0; /* XXX - current offset? */
208 file_hdr
.sigfigs
= 0; /* unknown, but also apparently unused */
209 file_hdr
.snaplen
= snaplen
;
210 file_hdr
.network
= linktype
;
212 return write_to_file(pfile
, (const uint8_t*)&file_hdr
, sizeof(file_hdr
), bytes_written
, err
);
215 /* Write a record for a packet to a dump file.
216 Returns true on success, false on failure. */
218 libpcap_write_packet(FILE* pfile
,
219 time_t sec
, uint32_t usec
,
220 uint32_t caplen
, uint32_t len
,
222 uint64_t *bytes_written
, int *err
)
224 struct pcaprec_hdr rec_hdr
;
226 rec_hdr
.ts_sec
= (uint32_t)sec
; /* Y2.038K issue in pcap format.... */
227 rec_hdr
.ts_usec
= usec
;
228 rec_hdr
.incl_len
= caplen
;
229 rec_hdr
.orig_len
= len
;
230 if (!write_to_file(pfile
, (const uint8_t*)&rec_hdr
, sizeof(rec_hdr
), bytes_written
, err
))
233 return write_to_file(pfile
, pd
, caplen
, bytes_written
, err
);
236 /* Writing pcapng files */
239 pcapng_count_string_option(const char *option_value
)
241 if ((option_value
!= NULL
) && (strlen(option_value
) > 0) && (strlen(option_value
) < UINT16_MAX
)) {
242 /* There's a value to write; get its length */
243 return (uint32_t)(sizeof(struct ws_option
) +
244 (uint16_t)ADD_PADDING(strlen(option_value
)));
246 return 0; /* nothing to write */
250 pcapng_write_string_option(FILE* pfile
,
251 uint16_t option_type
, const char *option_value
,
252 uint64_t *bytes_written
, int *err
)
254 size_t option_value_length
;
255 struct ws_option option
;
256 const uint32_t padding
= 0;
258 if (option_value
== NULL
)
259 return true; /* nothing to write */
260 option_value_length
= strlen(option_value
);
261 if ((option_value_length
> 0) && (option_value_length
< UINT16_MAX
)) {
262 /* something to write */
263 option
.type
= option_type
;
264 option
.value_length
= (uint16_t)option_value_length
;
266 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
269 if (!write_to_file(pfile
, (const uint8_t*)option_value
, (int) option_value_length
, bytes_written
, err
))
272 if (option_value_length
% 4) {
273 if (!write_to_file(pfile
, (const uint8_t*)&padding
, 4 - option_value_length
% 4, bytes_written
, err
))
280 /* Write a pre-formatted pcapng block directly to the output file */
282 pcapng_write_block(FILE* pfile
,
285 uint64_t *bytes_written
,
288 uint32_t block_length
, end_length
;
290 * - length and data are aligned to 4 bytes
291 * - block_total_length field is the same at the start and end of the block
293 * The block_total_length is not checked against the provided length but
294 * getting the trailing block_total_length from the length argument gives
295 * us an implicit check of correctness without needing to do an endian swap
297 if (((length
& 3) != 0) || (((intptr_t)data
& 3) != 0)) {
301 block_length
= *(const uint32_t *) (data
+sizeof(uint32_t));
302 end_length
= *(const uint32_t *) (data
+length
-sizeof(uint32_t));
303 if (block_length
!= end_length
) {
307 return write_to_file(pfile
, data
, length
, bytes_written
, err
);
311 pcapng_write_section_header_block(FILE* pfile
,
316 uint64_t section_length
,
317 uint64_t *bytes_written
,
321 struct ws_option option
;
322 uint32_t block_total_length
;
323 uint32_t options_length
;
325 /* Size of base header */
326 block_total_length
= sizeof(struct shb
) +
329 if (comments
!= NULL
) {
330 for (unsigned i
= 0; i
< comments
->len
; i
++) {
331 options_length
+= pcapng_count_string_option((char *)g_ptr_array_index(comments
, i
));
334 options_length
+= pcapng_count_string_option(hw
);
335 options_length
+= pcapng_count_string_option(os
);
336 options_length
+= pcapng_count_string_option(appname
);
337 /* If we have options add size of end-of-options */
338 if (options_length
!= 0) {
339 options_length
+= (uint32_t)sizeof(struct ws_option
);
341 block_total_length
+= options_length
;
343 /* write shb header */
344 shb
.block_type
= SECTION_HEADER_BLOCK_TYPE
;
345 shb
.block_total_length
= block_total_length
;
346 shb
.byte_order_magic
= PCAPNG_MAGIC
;
347 shb
.major_version
= PCAPNG_MAJOR_VERSION
;
348 shb
.minor_version
= PCAPNG_MINOR_VERSION
;
349 shb
.section_length
= section_length
;
351 if (!write_to_file(pfile
, (const uint8_t*)&shb
, sizeof(struct shb
), bytes_written
, err
))
354 if (comments
!= NULL
) {
355 for (unsigned i
= 0; i
< comments
->len
; i
++) {
356 if (!pcapng_write_string_option(pfile
, OPT_COMMENT
,
357 (char *)g_ptr_array_index(comments
, i
),
362 if (!pcapng_write_string_option(pfile
, SHB_HARDWARE
, hw
,
365 if (!pcapng_write_string_option(pfile
, SHB_OS
, os
,
368 if (!pcapng_write_string_option(pfile
, SHB_USERAPPL
, appname
,
371 if (options_length
!= 0) {
372 /* write end of options */
373 option
.type
= OPT_ENDOFOPT
;
374 option
.value_length
= 0;
375 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
379 /* write the trailing block total length */
380 return write_to_file(pfile
, (const uint8_t*)&block_total_length
, sizeof(uint32_t), bytes_written
, err
);
384 pcapng_write_interface_description_block(FILE* pfile
,
385 const char *comment
, /* OPT_COMMENT 1 */
386 const char *name
, /* IDB_NAME 2 */
387 const char *descr
, /* IDB_DESCRIPTION 3 */
388 const char *filter
, /* IDB_FILTER 11 */
389 const char *os
, /* IDB_OS 12 */
390 const char *hardware
, /* IDB_HARDWARE 15 */
393 uint64_t *bytes_written
,
394 uint64_t if_speed
, /* IDB_IF_SPEED 8 */
395 uint8_t tsresol
, /* IDB_TSRESOL 9 */
399 struct ws_option option
;
400 uint32_t block_total_length
;
401 uint32_t options_length
;
402 const uint32_t padding
= 0;
404 block_total_length
= (uint32_t)(sizeof(struct idb
) + sizeof(uint32_t));
406 /* 01 - OPT_COMMENT */
407 options_length
+= pcapng_count_string_option(comment
);
410 options_length
+= pcapng_count_string_option(name
);
412 /* 03 - IDB_DESCRIPTION */
413 options_length
+= pcapng_count_string_option(descr
);
415 /* 08 - IDB_IF_SPEED */
417 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
421 /* 09 - IDB_TSRESOL */
423 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
424 sizeof(struct ws_option
));
427 /* 11 - IDB_FILTER */
428 if ((filter
!= NULL
) && (strlen(filter
) > 0) && (strlen(filter
) < UINT16_MAX
- 1)) {
429 /* No, this isn't a string, it has an extra type byte */
430 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
431 (uint16_t)(ADD_PADDING(strlen(filter
)+ 1)));
435 options_length
+= pcapng_count_string_option(os
);
437 /* 15 - IDB_HARDWARE */
438 options_length
+= pcapng_count_string_option(hardware
);
440 /* If we have options add size of end-of-options */
441 if (options_length
!= 0) {
442 options_length
+= (uint32_t)sizeof(struct ws_option
);
444 block_total_length
+= options_length
;
446 /* write block header */
447 idb
.block_type
= INTERFACE_DESCRIPTION_BLOCK_TYPE
;
448 idb
.block_total_length
= block_total_length
;
449 idb
.link_type
= link_type
;
451 idb
.snap_len
= snap_len
;
452 if (!write_to_file(pfile
, (const uint8_t*)&idb
, sizeof(struct idb
), bytes_written
, err
))
455 /* 01 - OPT_COMMENT - write comment string if applicable */
456 if (!pcapng_write_string_option(pfile
, OPT_COMMENT
, comment
,
460 /* 02 - IDB_NAME - write interface name string if applicable */
461 if (!pcapng_write_string_option(pfile
, IDB_NAME
, name
,
465 /* 03 - IDB_DESCRIPTION */
466 /* write interface description string if applicable */
467 if (!pcapng_write_string_option(pfile
, IDB_DESCRIPTION
, descr
,
471 /* 08 - IDB_IF_SPEED */
473 option
.type
= IDB_IF_SPEED
;
474 option
.value_length
= sizeof(uint64_t);
476 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
479 if (!write_to_file(pfile
, (const uint8_t*)&if_speed
, sizeof(uint64_t), bytes_written
, err
))
483 /* 09 - IDB_TSRESOL */
485 option
.type
= IDB_TSRESOL
;
486 option
.value_length
= sizeof(uint8_t);
488 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
491 if (!write_to_file(pfile
, (const uint8_t*)&tsresol
, sizeof(uint8_t), bytes_written
, err
))
494 if (!write_to_file(pfile
, (const uint8_t*)&padding
, 3, bytes_written
, err
))
498 /* 11 - IDB_FILTER - write filter string if applicable
499 * We write out the libpcap filter expression, not the
500 * generated BPF code.
502 if ((filter
!= NULL
) && (strlen(filter
) > 0) && (strlen(filter
) < UINT16_MAX
- 1)) {
503 option
.type
= IDB_FILTER
;
504 option
.value_length
= (uint16_t)(strlen(filter
) + 1 );
505 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
508 /* The first byte of the Option Data keeps a code of the filter used, 0 = lipbpcap filter string */
509 if (!write_to_file(pfile
, (const uint8_t*)&padding
, 1, bytes_written
, err
))
511 if (!write_to_file(pfile
, (const uint8_t*)filter
, (int) strlen(filter
), bytes_written
, err
))
513 if ((strlen(filter
) + 1) % 4) {
514 if (!write_to_file(pfile
, (const uint8_t*)&padding
, 4 - (strlen(filter
) + 1) % 4, bytes_written
, err
))
519 /* 12 - IDB_OS - write os string if applicable */
520 if (!pcapng_write_string_option(pfile
, IDB_OS
, os
,
524 /* 15 - IDB_HARDWARE - write hardware string if applicable */
525 if (!pcapng_write_string_option(pfile
, IDB_HARDWARE
, hardware
,
529 if (options_length
!= 0) {
530 /* write end of options */
531 option
.type
= OPT_ENDOFOPT
;
532 option
.value_length
= 0;
533 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
537 /* write the trailing Block Total Length */
538 return write_to_file(pfile
, (const uint8_t*)&block_total_length
, sizeof(uint32_t), bytes_written
, err
);
541 /* Write a record for a packet to a dump file.
542 Returns true on success, false on failure. */
544 pcapng_write_enhanced_packet_block(FILE* pfile
,
546 time_t sec
, uint32_t usec
,
547 uint32_t caplen
, uint32_t len
,
548 uint32_t interface_id
,
552 uint64_t *bytes_written
,
556 struct ws_option option
;
557 uint32_t block_total_length
;
559 uint32_t options_length
;
560 const uint32_t padding
= 0;
565 block_total_length
= (uint32_t)(sizeof(struct epb
) +
566 ADD_PADDING(caplen
) +
569 options_length
+= pcapng_count_string_option(comment
);
571 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
574 /* If we have options add size of end-of-options */
575 if (options_length
!= 0) {
576 options_length
+= (uint32_t)sizeof(struct ws_option
);
578 block_total_length
+= options_length
;
579 timestamp
= (uint64_t)sec
* ts_mul
+ (uint64_t)usec
;
580 epb
.block_type
= ENHANCED_PACKET_BLOCK_TYPE
;
581 epb
.block_total_length
= block_total_length
;
582 epb
.interface_id
= interface_id
;
583 epb
.timestamp_high
= (uint32_t)((timestamp
>>32) & 0xffffffff);
584 epb
.timestamp_low
= (uint32_t)(timestamp
& 0xffffffff);
585 epb
.captured_len
= caplen
;
586 epb
.packet_len
= len
;
587 if (!write_to_file(pfile
, (const uint8_t*)&epb
, sizeof(struct epb
), bytes_written
, err
))
589 if (!write_to_file(pfile
, pd
, caplen
, bytes_written
, err
))
591 /* Use more efficient write in case of no "extras" */
593 pad_len
= 4 - (caplen
% 4);
596 * If we have no options to write, just write out the padding and
597 * the block total length with one fwrite() call.
599 if(!comment
&& flags
== 0 && options_length
==0){
600 /* Put padding in the buffer */
601 for (i
= 0; i
< pad_len
; i
++) {
604 /* Write the total length */
605 memcpy(&buff
[i
], &block_total_length
, sizeof(uint32_t));
606 i
+= sizeof(uint32_t);
607 return write_to_file(pfile
, (const uint8_t*)&buff
, i
, bytes_written
, err
);
610 if (!write_to_file(pfile
, (const uint8_t*)&padding
, pad_len
, bytes_written
, err
))
613 if (!pcapng_write_string_option(pfile
, OPT_COMMENT
, comment
,
617 option
.type
= EPB_FLAGS
;
618 option
.value_length
= sizeof(uint32_t);
619 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
621 if (!write_to_file(pfile
, (const uint8_t*)&flags
, sizeof(uint32_t), bytes_written
, err
))
624 if (options_length
!= 0) {
625 /* write end of options */
626 option
.type
= OPT_ENDOFOPT
;
627 option
.value_length
= 0;
628 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
632 return write_to_file(pfile
, (const uint8_t*)&block_total_length
, sizeof(uint32_t), bytes_written
, err
);
636 pcapng_write_interface_statistics_block(FILE* pfile
,
637 uint32_t interface_id
,
638 uint64_t *bytes_written
,
639 const char *comment
, /* OPT_COMMENT 1 */
640 uint64_t isb_starttime
, /* ISB_STARTTIME 2 */
641 uint64_t isb_endtime
, /* ISB_ENDTIME 3 */
642 uint64_t isb_ifrecv
, /* ISB_IFRECV 4 */
643 uint64_t isb_ifdrop
, /* ISB_IFDROP 5 */
652 struct ws_option option
;
653 uint32_t block_total_length
;
654 uint32_t options_length
;
659 * Current time, represented as 100-nanosecond intervals since
660 * January 1, 1601, 00:00:00 UTC.
662 * I think DWORD might be signed, so cast both parts of "now"
663 * to uint32_t so that the sign bit doesn't get treated specially.
665 * Windows 8 provides GetSystemTimePreciseAsFileTime which we
666 * might want to use instead.
668 GetSystemTimeAsFileTime(&now
);
669 timestamp
= (((uint64_t)(uint32_t)now
.dwHighDateTime
) << 32) +
670 (uint32_t)now
.dwLowDateTime
;
673 * Convert to same thing but as 1-microsecond, i.e. 1000-nanosecond,
679 * Subtract difference, in microseconds, between January 1, 1601
680 * 00:00:00 UTC and January 1, 1970, 00:00:00 UTC.
682 timestamp
-= EPOCH_DELTA_1601_01_01_00_00_00_UTC
*1000000;
685 * Current time, represented as seconds and microseconds since
686 * January 1, 1970, 00:00:00 UTC.
688 gettimeofday(&now
, NULL
);
691 * Convert to delta in microseconds.
693 timestamp
= (uint64_t)(now
.tv_sec
) * 1000000 +
694 (uint64_t)(now
.tv_usec
);
696 block_total_length
= (uint32_t)(sizeof(struct isb
) + sizeof(uint32_t));
698 if (isb_ifrecv
!= UINT64_MAX
) {
699 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
702 if (isb_ifdrop
!= UINT64_MAX
) {
703 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
707 options_length
+= pcapng_count_string_option(comment
);
708 if (isb_starttime
!=0) {
709 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
710 sizeof(uint64_t)); /* ISB_STARTTIME */
712 if (isb_endtime
!=0) {
713 options_length
+= (uint32_t)(sizeof(struct ws_option
) +
714 sizeof(uint64_t)); /* ISB_ENDTIME */
716 /* If we have options add size of end-of-options */
717 if (options_length
!= 0) {
718 options_length
+= (uint32_t)sizeof(struct ws_option
);
720 block_total_length
+= options_length
;
722 isb
.block_type
= INTERFACE_STATISTICS_BLOCK_TYPE
;
723 isb
.block_total_length
= block_total_length
;
724 isb
.interface_id
= interface_id
;
725 isb
.timestamp_high
= (uint32_t)((timestamp
>>32) & 0xffffffff);
726 isb
.timestamp_low
= (uint32_t)(timestamp
& 0xffffffff);
727 if (!write_to_file(pfile
, (const uint8_t*)&isb
, sizeof(struct isb
), bytes_written
, err
))
730 /* write comment string if applicable */
731 if (!pcapng_write_string_option(pfile
, OPT_COMMENT
, comment
,
735 if (isb_starttime
!=0) {
738 option
.type
= ISB_STARTTIME
;
739 option
.value_length
= sizeof(uint64_t);
740 high
= (uint32_t)((isb_starttime
>>32) & 0xffffffff);
741 low
= (uint32_t)(isb_starttime
& 0xffffffff);
742 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
745 if (!write_to_file(pfile
, (const uint8_t*)&high
, sizeof(uint32_t), bytes_written
, err
))
748 if (!write_to_file(pfile
, (const uint8_t*)&low
, sizeof(uint32_t), bytes_written
, err
))
751 if (isb_endtime
!=0) {
754 option
.type
= ISB_ENDTIME
;
755 option
.value_length
= sizeof(uint64_t);
756 high
= (uint32_t)((isb_endtime
>>32) & 0xffffffff);
757 low
= (uint32_t)(isb_endtime
& 0xffffffff);
758 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
761 if (!write_to_file(pfile
, (const uint8_t*)&high
, sizeof(uint32_t), bytes_written
, err
))
764 if (!write_to_file(pfile
, (const uint8_t*)&low
, sizeof(uint32_t), bytes_written
, err
))
767 if (isb_ifrecv
!= UINT64_MAX
) {
768 option
.type
= ISB_IFRECV
;
769 option
.value_length
= sizeof(uint64_t);
770 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
773 if (!write_to_file(pfile
, (const uint8_t*)&isb_ifrecv
, sizeof(uint64_t), bytes_written
, err
))
776 if (isb_ifdrop
!= UINT64_MAX
) {
777 option
.type
= ISB_IFDROP
;
778 option
.value_length
= sizeof(uint64_t);
779 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
782 if (!write_to_file(pfile
, (const uint8_t*)&isb_ifdrop
, sizeof(uint64_t), bytes_written
, err
))
785 if (options_length
!= 0) {
786 /* write end of options */
787 option
.type
= OPT_ENDOFOPT
;
788 option
.value_length
= 0;
789 if (!write_to_file(pfile
, (const uint8_t*)&option
, sizeof(struct ws_option
), bytes_written
, err
))
793 return write_to_file(pfile
, (const uint8_t*)&block_total_length
, sizeof(uint32_t), bytes_written
, err
);
797 * Editor modelines - https://www.wireshark.org/tools/modelines.html
802 * indent-tabs-mode: nil
805 * vi: set shiftwidth=8 tabstop=8 expandtab:
806 * :indentSize=8:tabSize=8:noTabs=true: