Avoid adding -pie on older cmake versions
[metze/wireshark/wip.git] / pcapio.c
1 /* pcapio.c
2  * Our own private code for writing libpcap files when capturing.
3  *
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
6  * provides that, but
7  *
8  *      1) earlier versions of libpcap doesn't have it
9  *
10  * and
11  *
12  *      2) WinPcap doesn'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).
16  *
17  * Libpcap's pcap_dump() also doesn't return any error indications.
18  *
19  * Wireshark - Network traffic analyzer
20  * By Gerald Combs <gerald@wireshark.org>
21  * Copyright 1998 Gerald Combs
22  *
23  * Derived from code in the Wiretap Library
24  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
25  *
26  * This program is free software; you can redistribute it and/or
27  * modify it under the terms of the GNU General Public License
28  * as published by the Free Software Foundation; either version 2
29  * of the License, or (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program; if not, write to the Free Software
38  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39  */
40
41 #include <config.h>
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <errno.h>
46 #include <string.h>
47 #ifdef HAVE_SYS_TIME_H
48 #include <sys/time.h>
49 #endif
50 #ifdef _WIN32
51 #include <Windows.h>
52 #endif
53
54 #include <glib.h>
55
56 #include "pcapio.h"
57
58 /* Magic numbers in "libpcap" files.
59
60    "libpcap" file records are written in the byte order of the host that
61    writes them, and the reader is expected to fix this up.
62
63    PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
64    is a byte-swapped version of that.
65
66    PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format,
67    which uses the same common file format as PCAP_MAGIC, but the
68    timestamps are saved in nanosecond resolution instead of microseconds.
69    PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */
70 #define PCAP_MAGIC                      0xa1b2c3d4
71 #define PCAP_SWAPPED_MAGIC              0xd4c3b2a1
72 #define PCAP_NSEC_MAGIC                 0xa1b23c4d
73 #define PCAP_SWAPPED_NSEC_MAGIC         0x4d3cb2a1
74
75 /* "libpcap" file header. */
76 struct pcap_hdr {
77         guint32 magic;          /* magic number */
78         guint16 version_major;  /* major version number */
79         guint16 version_minor;  /* minor version number */
80         gint32  thiszone;       /* GMT to local correction */
81         guint32 sigfigs;        /* accuracy of timestamps */
82         guint32 snaplen;        /* max length of captured packets, in octets */
83         guint32 network;        /* data link type */
84 };
85
86 /* "libpcap" record header. */
87 struct pcaprec_hdr {
88         guint32 ts_sec;         /* timestamp seconds */
89         guint32 ts_usec;        /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
90         guint32 incl_len;       /* number of octets of packet saved in file */
91         guint32 orig_len;       /* actual length of packet */
92 };
93
94 /* Magic numbers in ".pcapng" files.
95  *
96  * .pcapng file records are written in the byte order of the host that
97  * writes them, and the reader is expected to fix this up.
98  * PCAPNG_MAGIC is the magic number, in host byte order;
99  * PCAPNG_SWAPPED_MAGIC is a byte-swapped version of that.
100  */
101 #define PCAPNG_MAGIC         0x1A2B3C4D
102 #define PCAPNG_SWAPPED_MAGIC 0xD4C3B2A1
103
104 /* Currently we are only supporting the initial version of
105    the file format. */
106 #define PCAPNG_MAJOR_VERSION 1
107 #define PCAPNG_MINOR_VERSION 0
108
109 /* Section Header Block without options and trailing Block Total Length */
110 struct shb {
111         guint32 block_type;
112         guint32 block_total_length;
113         guint32 byte_order_magic;
114         guint16 major_version;
115         guint16 minor_version;
116         guint64 section_length;
117 };
118 #define SECTION_HEADER_BLOCK_TYPE 0x0A0D0D0A
119
120 /* Interface Decription Block without options and trailing Block Total Length */
121 struct idb {
122         guint32 block_type;
123         guint32 block_total_length;
124         guint16 link_type;
125         guint16 reserved;
126         guint32 snap_len;
127 };
128 #define INTERFACE_DESCRIPTION_BLOCK_TYPE 0x00000001
129
130 /* Interface Statistics Block without actual packet, options, and trailing
131    Block Total Length */
132 struct isb {
133         guint32 block_type;
134         guint32 block_total_length;
135         guint32 interface_id;
136         guint32 timestamp_high;
137         guint32 timestamp_low;
138 };
139 #define INTERFACE_STATISTICS_BLOCK_TYPE 0x00000005
140
141 /* Enhanced Packet Block without actual packet, options, and trailing
142    Block Total Length */
143 struct epb {
144         guint32 block_type;
145         guint32 block_total_length;
146         guint32 interface_id;
147         guint32 timestamp_high;
148         guint32 timestamp_low;
149         guint32 captured_len;
150         guint32 packet_len;
151 };
152 #define ENHANCED_PACKET_BLOCK_TYPE 0x00000006
153
154 struct option {
155         guint16 type;
156         guint16 value_length;
157 };
158 #define OPT_ENDOFOPT      0
159 #define OPT_COMMENT       1
160 #define EPB_FLAGS         2
161 #define SHB_HARDWARE      2 /* currently not used */
162 #define SHB_OS            3
163 #define SHB_USERAPPL      4
164 #define IDB_NAME          2
165 #define IDB_DESCRIPTION   3
166 #define IDB_IF_SPEED      8
167 #define IDB_TSRESOL       9
168 #define IDB_FILTER       11
169 #define IDB_OS           12
170 #define ISB_STARTTIME     2
171 #define ISB_ENDTIME       3
172 #define ISB_IFRECV        4
173 #define ISB_IFDROP        5
174 #define ISB_FILTERACCEPT  6
175 #define ISB_OSDROP        7
176 #define ISB_USRDELIV      8
177 #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
178
179 /* Write to capture file */
180 static gboolean
181 write_to_file(FILE* pfile, const guint8* data, size_t data_length,
182               guint64 *bytes_written, int *err)
183 {
184         size_t nwritten;
185
186         nwritten = fwrite(data, data_length, 1, pfile);
187         if (nwritten != 1) {
188                 if (ferror(pfile)) {
189                         *err = errno;
190                 } else {
191                         *err = 0;
192                 }
193                 return FALSE;
194         }
195
196         (*bytes_written) += data_length;
197         return TRUE;
198 }
199
200 /* Writing pcap files */
201
202 /* Write the file header to a dump file.
203    Returns TRUE on success, FALSE on failure.
204    Sets "*err" to an error code, or 0 for a short write, on failure*/
205 gboolean
206 libpcap_write_file_header(FILE* pfile, int linktype, int snaplen, gboolean ts_nsecs, guint64 *bytes_written, int *err)
207 {
208         struct pcap_hdr file_hdr;
209
210         file_hdr.magic = ts_nsecs ? PCAP_NSEC_MAGIC : PCAP_MAGIC;
211         /* current "libpcap" format is 2.4 */
212         file_hdr.version_major = 2;
213         file_hdr.version_minor = 4;
214         file_hdr.thiszone = 0;  /* XXX - current offset? */
215         file_hdr.sigfigs = 0;   /* unknown, but also apparently unused */
216         file_hdr.snaplen = snaplen;
217         file_hdr.network = linktype;
218
219         return write_to_file(pfile, (const guint8*)&file_hdr, sizeof(file_hdr), bytes_written, err);
220 }
221
222 /* Write a record for a packet to a dump file.
223    Returns TRUE on success, FALSE on failure. */
224 gboolean
225 libpcap_write_packet(FILE* pfile,
226                      time_t sec, guint32 usec,
227                      guint32 caplen, guint32 len,
228                      const guint8 *pd,
229                      guint64 *bytes_written, int *err)
230 {
231         struct pcaprec_hdr rec_hdr;
232
233         rec_hdr.ts_sec = (guint32)sec; /* Y2.038K issue in pcap format.... */
234         rec_hdr.ts_usec = usec;
235         rec_hdr.incl_len = caplen;
236         rec_hdr.orig_len = len;
237         if (!write_to_file(pfile, (const guint8*)&rec_hdr, sizeof(rec_hdr), bytes_written, err))
238                 return FALSE;
239
240         return write_to_file(pfile, pd, caplen, bytes_written, err);
241 }
242
243 /* Writing pcap-ng files */
244
245 static guint32
246 pcapng_count_string_option(const char *option_value)
247 {
248         if ((option_value != NULL) && (strlen(option_value) > 0) && (strlen(option_value) < G_MAXUINT16)) {
249                 /* There's a value to write; get its length */
250                 return (guint32)(sizeof(struct option) +
251                                  (guint16)ADD_PADDING(strlen(option_value)));
252         }
253         return 0; /* nothing to write */
254 }
255
256 static gboolean
257 pcapng_write_string_option(FILE* pfile,
258                            guint16 option_type, const char *option_value,
259                            guint64 *bytes_written, int *err)
260 {
261         size_t option_value_length;
262         struct option option;
263         const guint32 padding = 0;
264
265         if (option_value == NULL)
266                 return TRUE; /* nothing to write */
267         option_value_length = strlen(option_value);
268         if ((option_value_length > 0) && (option_value_length < G_MAXUINT16)) {
269                 /* something to write */
270                 option.type = option_type;
271                 option.value_length = (guint16)option_value_length;
272
273                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
274                         return FALSE;
275
276                 if (!write_to_file(pfile, (const guint8*)option_value, (int) option_value_length, bytes_written, err))
277                         return FALSE;
278
279                 if (option_value_length % 4) {
280                         if (!write_to_file(pfile, (const guint8*)&padding, 4 - option_value_length % 4, bytes_written, err))
281                                 return FALSE;
282                 }
283         }
284         return TRUE;
285 }
286
287 gboolean
288 pcapng_write_session_header_block(FILE* pfile,
289                                   const char *comment,
290                                   const char *hw,
291                                   const char *os,
292                                   const char *appname,
293                                   guint64 section_length,
294                                   guint64 *bytes_written,
295                                   int *err)
296 {
297         struct shb shb;
298         struct option option;
299         guint32 block_total_length;
300         guint32 options_length;
301
302         /* Size of base header */
303         block_total_length = sizeof(struct shb) +
304                              sizeof(guint32);
305         options_length = 0;
306         options_length += pcapng_count_string_option(comment);
307         options_length += pcapng_count_string_option(hw);
308         options_length += pcapng_count_string_option(os);
309         options_length += pcapng_count_string_option(appname);
310         /* If we have options add size of end-of-options */
311         if (options_length != 0) {
312                 options_length += (guint32)sizeof(struct option);
313         }
314         block_total_length += options_length;
315
316         /* write shb header */
317         shb.block_type = SECTION_HEADER_BLOCK_TYPE;
318         shb.block_total_length = block_total_length;
319         shb.byte_order_magic = PCAPNG_MAGIC;
320         shb.major_version = PCAPNG_MAJOR_VERSION;
321         shb.minor_version = PCAPNG_MINOR_VERSION;
322         shb.section_length = section_length;
323
324         if (!write_to_file(pfile, (const guint8*)&shb, sizeof(struct shb), bytes_written, err))
325                 return FALSE;
326
327         if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment,
328                                         bytes_written, err))
329                 return FALSE;
330         if (!pcapng_write_string_option(pfile, SHB_HARDWARE, hw,
331                                         bytes_written, err))
332                 return FALSE;
333         if (!pcapng_write_string_option(pfile, SHB_OS, os,
334                                         bytes_written, err))
335                 return FALSE;
336         if (!pcapng_write_string_option(pfile, SHB_USERAPPL, appname,
337                                         bytes_written, err))
338                 return FALSE;
339         if (options_length != 0) {
340                 /* write end of options */
341                 option.type = OPT_ENDOFOPT;
342                 option.value_length = 0;
343                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
344                         return FALSE;
345         }
346
347         /* write the trailing block total length */
348         return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err);
349 }
350
351 gboolean
352 pcapng_write_interface_description_block(FILE* pfile,
353                                          const char *comment, /* OPT_COMMENT        1 */
354                                          const char *name,    /* IDB_NAME           2 */
355                                          const char *descr,   /* IDB_DESCRIPTION    3 */
356                                          const char *filter,  /* IDB_FILTER        11 */
357                                          const char *os,      /* IDB_OS            12 */
358                                          int link_type,
359                                          int snap_len,
360                                          guint64 *bytes_written,
361                                          guint64 if_speed,    /* IDB_IF_SPEED       8 */
362                                          guint8 tsresol,      /* IDB_TSRESOL        9 */
363                                          int *err)
364 {
365         struct idb idb;
366         struct option option;
367         guint32 block_total_length;
368         guint32 options_length;
369         const guint32 padding = 0;
370
371         block_total_length = (guint32)(sizeof(struct idb) + sizeof(guint32));
372         options_length = 0;
373         /* 01 - OPT_COMMENT */
374         options_length += pcapng_count_string_option(comment);
375
376         /* 02 - IDB_NAME */
377         options_length += pcapng_count_string_option(name);
378
379         /* 03 - IDB_DESCRIPTION */
380         options_length += pcapng_count_string_option(descr);
381
382         /* 08 - IDB_IF_SPEED */
383         if (if_speed != 0) {
384                 options_length += (guint32)(sizeof(struct option) +
385                                             sizeof(guint64));
386         }
387
388         /* 09 - IDB_TSRESOL */
389         if (tsresol != 0) {
390                 options_length += (guint32)(sizeof(struct option) +
391                                             sizeof(struct option));
392         }
393
394         /* 11 - IDB_FILTER */
395         if ((filter != NULL) && (strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16)) {
396                 /* No, this isn't a string, it has an extra type byte */
397                 options_length += (guint32)(sizeof(struct option) +
398                                             (guint16)(ADD_PADDING(strlen(filter)+ 1)));
399         }
400
401         /* 12 - IDB_OS */
402         options_length += pcapng_count_string_option(os);
403
404         /* If we have options add size of end-of-options */
405         if (options_length != 0) {
406                 options_length += (guint32)sizeof(struct option);
407         }
408         block_total_length += options_length;
409
410         /* write block header */
411         idb.block_type = INTERFACE_DESCRIPTION_BLOCK_TYPE;
412         idb.block_total_length = block_total_length;
413         idb.link_type = link_type;
414         idb.reserved = 0;
415         idb.snap_len = snap_len;
416         if (!write_to_file(pfile, (const guint8*)&idb, sizeof(struct idb), bytes_written, err))
417                 return FALSE;
418
419         /* 01 - OPT_COMMENT - write comment string if applicable */
420         if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment,
421                                         bytes_written, err))
422                 return FALSE;
423
424         /* 02 - IDB_NAME - write interface name string if applicable */
425         if (!pcapng_write_string_option(pfile, IDB_NAME, name,
426                                         bytes_written, err))
427                 return FALSE;
428
429         /* 03 - IDB_DESCRIPTION */
430         /* write interface description string if applicable */
431         if (!pcapng_write_string_option(pfile, IDB_DESCRIPTION, descr,
432                                         bytes_written, err))
433                 return FALSE;
434
435         /* 08 - IDB_IF_SPEED */
436         if (if_speed != 0) {
437                 option.type = IDB_IF_SPEED;
438                 option.value_length = sizeof(guint64);
439
440                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
441                         return FALSE;
442
443                 if (!write_to_file(pfile, (const guint8*)&if_speed, sizeof(guint64), bytes_written, err))
444                         return FALSE;
445         }
446
447         /* 09 - IDB_TSRESOL */
448         if (tsresol != 0) {
449                 option.type = IDB_TSRESOL;
450                 option.value_length = sizeof(guint8);
451
452                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
453                         return FALSE;
454
455                 if (!write_to_file(pfile, (const guint8*)&tsresol, sizeof(guint8), bytes_written, err))
456                         return FALSE;
457
458                 if (!write_to_file(pfile, (const guint8*)&padding, 3, bytes_written, err))
459                         return FALSE;
460         }
461
462         /* 11 - IDB_FILTER - write filter string if applicable
463          * We only write version 1 of the filter, pcapng string
464          */
465         if ((filter != NULL) && (strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16 - 1)) {
466                 option.type = IDB_FILTER;
467                 option.value_length = (guint16)(strlen(filter) + 1 );
468                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
469                         return FALSE;
470
471                 /* The first byte of the Option Data keeps a code of the filter used, 0 = lipbpcap filter string */
472                 if (!write_to_file(pfile, (const guint8*)&padding, 1, bytes_written, err))
473                         return FALSE;
474                 if (!write_to_file(pfile, (const guint8*)filter, (int) strlen(filter), bytes_written, err))
475                         return FALSE;
476                 if ((strlen(filter) + 1) % 4) {
477                         if (!write_to_file(pfile, (const guint8*)&padding, 4 - (strlen(filter) + 1) % 4, bytes_written, err))
478                                 return FALSE;
479                 }
480         }
481
482         /* 12 - IDB_OS - write os string if applicable */
483         if (!pcapng_write_string_option(pfile, IDB_OS, os,
484                                         bytes_written, err))
485                 return FALSE;
486
487         if (options_length != 0) {
488                 /* write end of options */
489                 option.type = OPT_ENDOFOPT;
490                 option.value_length = 0;
491                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
492                         return FALSE;
493         }
494
495         /* write the trailing Block Total Length */
496         return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err);
497 }
498
499 /* Write a record for a packet to a dump file.
500    Returns TRUE on success, FALSE on failure. */
501 gboolean
502 pcapng_write_enhanced_packet_block(FILE* pfile,
503                                    const char *comment,
504                                    time_t sec, guint32 usec,
505                                    guint32 caplen, guint32 len,
506                                    guint32 interface_id,
507                                    guint ts_mul,
508                                    const guint8 *pd,
509                                    guint32 flags,
510                                    guint64 *bytes_written,
511                                    int *err)
512 {
513         struct epb epb;
514         struct option option;
515         guint32 block_total_length;
516         guint64 timestamp;
517         guint32 options_length;
518         const guint32 padding = 0;
519
520         block_total_length = (guint32)(sizeof(struct epb) +
521                                        ADD_PADDING(caplen) +
522                                        sizeof(guint32));
523         options_length = 0;
524         options_length += pcapng_count_string_option(comment);
525         if (flags != 0) {
526                 options_length += (guint32)(sizeof(struct option) +
527                                             sizeof(guint32));
528         }
529         /* If we have options add size of end-of-options */
530         if (options_length != 0) {
531                 options_length += (guint32)sizeof(struct option);
532         }
533         block_total_length += options_length;
534         timestamp = (guint64)sec * ts_mul + (guint64)usec;
535         epb.block_type = ENHANCED_PACKET_BLOCK_TYPE;
536         epb.block_total_length = block_total_length;
537         epb.interface_id = interface_id;
538         epb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff);
539         epb.timestamp_low = (guint32)(timestamp & 0xffffffff);
540         epb.captured_len = caplen;
541         epb.packet_len = len;
542         if (!write_to_file(pfile, (const guint8*)&epb, sizeof(struct epb), bytes_written, err))
543                 return FALSE;
544         if (!write_to_file(pfile, pd, caplen, bytes_written, err))
545                 return FALSE;
546         if (caplen % 4) {
547                 if (!write_to_file(pfile, (const guint8*)&padding, 4 - caplen % 4, bytes_written, err))
548                         return FALSE;
549         }
550         if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment,
551                                         bytes_written, err))
552                 return FALSE;
553         if (flags != 0) {
554                 option.type = EPB_FLAGS;
555                 option.value_length = sizeof(guint32);
556                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
557                         return FALSE;
558                 if (!write_to_file(pfile, (const guint8*)&flags, sizeof(guint32), bytes_written, err))
559                         return FALSE;
560         }
561         if (options_length != 0) {
562                 /* write end of options */
563                 option.type = OPT_ENDOFOPT;
564                 option.value_length = 0;
565                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
566                         return FALSE;
567         }
568
569        return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err);
570 }
571
572 gboolean
573 pcapng_write_interface_statistics_block(FILE* pfile,
574                                         guint32 interface_id,
575                                         guint64 *bytes_written,
576                                         const char *comment,   /* OPT_COMMENT           1 */
577                                         guint64 isb_starttime, /* ISB_STARTTIME         2 */
578                                         guint64 isb_endtime,   /* ISB_ENDTIME           3 */
579                                         guint64 isb_ifrecv,    /* ISB_IFRECV            4 */
580                                         guint64 isb_ifdrop,    /* ISB_IFDROP            5 */
581                                         int *err)
582 {
583         struct isb isb;
584 #ifdef _WIN32
585         FILETIME now;
586 #else
587         struct timeval now;
588 #endif
589         struct option option;
590         guint32 block_total_length;
591         guint32 options_length;
592         guint64 timestamp;
593
594 #ifdef _WIN32
595         /*
596          * Current time, represented as 100-nanosecond intervals since
597          * January 1, 1601, 00:00:00 UTC.
598          *
599          * I think DWORD might be signed, so cast both parts of "now"
600          * to guint32 so that the sign bit doesn't get treated specially.
601          *
602          * Windows 8 provides GetSystemTimePreciseAsFileTime which we
603          * might want to use instead.
604          */
605         GetSystemTimeAsFileTime(&now);
606         timestamp = (((guint64)(guint32)now.dwHighDateTime) << 32) +
607                     (guint32)now.dwLowDateTime;
608
609         /*
610          * Convert to same thing but as 1-microsecond, i.e. 1000-nanosecond,
611          * intervals.
612          */
613         timestamp /= 10;
614
615         /*
616          * Subtract difference, in microseconds, between January 1, 1601
617          * 00:00:00 UTC and January 1, 1970, 00:00:00 UTC.
618          */
619         timestamp -= G_GUINT64_CONSTANT(11644473600000000);
620 #else
621         /*
622          * Current time, represented as seconds and microseconds since
623          * January 1, 1970, 00:00:00 UTC.
624          */
625         gettimeofday(&now, NULL);
626
627         /*
628          * Convert to delta in microseconds.
629          */
630         timestamp = (guint64)(now.tv_sec) * 1000000 +
631                     (guint64)(now.tv_usec);
632 #endif
633         block_total_length = (guint32)(sizeof(struct isb) + sizeof(guint32));
634         options_length = 0;
635         if (isb_ifrecv != G_MAXUINT64) {
636                 options_length += (guint32)(sizeof(struct option) +
637                                             sizeof(guint64));
638         }
639         if (isb_ifdrop != G_MAXUINT64) {
640                 options_length += (guint32)(sizeof(struct option) +
641                                             sizeof(guint64));
642         }
643         /* OPT_COMMENT */
644         options_length += pcapng_count_string_option(comment);
645         if (isb_starttime !=0) {
646                 options_length += (guint32)(sizeof(struct option) +
647                                             sizeof(guint64)); /* ISB_STARTTIME */
648         }
649         if (isb_endtime !=0) {
650                 options_length += (guint32)(sizeof(struct option) +
651                                             sizeof(guint64)); /* ISB_ENDTIME */
652         }
653         /* If we have options add size of end-of-options */
654         if (options_length != 0) {
655                 options_length += (guint32)sizeof(struct option);
656         }
657         block_total_length += options_length;
658
659         isb.block_type = INTERFACE_STATISTICS_BLOCK_TYPE;
660         isb.block_total_length = block_total_length;
661         isb.interface_id = interface_id;
662         isb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff);
663         isb.timestamp_low = (guint32)(timestamp & 0xffffffff);
664         if (!write_to_file(pfile, (const guint8*)&isb, sizeof(struct isb), bytes_written, err))
665                 return FALSE;
666
667         /* write comment string if applicable */
668         if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment,
669                                         bytes_written, err))
670                 return FALSE;
671
672         if (isb_starttime !=0) {
673                 guint32 high, low;
674
675                 option.type = ISB_STARTTIME;
676                 option.value_length = sizeof(guint64);
677                 high = (guint32)((isb_starttime>>32) & 0xffffffff);
678                 low = (guint32)(isb_starttime & 0xffffffff);
679                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
680                         return FALSE;
681
682                 if (!write_to_file(pfile, (const guint8*)&high, sizeof(guint32), bytes_written, err))
683                         return FALSE;
684
685                 if (!write_to_file(pfile, (const guint8*)&low, sizeof(guint32), bytes_written, err))
686                         return FALSE;
687         }
688         if (isb_endtime !=0) {
689                 guint32 high, low;
690
691                 option.type = ISB_ENDTIME;
692                 option.value_length = sizeof(guint64);
693                 high = (guint32)((isb_endtime>>32) & 0xffffffff);
694                 low = (guint32)(isb_endtime & 0xffffffff);
695                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
696                         return FALSE;
697
698                 if (!write_to_file(pfile, (const guint8*)&high, sizeof(guint32), bytes_written, err))
699                         return FALSE;
700
701                 if (!write_to_file(pfile, (const guint8*)&low, sizeof(guint32), bytes_written, err))
702                         return FALSE;
703         }
704         if (isb_ifrecv != G_MAXUINT64) {
705                 option.type = ISB_IFRECV;
706                 option.value_length = sizeof(guint64);
707                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
708                         return FALSE;
709
710                 if (!write_to_file(pfile, (const guint8*)&isb_ifrecv, sizeof(guint64), bytes_written, err))
711                         return FALSE;
712         }
713         if (isb_ifdrop != G_MAXUINT64) {
714                 option.type = ISB_IFDROP;
715                 option.value_length = sizeof(guint64);
716                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
717                         return FALSE;
718
719                 if (!write_to_file(pfile, (const guint8*)&isb_ifdrop, sizeof(guint64), bytes_written, err))
720                         return FALSE;
721         }
722         if (options_length != 0) {
723                 /* write end of options */
724                 option.type = OPT_ENDOFOPT;
725                 option.value_length = 0;
726                 if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err))
727                         return FALSE;
728         }
729
730         return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err);
731 }
732
733 /*
734  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
735  *
736  * Local variables:
737  * c-basic-offset: 8
738  * tab-width: 8
739  * indent-tabs-mode: nil
740  * End:
741  *
742  * vi: set shiftwidth=8 tabstop=8 expandtab:
743  * :indentSize=8:tabSize=8:noTabs=true:
744  */