7870a797b12de6cf87b355d6511ee94644fb45b8
[obnox/wireshark/wip.git] / wiretap / pcapng.c
1 /* pcapng.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * File format support for pcap-ng file format
9  * Copyright (c) 2007 by Ulf Lamping <ulf.lamping@web.de>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 /* File format reference:
27  *   http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html
28  * Related Wiki page:
29  *   http://wiki.wireshark.org/Development/PcapNg
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include "wtap-int.h"
40 #include "file_wrappers.h"
41 #include "buffer.h"
42 #include "libpcap.h"
43 #include "pcap-common.h"
44 #include "pcap-encap.h"
45 #include "pcapng.h"
46
47 #if 0
48 #define pcapng_debug0(str) g_warning(str)
49 #define pcapng_debug1(str,p1) g_warning(str,p1)
50 #define pcapng_debug2(str,p1,p2) g_warning(str,p1,p2)
51 #define pcapng_debug3(str,p1,p2,p3) g_warning(str,p1,p2,p3)
52 #else
53 #define pcapng_debug0(str)
54 #define pcapng_debug1(str,p1)
55 #define pcapng_debug2(str,p1,p2)
56 #define pcapng_debug3(str,p1,p2,p3)
57 #endif
58
59 static gboolean
60 pcapng_read(wtap *wth, int *err, gchar **err_info,
61     gint64 *data_offset);
62 static gboolean
63 pcapng_seek_read(wtap *wth, gint64 seek_off,
64     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
65     int *err, gchar **err_info);
66 static void
67 pcapng_close(wtap *wth);
68
69
70 /* pcapng: common block header for every block type */
71 typedef struct pcapng_block_header_s {
72         guint32 block_type;
73         guint32 block_total_length;
74         /* x bytes block_body */
75         /* guint32 block_total_length */
76 } pcapng_block_header_t;
77
78 /* pcapng: section header block */
79 typedef struct pcapng_section_header_block_s {
80         /* pcapng_block_header_t */
81         guint32 magic;
82         guint16 version_major;
83         guint16 version_minor;
84         guint64 section_length; /* might be -1 for unknown */
85         /* ... Options ... */
86 } pcapng_section_header_block_t;
87
88 /* pcapng: interface description block */
89 typedef struct pcapng_interface_description_block_s {
90         guint16 linktype;
91         guint16 reserved;
92         guint32 snaplen;
93         /* ... Options ... */
94 } pcapng_interface_description_block_t;
95
96 /* pcapng: packet block (obsolete) */
97 typedef struct pcapng_packet_block_s {
98         guint16 interface_id;
99         guint16 drops_count;
100         guint32 timestamp_high;
101         guint32 timestamp_low;
102         guint32 captured_len;
103         guint32 packet_len;
104         /* ... Packet Data ... */
105         /* ... Padding ... */
106         /* ... Options ... */
107 } pcapng_packet_block_t;
108
109 /* pcapng: enhanced packet block */
110 typedef struct pcapng_enhanced_packet_block_s {
111         guint32 interface_id;
112         guint32 timestamp_high;
113         guint32 timestamp_low;
114         guint32 captured_len;
115         guint32 packet_len;
116         /* ... Packet Data ... */
117         /* ... Padding ... */
118         /* ... Options ... */
119 } pcapng_enhanced_packet_block_t;
120
121 /* pcapng: simple packet block */
122 typedef struct pcapng_simple_packet_block_s {
123         guint32 packet_len;
124         /* ... Packet Data ... */
125         /* ... Padding ... */
126 } pcapng_simple_packet_block_t;
127
128 /* pcapng: interface statistics block */
129 typedef struct pcapng_interface_statistics_block_s {
130         guint32 interface_id;
131         guint32 timestamp_high;
132         guint32 timestamp_low;
133         /* ... Options ... */
134 } pcapng_interface_statistics_block_t;
135
136 /* pcapng: common option header for every option type */
137 typedef struct pcapng_option_header_s {
138         guint16 option_code;
139         guint16 option_length;
140         /* ... x bytes Option Body ... */
141     /* ... Padding ... */
142 } pcapng_option_header_t;
143
144 /* Block types */
145 #define BLOCK_TYPE_IDB 0x00000001 /* Interface Description Block */
146 #define BLOCK_TYPE_PB  0x00000002 /* Packet Block (obsolete) */
147 #define BLOCK_TYPE_SPB 0x00000003 /* Simple Packet Block */
148 #define BLOCK_TYPE_NRB 0x00000004 /* Name Resolution Block */
149 #define BLOCK_TYPE_ISB 0x00000005 /* Interface Statistics Block */
150 #define BLOCK_TYPE_EPB 0x00000006 /* Enhanced Packet Block */
151 #define BLOCK_TYPE_SHB 0x0A0D0D0A /* Section Header Block */
152
153
154
155 /* Capture section */
156 typedef struct wtapng_section_s {
157         /* mandatory */
158         guint64                         section_length;
159         /* options */
160         gchar                           *opt_comment;   /* NULL if not available */
161         gchar                           *shb_hardware;  /* NULL if not available */
162         gchar                           *shb_os;        /* NULL if not available */
163         gchar                           *shb_user_appl; /* NULL if not available */
164 } wtapng_section_t;
165
166 /* Interface Description */
167 typedef struct wtapng_if_descr_s {
168         /* mandatory */
169         guint16                         link_type;
170         guint32                         snap_len;
171         /* options */
172         gchar                           *opt_comment;   /* NULL if not available */
173         gchar                           *if_name;       /* NULL if not available */
174         gchar                           *if_description;/* NULL if not available */
175         /* XXX: if_IPv4addr */
176         /* XXX: if_IPv6addr */
177         /* XXX: if_MACaddr */
178         /* XXX: if_EUIaddr */
179         guint64                         if_speed;       /* 0xFFFFFFFF if unknown */
180         guint8                          if_tsresol;     /* default is 6 for microsecond resolution */
181         gchar                           *if_filter;     /* NULL if not available */
182         gchar                           *if_os;         /* NULL if not available */
183         gint8                           if_fcslen;      /* -1 if unknown or changes between packets */
184         /* XXX: guint64 if_tsoffset; */
185 } wtapng_if_descr_t;
186
187 /* Packets */
188 typedef struct wtapng_packet_s {
189         /* mandatory */
190         guint32                         ts_high;        /* seconds since 1.1.1970 */
191         guint32                         ts_low;         /* fraction of seconds, depends on if_tsresol */
192         guint32                         cap_len;        /* data length in the file */
193         guint32                         packet_len;     /* data length on the wire */
194         guint32                         interface_id;   /* identifier of the interface. */
195         guint16                         drops_count;    /* drops count, only valid for packet block */
196                                                         /* 0xffff if information no available */
197         /* options */
198         gchar                           *opt_comment;   /* NULL if not available */
199         guint64                         drop_count;
200         guint32                         pack_flags;     /* XXX - 0 for now (any value for "we don't have it"?) */
201         /* pack_hash */
202
203         guint32                         pseudo_header_len;
204         int                             wtap_encap;
205         /* XXX - put the packet data / pseudo_header here as well? */
206 } wtapng_packet_t;
207
208 /* Simple Packets */
209 typedef struct wtapng_simple_packet_s {
210         /* mandatory */
211         guint32                         cap_len;        /* data length in the file */
212         guint32                         packet_len;     /* data length on the wire */
213         guint32                         pseudo_header_len;
214         int                             wtap_encap;
215         /* XXX - put the packet data / pseudo_header here as well? */
216 } wtapng_simple_packet_t;
217
218 /* Name Resolution */
219 typedef struct wtapng_name_res_s {
220         /* options */
221         gchar                           *opt_comment;   /* NULL if not available */
222         /* XXX */
223 } wtapng_name_res_t;
224
225 /* Interface Statistics */
226 typedef struct wtapng_if_stats_s {
227         /* mandatory */
228         guint64                         interface_id;
229         guint32                         ts_high;
230         guint32                         ts_low;
231         /* options */
232         gchar                           *opt_comment;   /* NULL if not available */
233         /* XXX */
234         /*guint32                               isb_starttime_high;*/
235         /*guint32                               isb_starttime_low;*/
236         /*guint32                               isb_endtime_high;*/
237         /*guint32                               isb_endtime_low;*/
238         guint64                         isb_ifrecv;
239         guint64                         isb_ifdrop;
240         /*guint64                               isb_filteraccept;*/
241         /*guint64                               isb_osdrop;*/
242         /*guint64                               isb_usrdeliv;*/
243 } wtapng_if_stats_t;
244
245
246 typedef struct wtapng_block_s {
247         guint32                                 type;           /* block_type as defined by pcapng */
248         union {
249                 wtapng_section_t        section;
250                 wtapng_if_descr_t       if_descr;
251                 wtapng_packet_t         packet;
252                 wtapng_simple_packet_t  simple_packet;
253                 wtapng_name_res_t       name_res;
254                 wtapng_if_stats_t       if_stats;
255         } data;
256
257         /*
258          * XXX - currently don't know how to handle these!
259          *
260          * For one thing, when we're reading a block, they must be
261          * writable, i.e. not const, so that we can read into them,
262          * but, when we're writing a block, they can be const, and,
263          * in fact, they sometimes point to const values.
264          */
265         const union wtap_pseudo_header *pseudo_header;
266         struct wtap_pkthdr *packet_header;
267         const guchar *frame_buffer;
268         int *file_encap;
269 } wtapng_block_t;
270
271 typedef struct interface_data_s {
272         int wtap_encap;
273         guint64 time_units_per_second;
274 } interface_data_t;
275
276
277 typedef struct {
278         gboolean byte_swapped;
279         guint16 version_major;
280         guint16 version_minor;
281         gint8 if_fcslen;
282         GArray *interface_data;
283         guint number_of_interfaces;
284 } pcapng_t;
285
286 static int
287 pcapng_get_encap(gint id, pcapng_t *pn)
288 {
289         interface_data_t int_data;
290
291         if ((id >= 0) && ((guint)id < pn->number_of_interfaces)) {
292                 int_data = g_array_index(pn->interface_data, interface_data_t, id);
293                 return int_data.wtap_encap;
294         } else {
295                 return WTAP_ERR_UNSUPPORTED_ENCAP;
296         }
297 }
298
299
300 static int
301 pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
302                    char *content, int len, int *err, gchar **err_info _U_)
303 {
304         int     bytes_read;
305         int     block_read;
306         guint64 file_offset64;
307
308
309         /* read option header */
310         errno = WTAP_ERR_CANT_READ;
311         bytes_read = file_read(oh, 1, sizeof (*oh), fh);
312         if (bytes_read != sizeof (*oh)) {
313             pcapng_debug0("pcapng_read_option: failed to read option");
314             *err = file_error(fh);
315             if (*err != 0)
316                     return -1;
317             return 0;
318         }
319         block_read = sizeof (*oh);
320         if(pn->byte_swapped) {
321                 oh->option_code      = BSWAP16(oh->option_code);
322                 oh->option_length    = BSWAP16(oh->option_length);
323         }
324
325         /* sanity check: option length */
326         if (oh->option_length > len) {
327                 pcapng_debug2("pcapng_read_option: option_length %u larger than buffer (%u)",
328                               oh->option_length, len);
329                 return 0;
330         }
331
332         /* read option content */
333         errno = WTAP_ERR_CANT_READ;
334         bytes_read = file_read(content, 1, oh->option_length, fh);
335         if (bytes_read != oh->option_length) {
336                 pcapng_debug1("pcapng_read_if_descr_block: failed to read content of option %u", oh->option_code);
337                 *err = file_error(fh);
338                 if (*err != 0)
339                         return -1;
340                 return 0;
341         }
342         block_read += oh->option_length;
343
344         /* jump over potential padding bytes at end of option */
345         if( (oh->option_length % 4) != 0) {
346                 file_offset64 = file_seek(fh, 4 - (oh->option_length % 4), SEEK_CUR, err);
347                 if (file_offset64 <= 0) {
348                         if (*err != 0)
349                                 return -1;
350                         return 0;
351                 }
352                 block_read += 4 - (oh->option_length % 4);
353         }
354
355         return block_read;
356 }
357
358
359 static int
360 pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
361                                  pcapng_block_header_t *bh, pcapng_t *pn,
362                                  wtapng_block_t *wblock, int *err,
363                                  gchar **err_info)
364 {
365         int     bytes_read;
366         int     block_read;
367         int to_read;
368         pcapng_section_header_block_t shb;
369         pcapng_option_header_t oh;
370         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
371
372
373         /* read block content */
374         errno = WTAP_ERR_CANT_READ;
375         bytes_read = file_read(&shb, 1, sizeof shb, fh);
376         if (bytes_read != sizeof shb) {
377                 *err = file_error(fh);
378                 if (*err == 0) {
379                         if (first_block) {
380                                 /*
381                                  * We're reading this as part of an open,
382                                  * and this block is too short to be
383                                  * an SHB, so the file is too short
384                                  * to be a pcap-ng file.
385                                  */
386                                 return 0;
387                         }
388
389                         /*
390                          * Otherwise, just report this as an error.
391                          */
392                         *err = WTAP_ERR_SHORT_READ;
393                 }
394                 return -1;
395         }
396         block_read = bytes_read;
397
398         /* is the magic number one we expect? */
399         switch(shb.magic) {
400             case(0x1A2B3C4D):
401                 /* this seems pcapng with correct byte order */
402                 pn->byte_swapped                = FALSE;
403                 pn->version_major               = shb.version_major;
404                 pn->version_minor               = shb.version_minor;
405
406                 pcapng_debug3("pcapng_read_section_header_block: SHB (little endian) V%u.%u, len %u",
407                                 pn->version_major, pn->version_minor, bh->block_total_length);
408                 break;
409             case(0x4D3C2B1A):
410                 /* this seems pcapng with swapped byte order */
411                 pn->byte_swapped                = TRUE;
412                 pn->version_major               = BSWAP16(shb.version_major);
413                 pn->version_minor               = BSWAP16(shb.version_minor);
414
415                 /* tweak the block length to meet current swapping that we know now */
416                 bh->block_total_length  = BSWAP32(bh->block_total_length);
417
418                 pcapng_debug3("pcapng_read_section_header_block: SHB (big endian) V%u.%u, len %u",
419                                 pn->version_major, pn->version_minor, bh->block_total_length);
420                 break;
421             default:
422                 /* Not a "pcapng" magic number we know about. */
423                 if (first_block) {
424                         /* Not a pcap-ng file. */
425                         return 0;
426                 }
427
428                 /* A bad block */
429                 *err = WTAP_ERR_BAD_RECORD;
430                 *err_info = g_strdup_printf("pcapng_read_section_header_block: unknown byte-order magic number 0x%08x", shb.magic);
431                 return 0;
432         }
433
434         /* OK, at this point we assume it's a pcap-ng file. */
435
436         /* we currently only understand SHB V1.0 */
437         if (pn->version_major != 1 || pn->version_minor > 0) {
438                 *err = WTAP_ERR_UNSUPPORTED;
439                 *err_info = g_strdup_printf("pcapng_read_section_header_block: unknown SHB version %u.%u",
440                               pn->version_major, pn->version_minor);
441                 return -1;
442         }
443
444         /* 64bit section_length (currently unused) */
445         if (pn->byte_swapped) {
446                 wblock->data.section.section_length = BSWAP64(shb.section_length);
447         } else {
448                 wblock->data.section.section_length = shb.section_length;
449         }
450
451         /* Option defaults */
452         wblock->data.section.opt_comment        = NULL;
453         wblock->data.section.shb_hardware       = NULL;
454         wblock->data.section.shb_os             = NULL;
455         wblock->data.section.shb_user_appl      = NULL;
456
457         /* Options */
458         errno = WTAP_ERR_CANT_READ;
459         to_read = bh->block_total_length
460         - (int)sizeof(pcapng_block_header_t)
461         - (int)sizeof (pcapng_section_header_block_t)
462         - (int)sizeof(bh->block_total_length);
463         while(to_read > 0) {
464                 /* read option */
465                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
466                 if (bytes_read <= 0) {
467                         pcapng_debug0("pcapng_read_section_header_block: failed to read option");
468                         return bytes_read;
469                 }
470                 block_read += bytes_read;
471                 to_read -= bytes_read;
472
473                 /* handle option content */
474                 switch(oh.option_code) {
475                     case(0): /* opt_endofopt */
476                         if(to_read != 0) {
477                                 pcapng_debug1("pcapng_read_section_header_block: %u bytes after opt_endofopt", to_read);
478                         }
479                         /* padding should be ok here, just get out of this */
480                         to_read = 0;
481                         break;
482                     case(1): /* opt_comment */
483                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
484                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
485                                 pcapng_debug1("pcapng_read_section_header_block: opt_comment %s", wblock->data.section.opt_comment);
486                         } else {
487                                 pcapng_debug1("pcapng_read_section_header_block: opt_comment length %u seems strange", oh.option_length);
488                         }
489                         break;
490                     case(2): /* shb_hardware */
491                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
492                                 wblock->data.section.shb_hardware = g_strndup(option_content, sizeof(option_content));
493                                 pcapng_debug1("pcapng_read_section_header_block: shb_hardware %s", wblock->data.section.shb_hardware);
494                         } else {
495                                 pcapng_debug1("pcapng_read_section_header_block: shb_hardware length %u seems strange", oh.option_length);
496                         }
497                         break;
498                     case(3): /* shb_os */
499                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
500                                 wblock->data.section.shb_os = g_strndup(option_content, sizeof(option_content));
501                                 pcapng_debug1("pcapng_read_section_header_block: shb_os %s", wblock->data.section.shb_os);
502                         } else {
503                                 pcapng_debug1("pcapng_read_section_header_block: shb_os length %u seems strange", oh.option_length);
504                         }
505                         break;
506                     case(4): /* shb_userappl */
507                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
508                                 wblock->data.section.shb_user_appl = g_strndup(option_content, sizeof(option_content));
509                                 pcapng_debug1("pcapng_read_section_header_block: shb_userappl %s", wblock->data.section.shb_user_appl);
510                         } else {
511                                 pcapng_debug1("pcapng_read_section_header_block: shb_userappl length %u seems strange", oh.option_length);
512                         }
513                         break;
514                     default:
515                         pcapng_debug2("pcapng_read_section_header_block: unknown option %u - ignoring %u bytes",
516                                       oh.option_code, oh.option_length);
517                 }
518         }
519
520         if (pn->interface_data != NULL) {
521                 g_array_free(pn->interface_data, TRUE);
522                 pn->interface_data = NULL;
523                 *err = WTAP_ERR_BAD_RECORD;
524                 *err_info = g_strdup_printf("pcapng: multiple section header blocks not supported.");
525                 return 0;
526         }
527         pn->interface_data = g_array_new(FALSE, FALSE, sizeof(interface_data_t));
528         pn->number_of_interfaces = 0;
529
530         return block_read;
531 }
532
533
534 /* "Interface Description Block" */
535 static int
536 pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
537                            wtapng_block_t *wblock, int *err, gchar **err_info _U_)
538 {
539         guint64 time_units_per_second;
540         int     bytes_read;
541         int     block_read;
542         int to_read;
543         pcapng_interface_description_block_t idb;
544         pcapng_option_header_t oh;
545         interface_data_t int_data;
546         gint encap;
547         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
548
549
550         time_units_per_second = 1000000; /* default */
551         /* read block content */
552         errno = WTAP_ERR_CANT_READ;
553         bytes_read = file_read(&idb, 1, sizeof idb, fh);
554         if (bytes_read != sizeof idb) {
555                 pcapng_debug0("pcapng_read_if_descr_block: failed to read IDB");
556                 *err = file_error(fh);
557                 if (*err != 0)
558                         return -1;
559                 return 0;
560         }
561         block_read = bytes_read;
562
563         /* mandatory values */
564         if (pn->byte_swapped) {
565                 wblock->data.if_descr.link_type = BSWAP16(idb.linktype);
566                 wblock->data.if_descr.snap_len  = BSWAP32(idb.snaplen);
567         } else {
568                 wblock->data.if_descr.link_type = idb.linktype;
569                 wblock->data.if_descr.snap_len  = idb.snaplen;
570         }
571
572         pcapng_debug3("pcapng_read_if_descr_block: IDB link_type %u (%s), snap %u",
573                       wblock->data.if_descr.link_type,
574                       wtap_encap_string(wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type)),
575                       wblock->data.if_descr.snap_len);
576
577         if (wblock->data.if_descr.snap_len > WTAP_MAX_PACKET_SIZE) {
578                 /* This is unrealisitic, but text2pcap currently uses 102400.
579                  * We do not use this value, maybe we should check the
580                  * snap_len of the packets against it. For now, only warn.
581                  */
582                 pcapng_debug1("pcapng_read_if_descr_block: snapshot length %u unrealistic.",
583                               wblock->data.if_descr.snap_len);
584                 /*wblock->data.if_descr.snap_len = WTAP_MAX_PACKET_SIZE;*/
585         }
586
587         /* Option defaults */
588         wblock->data.if_descr.opt_comment       = NULL;
589         wblock->data.if_descr.if_name           = NULL;
590         wblock->data.if_descr.if_description    = NULL;
591         /* XXX: if_IPv4addr */
592         /* XXX: if_IPv6addr */
593         /* XXX: if_MACaddr */
594         /* XXX: if_EUIaddr */
595         wblock->data.if_descr.if_speed          = 0xFFFFFFFF;   /* "unknown" */
596         wblock->data.if_descr.if_tsresol        = 6;            /* default is 6 for microsecond resolution */
597         wblock->data.if_descr.if_filter         = NULL;
598         wblock->data.if_descr.if_os             = NULL;
599         wblock->data.if_descr.if_fcslen         = -1;           /* unknown or changes between packets */
600         /* XXX: guint64 if_tsoffset; */
601
602
603         /* Options */
604         errno = WTAP_ERR_CANT_READ;
605         to_read = bh->block_total_length
606         - (int)sizeof(pcapng_block_header_t)
607         - (int)sizeof (pcapng_interface_description_block_t)
608         - (int)sizeof(bh->block_total_length);
609         while (to_read > 0) {
610                 /* read option */
611                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
612                 if (bytes_read <= 0) {
613                         pcapng_debug0("pcapng_read_if_descr_block: failed to read option");
614                         return bytes_read;
615                 }
616                 block_read += bytes_read;
617                 to_read -= bytes_read;
618
619                 /* handle option content */
620                 switch(oh.option_code) {
621                     case(0): /* opt_endofopt */
622                         if(to_read != 0) {
623                                 pcapng_debug1("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read);
624                         }
625                         /* padding should be ok here, just get out of this */
626                         to_read = 0;
627                         break;
628                     case(1): /* opt_comment */
629                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
630                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
631                                 pcapng_debug1("pcapng_read_if_descr_block: opt_comment %s", wblock->data.section.opt_comment);
632                         } else {
633                                 pcapng_debug1("pcapng_read_if_descr_block: opt_comment length %u seems strange", oh.option_length);
634                         }
635                         break;
636                     case(2): /* if_name */
637                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
638                                 wblock->data.if_descr.if_name = g_strndup(option_content, sizeof(option_content));
639                                 pcapng_debug1("pcapng_read_if_descr_block: if_name %s", wblock->data.if_descr.if_name);
640                         } else {
641                                 pcapng_debug1("pcapng_read_if_descr_block: if_name length %u seems strange", oh.option_length);
642                         }
643                         break;
644                     case(3): /* if_description */
645                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
646                             wblock->data.if_descr.if_description = g_strndup(option_content, sizeof(option_content));
647                                 pcapng_debug1("pcapng_read_if_descr_block: if_description %s", wblock->data.if_descr.if_description);
648                         } else {
649                                 pcapng_debug1("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length);
650                         }
651                         break;
652                     case(8): /* if_speed */
653                         if(oh.option_length == 8) {
654                                 /*  Don't cast a char[] into a guint64--the
655                                  *  char[] may not be aligned correctly.
656                                  */
657                                 memcpy(&wblock->data.if_descr.if_speed, option_content, sizeof(guint64));
658                                 if(pn->byte_swapped)
659                                         wblock->data.if_descr.if_speed = BSWAP64(wblock->data.if_descr.if_speed);
660                                 pcapng_debug1("pcapng_read_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", wblock->data.if_descr.if_speed);
661                         } else {
662                                     pcapng_debug1("pcapng_read_if_descr_block: if_speed length %u not 8 as expected", oh.option_length);
663                         }
664                         break;
665                     case(9): /* if_tsresol */
666                         if (oh.option_length == 1) {
667                                 guint64 base;
668                                 guint64 result;
669                                 guint8 i, exponent;
670
671                                 wblock->data.if_descr.if_tsresol = option_content[0];
672                                 if (wblock->data.if_descr.if_tsresol & 0x80) {
673                                         base = 2;
674                                 } else {
675                                         base = 10;
676                                 }
677                                 exponent = (guint8)(wblock->data.if_descr.if_tsresol & 0x7f);
678                                 if (((base == 2) && (exponent < 64)) || ((base == 10) && (exponent < 20))) {
679                                         result = 1;
680                                         for (i = 0; i < exponent; i++) {
681                                                 result *= base;
682                                         }
683                                         time_units_per_second = result;
684                                 } else {
685                                         time_units_per_second = G_MAXUINT64;
686                                 }
687                                 if (time_units_per_second > (((guint64)1) << 32)) {
688                                         pcapng_debug0("pcapng_open: time conversion might be inaccurate");
689                                 }
690                                 pcapng_debug1("pcapng_read_if_descr_block: if_tsresol %u", wblock->data.if_descr.if_tsresol);
691                         } else {
692                                 pcapng_debug1("pcapng_read_if_descr_block: if_tsresol length %u not 1 as expected", oh.option_length);
693                         }
694                         break;
695                     case(11): /* if_filter */
696                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
697                                 wblock->data.if_descr.if_filter = g_strndup(option_content, sizeof(option_content));
698                                 pcapng_debug1("pcapng_read_if_descr_block: if_filter %s", wblock->data.if_descr.if_filter);
699                         } else {
700                                 pcapng_debug1("pcapng_read_if_descr_block: if_filter length %u seems strange", oh.option_length);
701                         }
702                         break;
703                     case(13): /* if_fcslen */
704                         if(oh.option_length == 1) {
705                                 wblock->data.if_descr.if_fcslen = option_content[0];
706                                 pn->if_fcslen = wblock->data.if_descr.if_fcslen;
707                                 pcapng_debug1("pcapng_read_if_descr_block: if_fcslen %u", wblock->data.if_descr.if_fcslen);
708                                 /* XXX - add sanity check */
709                         } else {
710                                 pcapng_debug1("pcapng_read_if_descr_block: if_fcslen length %u not 1 as expected", oh.option_length);
711                         }
712                         break;
713                     default:
714                         pcapng_debug2("pcapng_read_if_descr_block: unknown option %u - ignoring %u bytes",
715                                       oh.option_code, oh.option_length);
716                 }
717         }
718
719         encap = wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type);
720         if (*wblock->file_encap == WTAP_ENCAP_UNKNOWN) {
721                 *wblock->file_encap = encap;
722         } else {
723                 if (*wblock->file_encap != encap) {
724                         *wblock->file_encap = WTAP_ENCAP_PER_PACKET;
725                 }
726         }
727
728         int_data.wtap_encap = encap;
729         int_data.time_units_per_second = time_units_per_second;
730         g_array_append_val(pn->interface_data, int_data);
731         pn->number_of_interfaces++;
732         return block_read;
733 }
734
735
736 static int
737 pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info _U_, gboolean enhanced)
738 {
739         int bytes_read;
740         int block_read;
741         int to_read;
742         guint64 file_offset64;
743         pcapng_enhanced_packet_block_t epb;
744         pcapng_packet_block_t pb;
745         guint32 block_total_length;
746         pcapng_option_header_t oh;
747         gint wtap_encap;
748         int pseudo_header_len;
749         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
750
751
752         /* "(Enhanced) Packet Block" read fixed part */
753         errno = WTAP_ERR_CANT_READ;
754         if (enhanced) {
755                 bytes_read = file_read(&epb, 1, sizeof epb, fh);
756                 if (bytes_read != sizeof epb) {
757                         pcapng_debug0("pcapng_read_packet_block: failed to read packet data");
758                         *err = file_error(fh);
759                         return 0;
760                 }
761                 block_read = bytes_read;
762
763                 if (pn->byte_swapped) {
764                         wblock->data.packet.interface_id        = BSWAP32(epb.interface_id);
765                         wblock->data.packet.drops_count         = -1; /* invalid */
766                         wblock->data.packet.ts_high             = BSWAP32(epb.timestamp_high);
767                         wblock->data.packet.ts_low              = BSWAP32(epb.timestamp_low);
768                         wblock->data.packet.cap_len             = BSWAP32(epb.captured_len);
769                         wblock->data.packet.packet_len          = BSWAP32(epb.packet_len);
770                 } else {
771                         wblock->data.packet.interface_id        = epb.interface_id;
772                         wblock->data.packet.drops_count         = -1; /* invalid */
773                         wblock->data.packet.ts_high             = epb.timestamp_high;
774                         wblock->data.packet.ts_low              = epb.timestamp_low;
775                         wblock->data.packet.cap_len             = epb.captured_len;
776                         wblock->data.packet.packet_len          = epb.packet_len;
777                 }
778         } else {
779                 bytes_read = file_read(&pb, 1, sizeof pb, fh);
780                 if (bytes_read != sizeof pb) {
781                         pcapng_debug0("pcapng_read_packet_block: failed to read packet data");
782                         *err = file_error(fh);
783                         return 0;
784                 }
785                 block_read = bytes_read;
786
787                 if (pn->byte_swapped) {
788                         wblock->data.packet.interface_id        = BSWAP16(pb.interface_id);
789                         wblock->data.packet.drops_count         = BSWAP16(pb.drops_count);
790                         wblock->data.packet.ts_high             = BSWAP32(pb.timestamp_high);
791                         wblock->data.packet.ts_low              = BSWAP32(pb.timestamp_low);
792                         wblock->data.packet.cap_len             = BSWAP32(pb.captured_len);
793                         wblock->data.packet.packet_len          = BSWAP32(pb.packet_len);
794                 } else {
795                         wblock->data.packet.interface_id        = pb.interface_id;
796                         wblock->data.packet.drops_count         = pb.drops_count;
797                         wblock->data.packet.ts_high             = pb.timestamp_high;
798                         wblock->data.packet.ts_low              = pb.timestamp_low;
799                         wblock->data.packet.cap_len             = pb.captured_len;
800                         wblock->data.packet.packet_len          = pb.packet_len;
801                 }
802         }
803
804         if (wblock->data.packet.cap_len > wblock->data.packet.packet_len) {
805                 *err = WTAP_ERR_BAD_RECORD;
806                 *err_info = g_strdup_printf("pcapng_read_packet_block: cap_len %u is larger than packet_len %u.",
807                     wblock->data.packet.cap_len, wblock->data.packet.packet_len);
808                 return 0;
809         }
810         if (wblock->data.packet.cap_len > WTAP_MAX_PACKET_SIZE) {
811                 *err = WTAP_ERR_BAD_RECORD;
812                 *err_info = g_strdup_printf("pcapng_read_packet_block: cap_len %u is larger than WTAP_MAX_PACKET_SIZE %u.",
813                     wblock->data.packet.cap_len, WTAP_MAX_PACKET_SIZE);
814                 return 0;
815         }
816         pcapng_debug3("pcapng_read_packet_block: packet data: packet_len %u captured_len %u interface_id %u",
817                       wblock->data.packet.packet_len,
818                       wblock->data.packet.cap_len,
819                       wblock->data.packet.interface_id);
820         if (wblock->data.packet.packet_len > WTAP_MAX_PACKET_SIZE) {
821                 *err = WTAP_ERR_BAD_RECORD;
822                 *err_info = g_strdup_printf("pcapng_read_packet_block: packet_len %u is larger than WTAP_MAX_PACKET_SIZE %u.",
823                     wblock->data.packet.packet_len, WTAP_MAX_PACKET_SIZE);
824                 return 0;
825         }
826
827         wtap_encap = pcapng_get_encap(wblock->data.packet.interface_id, pn);
828         pcapng_debug3("pcapng_read_packet_block: encapsulation = %d (%s), pseudo header size = %d.",
829                        wtap_encap,
830                        wtap_encap_string(wtap_encap),
831                        pcap_get_phdr_size(wtap_encap, wblock->pseudo_header));
832
833         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
834         pseudo_header_len = pcap_process_pseudo_header(fh,
835                                                        WTAP_FILE_PCAPNG,
836                                                        wtap_encap,
837                                                        wblock->data.packet.cap_len,
838                                                        TRUE,
839                                                        wblock->packet_header,
840                                                        (union wtap_pseudo_header *)wblock->pseudo_header,
841                                                        err,
842                                                        err_info);
843         if (pseudo_header_len < 0) {
844                 return 0;
845         }
846         wblock->data.packet.pseudo_header_len = (guint32)pseudo_header_len;
847         block_read += pseudo_header_len;
848         if (pseudo_header_len != pcap_get_phdr_size(wtap_encap, wblock->pseudo_header)) {
849                 pcapng_debug1("pcapng_read_packet_block: Could only read %d bytes for pseudo header.",
850                               pseudo_header_len);
851         }
852
853         /* "(Enhanced) Packet Block" read capture data */
854         errno = WTAP_ERR_CANT_READ;
855         bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.packet.cap_len - pseudo_header_len, fh);
856         if (bytes_read != (int) (wblock->data.packet.cap_len - pseudo_header_len)) {
857                 *err = file_error(fh);
858                 pcapng_debug1("pcapng_read_packet_block: couldn't read %u bytes of captured data",
859                               wblock->data.packet.cap_len - pseudo_header_len);
860                 if (*err == 0)
861                         *err = WTAP_ERR_SHORT_READ;
862                 return 0;
863         }
864         block_read += bytes_read;
865
866         /* jump over potential padding bytes at end of the packet data */
867         if( (wblock->data.packet.cap_len % 4) != 0) {
868                 file_offset64 = file_seek(fh, 4 - (wblock->data.packet.cap_len % 4), SEEK_CUR, err);
869                 if (file_offset64 <= 0) {
870                         if (*err != 0)
871                                 return -1;
872                         return 0;
873                 }
874                 block_read += 4 - (wblock->data.packet.cap_len % 4);
875         }
876
877         /* add padding bytes to "block total length" */
878         /* (the "block total length" of some example files don't contain the packet data padding bytes!) */
879         if (bh->block_total_length % 4) {
880                 block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
881         } else {
882                 block_total_length = bh->block_total_length;
883         }
884
885         /* Option defaults */
886         wblock->data.packet.opt_comment = NULL;
887         wblock->data.packet.drop_count  = -1;
888         wblock->data.packet.pack_flags  = 0;    /* XXX - is 0 ok to signal "not used"? */
889
890         /* Options */
891         errno = WTAP_ERR_CANT_READ;
892         to_read = block_total_length
893         - (int)sizeof(pcapng_block_header_t)
894         - block_read    /* fixed and variable part, including padding */
895         - (int)sizeof(bh->block_total_length);
896         while(to_read > 0) {
897                 /* read option */
898                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
899                 if (bytes_read <= 0) {
900                         pcapng_debug0("pcapng_read_packet_block: failed to read option");
901                         return bytes_read;
902                 }
903                 block_read += bytes_read;
904                 to_read -= bytes_read;
905
906                 /* handle option content */
907                 switch(oh.option_code) {
908                     case(0): /* opt_endofopt */
909                         if(to_read != 0) {
910                                 pcapng_debug1("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read);
911                         }
912                         /* padding should be ok here, just get out of this */
913                         to_read = 0;
914                         break;
915                     case(1): /* opt_comment */
916                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
917                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
918                                 pcapng_debug1("pcapng_read_packet_block: opt_comment %s", wblock->data.section.opt_comment);
919                         } else {
920                                 pcapng_debug1("pcapng_read_packet_block: opt_comment length %u seems strange", oh.option_length);
921                         }
922                         break;
923                     case(2): /* pack_flags / epb_flags */
924                         if(oh.option_length == 4) {
925                                 /*  Don't cast a char[] into a guint32--the
926                                  *  char[] may not be aligned correctly.
927                                  */
928                                 memcpy(&wblock->data.packet.pack_flags, option_content, sizeof(guint32));
929                                 if(pn->byte_swapped)
930                                         wblock->data.packet.pack_flags = BSWAP32(wblock->data.packet.pack_flags);
931                                 pcapng_debug1("pcapng_read_if_descr_block: pack_flags %u (ignored)", wblock->data.packet.pack_flags);
932                         } else {
933                                 pcapng_debug1("pcapng_read_if_descr_block: pack_flags length %u not 4 as expected", oh.option_length);
934                         }
935                         break;
936                     default:
937                         pcapng_debug2("pcapng_read_packet_block: unknown option %u - ignoring %u bytes",
938                                       oh.option_code, oh.option_length);
939                 }
940         }
941
942         pcap_read_post_process(wtap_encap,
943             (int) (wblock->data.packet.cap_len - pseudo_header_len),
944             pn->byte_swapped, (guchar *) (wblock->frame_buffer));
945         return block_read;
946 }
947
948
949 static int
950 pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info _U_)
951 {
952         int bytes_read;
953         int block_read;
954         guint64 file_offset64;
955         gint encap;
956         int pseudo_header_len;
957         pcapng_simple_packet_block_t spb;
958
959
960         /* "Simple Packet Block" read fixed part */
961         errno = WTAP_ERR_CANT_READ;
962         bytes_read = file_read(&spb, 1, sizeof spb, fh);
963         if (bytes_read != sizeof spb) {
964                 pcapng_debug0("pcapng_read_simple_packet_block: failed to read packet data");
965                 *err = file_error(fh);
966                 return 0;
967         }
968         block_read = bytes_read;
969
970         if (pn->byte_swapped) {
971                 wblock->data.simple_packet.packet_len   = BSWAP32(spb.packet_len);
972         } else {
973                 wblock->data.simple_packet.packet_len   = spb.packet_len;
974         }
975
976         wblock->data.simple_packet.cap_len = bh->block_total_length
977                                              - (guint32)sizeof(pcapng_simple_packet_block_t)
978                                              - (guint32)sizeof(bh->block_total_length);
979
980         if (wblock->data.simple_packet.cap_len > WTAP_MAX_PACKET_SIZE) {
981                 *err = WTAP_ERR_BAD_RECORD;
982                 *err_info = g_strdup_printf("pcapng_read_simple_packet_block: cap_len %u is larger than WTAP_MAX_PACKET_SIZE %u.",
983                     wblock->data.simple_packet.cap_len, WTAP_MAX_PACKET_SIZE);
984                 return 0;
985         }
986         pcapng_debug1("pcapng_read_simple_packet_block: packet data: packet_len %u",
987                        wblock->data.simple_packet.packet_len);
988         if (wblock->data.simple_packet.packet_len > WTAP_MAX_PACKET_SIZE) {
989                 *err = WTAP_ERR_BAD_RECORD;
990                 *err_info = g_strdup_printf("pcapng_read_simple_packet_block: packet_len %u is larger than WTAP_MAX_PACKET_SIZE %u.",
991                     wblock->data.simple_packet.packet_len, WTAP_MAX_PACKET_SIZE);
992                 return 0;
993         }
994
995         encap = pcapng_get_encap(0, pn);
996         pcapng_debug1("pcapng_read_simple_packet_block: Need to read pseudo header of size %d",
997                       pcap_get_phdr_size(encap, wblock->pseudo_header));
998
999         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
1000         pseudo_header_len = pcap_process_pseudo_header(fh,
1001                                                        WTAP_FILE_PCAPNG,
1002                                                        encap,
1003                                                        wblock->data.simple_packet.cap_len,
1004                                                        TRUE,
1005                                                        wblock->packet_header,
1006                                                        (union wtap_pseudo_header *)wblock->pseudo_header,
1007                                                        err,
1008                                                        err_info);
1009         if (pseudo_header_len < 0) {
1010                 return 0;
1011         }
1012         wblock->data.simple_packet.pseudo_header_len = (guint32)pseudo_header_len;
1013         block_read += pseudo_header_len;
1014         if (pseudo_header_len != pcap_get_phdr_size(encap, wblock->pseudo_header)) {
1015                 pcapng_debug1("pcapng_read_simple_packet_block: Could only read %d bytes for pseudo header.",
1016                               pseudo_header_len);
1017         }
1018
1019         /* XXX - implement other linktypes then Ethernet */
1020         /* (or even better share the code with libpcap.c) */
1021
1022         /* Ethernet FCS length, might be overwritten by "per packet" options */
1023         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
1024         ((union wtap_pseudo_header *) wblock->pseudo_header)->eth.fcs_len = pn->if_fcslen;
1025
1026         /* "Simple Packet Block" read capture data */
1027         errno = WTAP_ERR_CANT_READ;
1028         bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.simple_packet.cap_len, fh);
1029         if (bytes_read != (int) wblock->data.simple_packet.cap_len) {
1030                 *err = file_error(fh);
1031                 pcapng_debug1("pcapng_read_simple_packet_block: couldn't read %u bytes of captured data",
1032                               wblock->data.simple_packet.cap_len);
1033                 if (*err == 0)
1034                         *err = WTAP_ERR_SHORT_READ;
1035                 return 0;
1036         }
1037         block_read += bytes_read;
1038
1039         /* jump over potential padding bytes at end of the packet data */
1040         if ((wblock->data.simple_packet.cap_len % 4) != 0) {
1041                 file_offset64 = file_seek(fh, 4 - (wblock->data.simple_packet.cap_len % 4), SEEK_CUR, err);
1042                 if (file_offset64 <= 0) {
1043                         if (*err != 0)
1044                                 return -1;
1045                         return 0;
1046                 }
1047                 block_read += 4 - (wblock->data.simple_packet.cap_len % 4);
1048         }
1049
1050         pcap_read_post_process(encap, (int) wblock->data.simple_packet.cap_len,
1051             pn->byte_swapped, (guchar *) (wblock->frame_buffer));
1052         return block_read;
1053 }
1054
1055 static int
1056 pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info _U_)
1057 {
1058         int bytes_read;
1059         int block_read;
1060         int to_read;
1061         pcapng_interface_statistics_block_t isb;
1062         pcapng_option_header_t oh;
1063         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
1064
1065
1066         /* "Interface Statistics Block" read fixed part */
1067         errno = WTAP_ERR_CANT_READ;
1068         bytes_read = file_read(&isb, 1, sizeof isb, fh);
1069         if (bytes_read != sizeof isb) {
1070                 pcapng_debug0("pcapng_read_interface_statistics_block: failed to read packet data");
1071                 *err = file_error(fh);
1072                 return 0;
1073         }
1074         block_read = bytes_read;
1075
1076         if(pn->byte_swapped) {
1077                 wblock->data.if_stats.interface_id      = BSWAP64(isb.interface_id);
1078                 wblock->data.if_stats.ts_high           = BSWAP32(isb.timestamp_high);
1079                 wblock->data.if_stats.ts_low            = BSWAP32(isb.timestamp_low);
1080         } else {
1081                 wblock->data.if_stats.interface_id      = isb.interface_id;
1082                 wblock->data.if_stats.ts_high           = isb.timestamp_high;
1083                 wblock->data.if_stats.ts_low            = isb.timestamp_low;
1084         }
1085         pcapng_debug1("pcapng_read_interface_statistics_block: interface_id %" G_GINT64_MODIFIER "u", wblock->data.if_stats.interface_id);
1086
1087         /* Option defaults */
1088         wblock->data.if_stats.opt_comment = NULL;
1089         wblock->data.if_stats.isb_ifrecv  = -1;
1090         wblock->data.if_stats.isb_ifdrop  = -1;
1091
1092         /* Options */
1093         errno = WTAP_ERR_CANT_READ;
1094         to_read = bh->block_total_length
1095         - sizeof(pcapng_block_header_t)
1096         - block_read    /* fixed and variable part, including padding */
1097         - sizeof(bh->block_total_length);
1098         while(to_read > 0) {
1099                 /* read option */
1100                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
1101                 if (bytes_read <= 0) {
1102                         pcapng_debug0("pcapng_read_interface_statistics_block: failed to read option");
1103                         return bytes_read;
1104                 }
1105                 block_read += bytes_read;
1106                 to_read -= bytes_read;
1107
1108                 /* handle option content */
1109                 switch(oh.option_code) {
1110                     case(0): /* opt_endofopt */
1111                         if(to_read != 0) {
1112                                 pcapng_debug1("pcapng_read_interface_statistics_block: %u bytes after opt_endofopt", to_read);
1113                         }
1114                         /* padding should be ok here, just get out of this */
1115                         to_read = 0;
1116                         break;
1117                     case(1): /* opt_comment */
1118                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
1119                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
1120                                 pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment %s", wblock->data.section.opt_comment);
1121                         } else {
1122                                 pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment length %u seems strange", oh.option_length);
1123                         }
1124                         break;
1125                     case(4): /* isb_ifrecv */
1126                         if(oh.option_length == 8) {
1127                                 /*  Don't cast a char[] into a guint32--the
1128                                  *  char[] may not be aligned correctly.
1129                                  */
1130                                 memcpy(&wblock->data.if_stats.isb_ifrecv, option_content, sizeof(guint64));
1131                                 if(pn->byte_swapped)
1132                                         wblock->data.if_stats.isb_ifrecv = BSWAP64(wblock->data.if_stats.isb_ifrecv);
1133                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifrecv);
1134                         } else {
1135                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv length %u not 8 as expected", oh.option_length);
1136                         }
1137                         break;
1138                     case(5): /* isb_ifdrop */
1139                         if(oh.option_length == 8) {
1140                                 /*  Don't cast a char[] into a guint32--the
1141                                  *  char[] may not be aligned correctly.
1142                                  */
1143                                 memcpy(&wblock->data.if_stats.isb_ifdrop, option_content, sizeof(guint64));
1144                                 if(pn->byte_swapped)
1145                                         wblock->data.if_stats.isb_ifdrop = BSWAP64(wblock->data.if_stats.isb_ifdrop);
1146                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifdrop);
1147                         } else {
1148                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop length %u not 8 as expected", oh.option_length);
1149                         }
1150                         break;
1151                     default:
1152                         pcapng_debug2("pcapng_read_interface_statistics_block: unknown option %u - ignoring %u bytes",
1153                                       oh.option_code, oh.option_length);
1154                 }
1155         }
1156
1157     return block_read;
1158 }
1159
1160
1161 static int
1162 pcapng_read_unknown_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn _U_, wtapng_block_t *wblock _U_,int *err, gchar **err_info _U_)
1163 {
1164         int block_read;
1165         guint64 file_offset64;
1166         guint32 block_total_length;
1167
1168
1169         /* add padding bytes to "block total length" */
1170         /* (the "block total length" of some example files don't contain any padding bytes!) */
1171         if (bh->block_total_length % 4) {
1172                 block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
1173         } else {
1174                 block_total_length = bh->block_total_length;
1175         }
1176
1177         block_read = block_total_length - (guint32)sizeof(pcapng_block_header_t) - (guint32)sizeof(bh->block_total_length);
1178
1179         /* jump over this unknown block */
1180         file_offset64 = file_seek(fh, block_read, SEEK_CUR, err);
1181         if (file_offset64 <= 0) {
1182                 if (*err != 0)
1183                         return -1;
1184                 return 0;
1185         }
1186
1187         return block_read;
1188 }
1189
1190
1191 static int
1192 pcapng_read_block(FILE_T fh, gboolean first_block, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
1193 {
1194         int block_read;
1195         int bytes_read;
1196         pcapng_block_header_t bh;
1197         guint32 block_total_length;
1198
1199
1200         /* Try to read the (next) block header */
1201         errno = WTAP_ERR_CANT_READ;
1202         bytes_read = file_read(&bh, 1, sizeof bh, fh);
1203         if (bytes_read != sizeof bh) {
1204                 pcapng_debug0("pcapng_read_block: end of file or error");
1205                 *err = file_error(fh);
1206                 if (*err != 0)
1207                         return -1;
1208                 return 0;
1209         }
1210
1211         block_read = bytes_read;
1212         if (pn->byte_swapped) {
1213                 bh.block_type         = BSWAP32(bh.block_type);
1214                 bh.block_total_length = BSWAP32(bh.block_total_length);
1215         }
1216
1217         wblock->type = bh.block_type;
1218
1219         pcapng_debug1("pcapng_read_block: block_type 0x%x", bh.block_type);
1220
1221         if (first_block) {
1222                 /*
1223                  * This is being read in by pcapng_open(), so this block
1224                  * must be an SHB.  If it's not, this is not a pcap-ng
1225                  * file.
1226                  *
1227                  * XXX - check for various forms of Windows <-> UN*X
1228                  * mangling, and suggest that the file might be a
1229                  * pcap-ng file that was damaged in transit?
1230                  */
1231                 if (bh.block_type != BLOCK_TYPE_SHB)
1232                         return 0;       /* not a pcap-ng file */
1233         }
1234
1235         switch(bh.block_type) {
1236                 case(BLOCK_TYPE_SHB):
1237                         bytes_read = pcapng_read_section_header_block(fh, first_block, &bh, pn, wblock, err, err_info);
1238                         break;
1239                 case(BLOCK_TYPE_IDB):
1240                         bytes_read = pcapng_read_if_descr_block(fh, &bh, pn, wblock, err, err_info);
1241                         break;
1242                 case(BLOCK_TYPE_PB):
1243                         bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, FALSE);
1244                         break;
1245                 case(BLOCK_TYPE_SPB):
1246                         bytes_read = pcapng_read_simple_packet_block(fh, &bh, pn, wblock, err, err_info);
1247                         break;
1248                 case(BLOCK_TYPE_EPB):
1249                         bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, TRUE);
1250                         break;
1251                 case(BLOCK_TYPE_ISB):
1252                         bytes_read = pcapng_read_interface_statistics_block(fh, &bh, pn, wblock, err, err_info);
1253                         break;
1254                 default:
1255                         pcapng_debug2("pcapng_read_block: Unknown block_type: 0x%x (block ignored), block total length %d", bh.block_type, bh.block_total_length);
1256                         bytes_read = pcapng_read_unknown_block(fh, &bh, pn, wblock, err, err_info);
1257         }
1258
1259         if (bytes_read <= 0) {
1260                 return bytes_read;
1261         }
1262         block_read += bytes_read;
1263
1264         /* sanity check: first and second block lengths must match */
1265         errno = WTAP_ERR_CANT_READ;
1266         bytes_read = file_read(&block_total_length, 1, sizeof block_total_length, fh);
1267         if (bytes_read != sizeof block_total_length) {
1268                 pcapng_debug0("pcapng_read_block: couldn't read second block length");
1269                 *err = file_error(fh);
1270                 if (*err == 0)
1271                         *err = WTAP_ERR_SHORT_READ;
1272                 return -1;
1273         }
1274         block_read += bytes_read;
1275
1276         if (pn->byte_swapped)
1277                 block_total_length = BSWAP32(block_total_length);
1278
1279         if (!(block_total_length == bh.block_total_length)) {
1280                 *err = WTAP_ERR_BAD_RECORD;
1281                 *err_info = g_strdup_printf("pcapng_read_block: total block lengths (first %u and second %u) don't match",
1282                               bh.block_total_length, block_total_length);
1283                 return -1;
1284         }
1285
1286         return block_read;
1287 }
1288
1289
1290 /* classic wtap: open capture file */
1291 int
1292 pcapng_open(wtap *wth, int *err, gchar **err_info)
1293 {
1294         int bytes_read;
1295         pcapng_t pn;
1296         wtapng_block_t wblock;
1297         pcapng_t *pcapng;
1298
1299         /* we don't know the byte swapping of the file yet */
1300         pn.byte_swapped = FALSE;
1301         pn.if_fcslen = -1;
1302         pn.version_major = -1;
1303         pn.version_minor = -1;
1304         pn.interface_data = NULL;
1305         pn.number_of_interfaces = 0;
1306
1307         /* we don't expect any packet blocks yet */
1308         wblock.frame_buffer = NULL;
1309         wblock.pseudo_header = NULL;
1310         wblock.packet_header = NULL;
1311         wblock.file_encap = &wth->file_encap;
1312
1313         pcapng_debug0("pcapng_open: opening file");
1314         /* read first block */
1315         bytes_read = pcapng_read_block(wth->fh, TRUE, &pn, &wblock, err, err_info);
1316         if (bytes_read <= 0) {
1317                 pcapng_debug0("pcapng_open: couldn't read first SHB");
1318                 *err = file_error(wth->fh);
1319                 if (*err != 0)
1320                         return -1;
1321                 return 0;
1322         }
1323         wth->data_offset += bytes_read;
1324
1325         /* first block must be a "Section Header Block" */
1326         if (wblock.type != BLOCK_TYPE_SHB) {
1327                 /*
1328                  * XXX - check for damage from transferring a file
1329                  * between Windows and UN*X as text rather than
1330                  * binary data?
1331                  */
1332                 pcapng_debug1("pcapng_open: first block type %u not SHB", wblock.type);
1333                 return 0;
1334         }
1335
1336         wth->file_encap = WTAP_ENCAP_UNKNOWN;
1337         wth->snapshot_length = 0;
1338         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
1339         pcapng = (pcapng_t *)g_malloc(sizeof(pcapng_t));
1340         wth->priv = (void *)pcapng;
1341         *pcapng = pn;
1342         wth->subtype_read = pcapng_read;
1343         wth->subtype_seek_read = pcapng_seek_read;
1344         wth->subtype_close = pcapng_close;
1345         wth->file_type = WTAP_FILE_PCAPNG;
1346
1347         return 1;
1348 }
1349
1350
1351 /* classic wtap: read packet */
1352 static gboolean
1353 pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
1354 {
1355         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1356         int bytes_read;
1357         guint64 ts;
1358         wtapng_block_t wblock;
1359
1360         pcapng_debug1("pcapng_read: wth->data_offset is initially %" G_GINT64_MODIFIER "u", wth->data_offset);
1361         *data_offset = wth->data_offset;
1362         pcapng_debug1("pcapng_read: *data_offset is initially set to %" G_GINT64_MODIFIER "u", *data_offset);
1363
1364         /* XXX - This should be done in the packet block reading function and
1365          * should make use of the caplen of the packet.
1366          */
1367         if (wth->snapshot_length > 0) {
1368                 buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
1369         } else {
1370                 buffer_assure_space(wth->frame_buffer, WTAP_MAX_PACKET_SIZE);
1371         }
1372
1373         wblock.frame_buffer  = buffer_start_ptr(wth->frame_buffer);
1374         wblock.pseudo_header = &wth->pseudo_header;
1375         wblock.packet_header = &wth->phdr;
1376         wblock.file_encap    = &wth->file_encap;
1377
1378         /* read next block */
1379         while (1) {
1380                 bytes_read = pcapng_read_block(wth->fh, FALSE, pcapng, &wblock, err, err_info);
1381                 if (bytes_read <= 0) {
1382                         pcapng_debug0("pcapng_read: couldn't read packet block");
1383                         return FALSE;
1384                 }
1385
1386                 /* block must be a "Packet Block" or an "Enhanced Packet Block" -> otherwise continue */
1387                 if (wblock.type == BLOCK_TYPE_PB || wblock.type == BLOCK_TYPE_EPB) {
1388                         break;
1389                 }
1390
1391                 /* XXX - improve handling of "unknown" blocks */
1392                 pcapng_debug1("pcapng_read: block type 0x%x not PB/EPB", wblock.type);
1393                 *data_offset += bytes_read;
1394                 pcapng_debug1("pcapng_read: *data_offset is updated to %" G_GINT64_MODIFIER "u", *data_offset);
1395         }
1396
1397         /* Combine the two 32-bit pieces of the timestamp into one 64-bit value */
1398         ts = (((guint64)wblock.data.packet.ts_high) << 32) | ((guint64)wblock.data.packet.ts_low);
1399
1400         wth->phdr.caplen = wblock.data.packet.cap_len - wblock.data.packet.pseudo_header_len;
1401         wth->phdr.len = wblock.data.packet.packet_len - wblock.data.packet.pseudo_header_len;
1402         if (wblock.data.packet.interface_id < pcapng->number_of_interfaces) {
1403                 interface_data_t int_data;
1404                 guint64 time_units_per_second;
1405                 gint id;
1406
1407                 id = (gint)wblock.data.packet.interface_id;
1408                 int_data = g_array_index(pcapng->interface_data, interface_data_t, id);
1409                 time_units_per_second = int_data.time_units_per_second;
1410                 wth->phdr.pkt_encap = int_data.wtap_encap;
1411                 wth->phdr.ts.secs = (time_t)(ts / time_units_per_second);
1412                 wth->phdr.ts.nsecs = (int)(((ts % time_units_per_second) * 1000000000) / time_units_per_second);
1413         } else {
1414                 wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
1415                 *err = WTAP_ERR_BAD_RECORD;
1416                 *err_info = g_strdup_printf("pcapng: interface index %u is not less than interface count %u.",
1417                     wblock.data.packet.interface_id, pcapng->number_of_interfaces);
1418                 return FALSE;
1419         }
1420
1421         /*pcapng_debug2("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/
1422         wth->data_offset = *data_offset + bytes_read;
1423         pcapng_debug1("pcapng_read: wth->data_offset is finally %" G_GINT64_MODIFIER "u", wth->data_offset);
1424
1425         return TRUE;
1426 }
1427
1428
1429 /* classic wtap: seek to file position and read packet */
1430 static gboolean
1431 pcapng_seek_read(wtap *wth, gint64 seek_off,
1432     union wtap_pseudo_header *pseudo_header, guchar *pd, int length _U_,
1433     int *err, gchar **err_info)
1434 {
1435         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1436         guint64 bytes_read64;
1437         int bytes_read;
1438         wtapng_block_t wblock;
1439
1440
1441         /* seek to the right file position */
1442         bytes_read64 = file_seek(wth->random_fh, seek_off, SEEK_SET, err);
1443         if (bytes_read64 <= 0) {
1444                 return FALSE;   /* Seek error */
1445         }
1446         pcapng_debug1("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
1447
1448         wblock.frame_buffer = pd;
1449         wblock.pseudo_header = pseudo_header;
1450         wblock.packet_header = &wth->phdr;
1451         wblock.file_encap = &wth->file_encap;
1452
1453         /* read the block */
1454         bytes_read = pcapng_read_block(wth->random_fh, FALSE, pcapng, &wblock, err, err_info);
1455         if (bytes_read <= 0) {
1456                 *err = file_error(wth->random_fh);
1457                 pcapng_debug3("pcapng_seek_read: couldn't read packet block (err=%d, errno=%d, bytes_read=%d).",
1458                               *err, errno, bytes_read);
1459                 return FALSE;
1460         }
1461
1462         /* block must be a "Packet Block" or an "Enhanced Packet Block" */
1463         if (wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB) {
1464                 pcapng_debug1("pcapng_seek_read: block type %u not PB/EPB", wblock.type);
1465                 return FALSE;
1466         }
1467
1468         return TRUE;
1469 }
1470
1471
1472 /* classic wtap: close capture file */
1473 static void
1474 pcapng_close(wtap *wth)
1475 {
1476         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1477
1478         pcapng_debug0("pcapng_close: closing file");
1479         if (pcapng->interface_data != NULL) {
1480                 g_array_free(pcapng->interface_data, TRUE);
1481         }
1482 }
1483
1484
1485
1486 typedef struct {
1487         GArray *interface_data;
1488         guint number_of_interfaces;
1489 } pcapng_dump_t;
1490
1491 static gboolean
1492 pcapng_write_section_header_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1493 {
1494         pcapng_block_header_t bh;
1495         pcapng_section_header_block_t shb;
1496
1497
1498         /* write block header */
1499         bh.block_type = wblock->type;
1500         bh.block_total_length = sizeof(bh) + sizeof(shb) /* + options */ + 4;
1501
1502         if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
1503                 return FALSE;
1504         wdh->bytes_dumped += sizeof bh;
1505
1506         /* write block fixed content */
1507         /* XXX - get these values from wblock? */
1508         shb.magic = 0x1A2B3C4D;
1509         shb.version_major = 1;
1510         shb.version_minor = 0;
1511         shb.section_length = -1;
1512
1513         if (!wtap_dump_file_write(wdh, &shb, sizeof shb, err))
1514                 return FALSE;
1515         wdh->bytes_dumped += sizeof shb;
1516
1517         /* XXX - write (optional) block options */
1518
1519         /* write block footer */
1520         if (!wtap_dump_file_write(wdh, &bh.block_total_length,
1521             sizeof bh.block_total_length, err))
1522                 return FALSE;
1523         wdh->bytes_dumped += sizeof bh.block_total_length;
1524
1525         return TRUE;
1526 }
1527
1528
1529
1530 static gboolean
1531 pcapng_write_if_descr_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1532 {
1533         pcapng_block_header_t bh;
1534         pcapng_interface_description_block_t idb;
1535
1536
1537         pcapng_debug3("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d",
1538                       wblock->data.if_descr.link_type,
1539                       wtap_encap_string(wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type)),
1540                       wblock->data.if_descr.snap_len);
1541
1542         if (wblock->data.if_descr.link_type == (guint16)-1) {
1543                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
1544                 return FALSE;
1545         }
1546
1547         /* write block header */
1548         bh.block_type = wblock->type;
1549         bh.block_total_length = sizeof(bh) + sizeof(idb) /* + options */ + 4;
1550
1551         if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
1552                 return FALSE;
1553         wdh->bytes_dumped += sizeof bh;
1554
1555         /* write block fixed content */
1556         idb.linktype    = wblock->data.if_descr.link_type;
1557         idb.reserved    = 0;
1558         idb.snaplen     = wblock->data.if_descr.snap_len;
1559
1560         if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err))
1561                 return FALSE;
1562         wdh->bytes_dumped += sizeof idb;
1563
1564         /* XXX - write (optional) block options */
1565
1566         /* write block footer */
1567         if (!wtap_dump_file_write(wdh, &bh.block_total_length,
1568             sizeof bh.block_total_length, err))
1569                 return FALSE;
1570         wdh->bytes_dumped += sizeof bh.block_total_length;
1571
1572         return TRUE;
1573 }
1574
1575
1576 static gboolean
1577 pcapng_write_packet_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1578 {
1579         pcapng_block_header_t bh;
1580         pcapng_enhanced_packet_block_t epb;
1581         const guint32 zero_pad = 0;
1582         guint32 pad_len;
1583         guint32 phdr_len;
1584
1585         phdr_len = (guint32)pcap_get_phdr_size(wblock->data.packet.wtap_encap, wblock->pseudo_header);
1586         if ((phdr_len + wblock->data.packet.cap_len) % 4) {
1587                 pad_len = 4 - ((phdr_len + wblock->data.packet.cap_len) % 4);
1588         } else {
1589                 pad_len = 0;
1590         }
1591
1592         /* write (enhanced) packet block header */
1593         bh.block_type = wblock->type;
1594         bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + wblock->data.packet.cap_len + pad_len /* + options */ + 4;
1595
1596         if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
1597                 return FALSE;
1598         wdh->bytes_dumped += sizeof bh;
1599
1600         /* write block fixed content */
1601         epb.interface_id        = wblock->data.packet.interface_id;
1602         epb.timestamp_high      = wblock->data.packet.ts_high;
1603         epb.timestamp_low       = wblock->data.packet.ts_low;
1604         epb.captured_len        = wblock->data.packet.cap_len + phdr_len;
1605         epb.packet_len          = wblock->data.packet.packet_len + phdr_len;
1606
1607         if (!wtap_dump_file_write(wdh, &epb, sizeof epb, err))
1608                 return FALSE;
1609         wdh->bytes_dumped += sizeof epb;
1610
1611         /* write pseudo header */
1612         if (!pcap_write_phdr(wdh, wblock->data.packet.wtap_encap, wblock->pseudo_header, err)) {
1613                 return FALSE;
1614         }
1615         wdh->bytes_dumped += phdr_len;
1616
1617         /* write packet data */
1618         if (!wtap_dump_file_write(wdh, wblock->frame_buffer,
1619             wblock->data.packet.cap_len, err))
1620                 return FALSE;
1621         wdh->bytes_dumped += wblock->data.packet.cap_len;
1622
1623         /* write padding (if any) */
1624         if (pad_len != 0) {
1625                 if (!wtap_dump_file_write(wdh, &zero_pad, pad_len, err))
1626                         return FALSE;
1627                 wdh->bytes_dumped += pad_len;
1628         }
1629
1630         /* XXX - write (optional) block options */
1631
1632         /* write block footer */
1633         if (!wtap_dump_file_write(wdh, &bh.block_total_length,
1634             sizeof bh.block_total_length, err))
1635                 return FALSE;
1636         wdh->bytes_dumped += sizeof bh.block_total_length;
1637
1638         return TRUE;
1639 }
1640
1641
1642 static gboolean
1643 pcapng_write_block(wtap_dumper *wdh, /*pcapng_t *pn, */wtapng_block_t *wblock, int *err)
1644 {
1645         switch(wblock->type) {
1646             case(BLOCK_TYPE_SHB):
1647                 return pcapng_write_section_header_block(wdh, wblock, err);
1648             case(BLOCK_TYPE_IDB):
1649                 return pcapng_write_if_descr_block(wdh, wblock, err);
1650             case(BLOCK_TYPE_PB):
1651                 /* Packet Block is obsolete */
1652                 return FALSE;
1653             case(BLOCK_TYPE_EPB):
1654                 return pcapng_write_packet_block(wdh, wblock, err);
1655             default:
1656                 pcapng_debug1("Unknown block_type: 0x%x", wblock->type);
1657                 return FALSE;
1658         }
1659 }
1660
1661
1662 static guint32
1663 pcapng_lookup_interface_id_by_encap(int wtap_encap, wtap_dumper *wdh)
1664 {
1665         gint i;
1666         interface_data_t int_data;
1667         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1668
1669         for(i = 0; i < (gint)pcapng->number_of_interfaces; i++) {
1670                 int_data = g_array_index(pcapng->interface_data, interface_data_t, i);
1671                 if (wtap_encap == int_data.wtap_encap) {
1672                         return (guint32)i;
1673                 }
1674         }
1675         return G_MAXUINT32;
1676 }
1677
1678
1679 static gboolean pcapng_dump(wtap_dumper *wdh,
1680         const struct wtap_pkthdr *phdr,
1681         const union wtap_pseudo_header *pseudo_header,
1682         const guchar *pd, int *err)
1683 {
1684         wtapng_block_t wblock;
1685         interface_data_t int_data;
1686         guint32 interface_id;
1687         guint64 ts;
1688         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1689
1690         pcapng_debug2("pcapng_dump: encap = %d (%s)",
1691                       phdr->pkt_encap,
1692                       wtap_encap_string(phdr->pkt_encap));
1693
1694         interface_id = pcapng_lookup_interface_id_by_encap(phdr->pkt_encap, wdh);
1695         if (interface_id == G_MAXUINT32) {
1696                 /* write the interface description block */
1697                 wblock.frame_buffer            = NULL;
1698                 wblock.pseudo_header           = NULL;
1699                 wblock.packet_header           = NULL;
1700                 wblock.file_encap              = NULL;
1701                 wblock.type                    = BLOCK_TYPE_IDB;
1702                 wblock.data.if_descr.link_type = wtap_wtap_encap_to_pcap_encap(phdr->pkt_encap);
1703                 wblock.data.if_descr.snap_len  = wdh->snaplen; /* XXX */
1704
1705                 /* XXX - options unused */
1706                 wblock.data.if_descr.if_speed   = -1;
1707                 wblock.data.if_descr.if_tsresol = 6;    /* default: usec */
1708                 wblock.data.if_descr.if_os      = NULL;
1709                 wblock.data.if_descr.if_fcslen  = -1;
1710
1711                 if (!pcapng_write_block(wdh, &wblock, err)) {
1712                         return FALSE;
1713                 }
1714
1715                 interface_id = pcapng->number_of_interfaces;
1716                 int_data.wtap_encap = phdr->pkt_encap;
1717                 int_data.time_units_per_second = 0;
1718                 g_array_append_val(pcapng->interface_data, int_data);
1719                 pcapng->number_of_interfaces++;
1720
1721                 pcapng_debug3("pcapng_dump: added interface description block with index %u for encap = %d (%s).",
1722                               interface_id,
1723                               phdr->pkt_encap,
1724                               wtap_encap_string(phdr->pkt_encap));
1725         }
1726
1727         wblock.frame_buffer  = pd;
1728         wblock.pseudo_header = pseudo_header;
1729         wblock.packet_header = NULL;
1730         wblock.file_encap    = NULL;
1731
1732         /* write the (enhanced) packet block */
1733         wblock.type = BLOCK_TYPE_EPB;
1734
1735         /* default is to write out in microsecond resolution */
1736         ts = (((guint64)phdr->ts.secs) * 1000000) + (phdr->ts.nsecs / 1000);
1737
1738         /* Split the 64-bit timestamp into two 32-bit pieces */
1739         wblock.data.packet.ts_high      = (guint32)(ts >> 32);
1740         wblock.data.packet.ts_low       = (guint32)ts;
1741
1742         wblock.data.packet.cap_len      = phdr->caplen;
1743         wblock.data.packet.packet_len   = phdr->len;
1744         wblock.data.packet.interface_id = interface_id;
1745         wblock.data.packet.wtap_encap   = phdr->pkt_encap;
1746
1747         /* currently unused */
1748         wblock.data.packet.drop_count   = -1;
1749         wblock.data.packet.opt_comment  = NULL;
1750
1751         if (!pcapng_write_block(wdh, &wblock, err)) {
1752                 return FALSE;
1753         }
1754
1755         return TRUE;
1756 }
1757
1758
1759 /* Finish writing to a dump file.
1760    Returns TRUE on success, FALSE on failure. */
1761 static gboolean pcapng_dump_close(wtap_dumper *wdh, int *err _U_)
1762 {
1763         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1764
1765         pcapng_debug0("pcapng_dump_close");
1766         g_array_free(pcapng->interface_data, TRUE);
1767         pcapng->number_of_interfaces = 0;
1768         return TRUE;
1769 }
1770
1771
1772 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1773    failure */
1774 gboolean
1775 pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
1776 {
1777         wtapng_block_t wblock;
1778         pcapng_dump_t *pcapng;
1779
1780         wblock.frame_buffer  = NULL;
1781         wblock.pseudo_header = NULL;
1782         wblock.packet_header = NULL;
1783         wblock.file_encap    = NULL;
1784
1785         pcapng_debug0("pcapng_dump_open");
1786         /* This is a pcapng file */
1787         wdh->subtype_write = pcapng_dump;
1788         wdh->subtype_close = pcapng_dump_close;
1789         pcapng = (pcapng_dump_t *)g_malloc(sizeof(pcapng_dump_t));
1790         wdh->priv = (void *)pcapng;
1791         pcapng->interface_data = g_array_new(FALSE, FALSE, sizeof(interface_data_t));
1792         pcapng->number_of_interfaces = 0;
1793
1794         /* write the section header block */
1795         wblock.type = BLOCK_TYPE_SHB;
1796         wblock.data.section.section_length = -1;
1797
1798         /* XXX - options unused */
1799         wblock.data.section.opt_comment   = NULL;
1800         wblock.data.section.shb_hardware  = NULL;
1801         wblock.data.section.shb_os        = NULL;
1802         wblock.data.section.shb_user_appl = NULL;
1803
1804         if (!pcapng_write_block(wdh, &wblock, err)) {
1805                 return FALSE;
1806         }
1807         pcapng_debug0("pcapng_dump_open: wrote section header block.");
1808
1809         return TRUE;
1810 }
1811
1812
1813 /* Returns 0 if we could write the specified encapsulation type,
1814    an error indication otherwise. */
1815 int pcapng_dump_can_write_encap(int wtap_encap)
1816 {
1817         pcapng_debug2("pcapng_dump_can_write_encap: encap = %d (%s)",
1818                       wtap_encap,
1819                       wtap_encap_string(wtap_encap));
1820
1821         /* Per-packet encapsulations is supported. */
1822         if (wtap_encap == WTAP_ENCAP_PER_PACKET)
1823                 return 0;
1824
1825         /* Make sure we can figure out this DLT type */
1826         if (wtap_wtap_encap_to_pcap_encap(wtap_encap) == -1)
1827                 return WTAP_ERR_UNSUPPORTED_ENCAP;
1828
1829         return 0;
1830 }