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