Constify.
[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, pcapng_block_header_t *bh,
361                                  pcapng_t *pn, wtapng_block_t *wblock, int *err,
362                                  gchar **err_info)
363 {
364         int     bytes_read;
365         int     block_read;
366         int to_read;
367         pcapng_section_header_block_t shb;
368         pcapng_option_header_t oh;
369         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
370
371
372         /* read block content */
373         errno = WTAP_ERR_CANT_READ;
374         bytes_read = file_read(&shb, 1, sizeof shb, fh);
375         if (bytes_read != sizeof shb) {
376                 *err = file_error(fh);
377                 if (*err != 0)
378                         return -1;
379                 return 0;
380         }
381         block_read = bytes_read;
382
383         /* is the magic number one we expect? */
384         switch(shb.magic) {
385             case(0x1A2B3C4D):
386                 /* this seems pcapng with correct byte order */
387                 pn->byte_swapped                = FALSE;
388                 pn->version_major               = shb.version_major;
389                 pn->version_minor               = shb.version_minor;
390
391                 pcapng_debug3("pcapng_read_section_header_block: SHB (little endian) V%u.%u, len %u",
392                                 pn->version_major, pn->version_minor, bh->block_total_length);
393                 break;
394             case(0x4D3C2B1A):
395                 /* this seems pcapng with swapped byte order */
396                 pn->byte_swapped                = TRUE;
397                 pn->version_major               = BSWAP16(shb.version_major);
398                 pn->version_minor               = BSWAP16(shb.version_minor);
399                         
400                 /* tweak the block length to meet current swapping that we know now */
401                 bh->block_total_length  = BSWAP32(bh->block_total_length);
402
403                 pcapng_debug3("pcapng_read_section_header_block: SHB (big endian) V%u.%u, len %u",
404                                 pn->version_major, pn->version_minor, bh->block_total_length);
405                 break;
406             default:
407                 /* Not a "pcapng" magic number we know about. */
408                 pcapng_debug1("pcapng_read_section_header_block: unknown magic number %u (probably not an pcapng file)", shb.magic);
409                 return 0;
410         }
411
412         /* we currently only understand SHB V1.0 */
413         if (pn->version_major != 1 || pn->version_minor != 0) {
414                 pcapng_debug2("pcapng_read_section_header_block: unknown SHB version %u.%u", 
415                               pn->version_major, pn->version_minor);
416                 return 0;
417         }
418
419         /* 64bit section_length (currently unused) */
420         if (pn->byte_swapped) {
421                 wblock->data.section.section_length = BSWAP64(shb.section_length);
422         } else {
423                 wblock->data.section.section_length = shb.section_length;
424         }
425
426         /* Option defaults */
427         wblock->data.section.opt_comment        = NULL;
428         wblock->data.section.shb_hardware       = NULL;
429         wblock->data.section.shb_os             = NULL;
430         wblock->data.section.shb_user_appl      = NULL;
431
432         /* Options */
433         errno = WTAP_ERR_CANT_READ;
434         to_read = bh->block_total_length
435         - (int)sizeof(pcapng_block_header_t) 
436         - (int)sizeof (pcapng_section_header_block_t) 
437         - (int)sizeof(bh->block_total_length);
438         while(to_read > 0) {
439                 /* read option */
440                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
441                 if (bytes_read <= 0) {
442                         pcapng_debug0("pcapng_read_section_header_block: failed to read option");
443                         return bytes_read;
444                 }
445                 block_read += bytes_read;
446                 to_read -= bytes_read;
447
448                 /* handle option content */
449                 switch(oh.option_code) {
450                     case(0): /* opt_endofopt */
451                         if(to_read != 0) {
452                                 pcapng_debug1("pcapng_read_section_header_block: %u bytes after opt_endofopt", to_read);
453                         }
454                         /* padding should be ok here, just get out of this */
455                         to_read = 0;
456                         break;
457                     case(1): /* opt_comment */
458                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
459                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
460                                 pcapng_debug1("pcapng_read_section_header_block: opt_comment %s", wblock->data.section.opt_comment);
461                         } else {
462                                 pcapng_debug1("pcapng_read_section_header_block: opt_comment length %u seems strange", oh.option_length);
463                         }
464                         break;
465                     case(2): /* shb_hardware */
466                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
467                                 wblock->data.section.shb_hardware = g_strndup(option_content, sizeof(option_content));
468                                 pcapng_debug1("pcapng_read_section_header_block: shb_hardware %s", wblock->data.section.shb_hardware);
469                         } else {
470                                 pcapng_debug1("pcapng_read_section_header_block: shb_hardware length %u seems strange", oh.option_length);
471                         }
472                         break;
473                     case(3): /* shb_os */
474                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
475                                 wblock->data.section.shb_os = g_strndup(option_content, sizeof(option_content));
476                                 pcapng_debug1("pcapng_read_section_header_block: shb_os %s", wblock->data.section.shb_os);
477                         } else {
478                                 pcapng_debug1("pcapng_read_section_header_block: shb_os length %u seems strange", oh.option_length);
479                         }
480                         break;
481                     case(4): /* shb_userappl */
482                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
483                                 wblock->data.section.shb_user_appl = g_strndup(option_content, sizeof(option_content));
484                                 pcapng_debug1("pcapng_read_section_header_block: shb_userappl %s", wblock->data.section.shb_user_appl);
485                         } else {
486                                 pcapng_debug1("pcapng_read_section_header_block: shb_userappl length %u seems strange", oh.option_length);
487                         }
488                         break;
489                     default:
490                         pcapng_debug2("pcapng_read_section_header_block: unknown option %u - ignoring %u bytes",
491                                       oh.option_code, oh.option_length);
492                 }
493         }
494
495         if (pn->interface_data != NULL) {
496                 pcapng_debug0("pcapng_read_section_header_block: Multiple section header blocks!");
497                 g_array_free(pn->interface_data, TRUE);
498                 pn->interface_data = NULL;
499                 *err = WTAP_ERR_BAD_RECORD;
500                 *err_info = g_strdup_printf("pcapng: multiple section header blocks not supported.");
501                 return 0;
502         }
503         pn->interface_data = g_array_new(FALSE, FALSE, sizeof(interface_data_t));
504         pn->number_of_interfaces = 0;
505
506         return block_read;
507 }
508
509
510 /* "Interface Description Block" */
511 static int
512 pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
513                            wtapng_block_t *wblock, int *err, gchar **err_info _U_)
514 {
515         guint64 time_units_per_second;
516         int     bytes_read;
517         int     block_read;
518         int to_read;
519         pcapng_interface_description_block_t idb;
520         pcapng_option_header_t oh;
521         interface_data_t int_data;
522         gint encap;
523         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
524
525
526         time_units_per_second = 1000000; /* default */
527         /* read block content */
528         errno = WTAP_ERR_CANT_READ;
529         bytes_read = file_read(&idb, 1, sizeof idb, fh);
530         if (bytes_read != sizeof idb) {
531                 pcapng_debug0("pcapng_read_if_descr_block: failed to read IDB");
532                 *err = file_error(fh);
533                 if (*err != 0)
534                         return -1;
535                 return 0;
536         }
537         block_read = bytes_read;
538
539         /* mandatory values */
540         if (pn->byte_swapped) {
541                 wblock->data.if_descr.link_type = BSWAP16(idb.linktype);
542                 wblock->data.if_descr.snap_len  = BSWAP32(idb.snaplen);
543         } else {
544                 wblock->data.if_descr.link_type = idb.linktype;
545                 wblock->data.if_descr.snap_len  = idb.snaplen;
546         }
547
548         pcapng_debug3("pcapng_read_if_descr_block: IDB link_type %u (%s), snap %u",
549                       wblock->data.if_descr.link_type,
550                       wtap_encap_string(wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type)),
551                       wblock->data.if_descr.snap_len);
552
553         if (wblock->data.if_descr.snap_len > WTAP_MAX_PACKET_SIZE) {
554                 /* This is unrealisitic, but text2pcap currently uses 102400.
555                  * We do not use this value, maybe we should check the
556                  * snap_len of the packets against it. For now, only warn.
557                  */
558                 pcapng_debug1("pcapng_read_if_descr_block: snapshot length %u unrealistic.",
559                               wblock->data.if_descr.snap_len);
560                 /*wblock->data.if_descr.snap_len = WTAP_MAX_PACKET_SIZE;*/
561         }
562
563         /* Option defaults */
564         wblock->data.if_descr.opt_comment       = NULL;
565         wblock->data.if_descr.if_name           = NULL;
566         wblock->data.if_descr.if_description    = NULL;
567         /* XXX: if_IPv4addr */
568         /* XXX: if_IPv6addr */
569         /* XXX: if_MACaddr */
570         /* XXX: if_EUIaddr */
571         wblock->data.if_descr.if_speed          = 0xFFFFFFFF;   /* "unknown" */
572         wblock->data.if_descr.if_tsresol        = 6;            /* default is 6 for microsecond resolution */
573         wblock->data.if_descr.if_filter         = NULL;
574         wblock->data.if_descr.if_os             = NULL;
575         wblock->data.if_descr.if_fcslen         = -1;           /* unknown or changes between packets */
576         /* XXX: guint64 if_tsoffset; */
577
578
579         /* Options */
580         errno = WTAP_ERR_CANT_READ;
581         to_read = bh->block_total_length 
582         - (int)sizeof(pcapng_block_header_t) 
583         - (int)sizeof (pcapng_interface_description_block_t) 
584         - (int)sizeof(bh->block_total_length);
585         while (to_read > 0) {
586                 /* read option */
587                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
588                 if (bytes_read <= 0) {
589                         pcapng_debug0("pcapng_read_if_descr_block: failed to read option");
590                         return bytes_read;
591                 }
592                 block_read += bytes_read;
593                 to_read -= bytes_read;
594
595                 /* handle option content */
596                 switch(oh.option_code) {
597                     case(0): /* opt_endofopt */
598                         if(to_read != 0) {
599                                 pcapng_debug1("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read);
600                         }
601                         /* padding should be ok here, just get out of this */
602                         to_read = 0;
603                         break;
604                     case(1): /* opt_comment */
605                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
606                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
607                                 pcapng_debug1("pcapng_read_if_descr_block: opt_comment %s", wblock->data.section.opt_comment);
608                         } else {
609                                 pcapng_debug1("pcapng_read_if_descr_block: opt_comment length %u seems strange", oh.option_length);
610                         }
611                         break;
612                     case(2): /* if_name */
613                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
614                                 wblock->data.if_descr.if_name = g_strndup(option_content, sizeof(option_content));
615                                 pcapng_debug1("pcapng_read_if_descr_block: if_name %s", wblock->data.if_descr.if_name);
616                         } else {
617                                 pcapng_debug1("pcapng_read_if_descr_block: if_name length %u seems strange", oh.option_length);
618                         }
619                         break;
620                     case(3): /* if_description */
621                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
622                             wblock->data.if_descr.if_description = g_strndup(option_content, sizeof(option_content));
623                                 pcapng_debug1("pcapng_read_if_descr_block: if_description %s", wblock->data.if_descr.if_description);
624                         } else {
625                                 pcapng_debug1("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length);
626                         }
627                         break;
628                     case(8): /* if_speed */
629                         if(oh.option_length == 8) {
630                                 /*  Don't cast a char[] into a guint64--the
631                                  *  char[] may not be aligned correctly.
632                                  */
633                                 memcpy(&wblock->data.if_descr.if_speed, option_content, sizeof(guint64));
634                                 if(pn->byte_swapped) 
635                                         wblock->data.if_descr.if_speed = BSWAP64(wblock->data.if_descr.if_speed);
636                                 pcapng_debug1("pcapng_read_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", wblock->data.if_descr.if_speed);
637                         } else {
638                                     pcapng_debug1("pcapng_read_if_descr_block: if_speed length %u not 8 as expected", oh.option_length);
639                         }
640                         break;
641                     case(9): /* if_tsresol */
642                         if (oh.option_length == 1) {
643                                 guint64 base;
644                                 guint64 result;
645                                 guint8 i, exponent;
646
647                                 wblock->data.if_descr.if_tsresol = option_content[0];
648                                 if (wblock->data.if_descr.if_tsresol & 0x80) {
649                                         base = 2;
650                                 } else {
651                                         base = 10;
652                                 }
653                                 exponent = (guint8)(wblock->data.if_descr.if_tsresol & 0x7f);
654                                 if (((base == 2) && (exponent < 64)) || ((base == 10) && (exponent < 20))) {
655                                         result = 1;
656                                         for (i = 0; i < exponent; i++) {
657                                                 result *= base;
658                                         }
659                                         time_units_per_second = result;
660                                 } else {
661                                         time_units_per_second = G_MAXUINT64;
662                                 }
663                                 if (time_units_per_second > (((guint64)1) << 32)) {
664                                         pcapng_debug0("pcapng_open: time conversion might be inaccurate");
665                                 }
666                                 pcapng_debug1("pcapng_read_if_descr_block: if_tsresol %u", wblock->data.if_descr.if_tsresol);
667                         } else {
668                                 pcapng_debug1("pcapng_read_if_descr_block: if_tsresol length %u not 1 as expected", oh.option_length);
669                         }
670                         break;
671                     case(11): /* if_filter */
672                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
673                                 wblock->data.if_descr.if_filter = g_strndup(option_content, sizeof(option_content));
674                                 pcapng_debug1("pcapng_read_if_descr_block: if_filter %s", wblock->data.if_descr.if_filter);
675                         } else {
676                                 pcapng_debug1("pcapng_read_if_descr_block: if_filter length %u seems strange", oh.option_length);
677                         }
678                         break;
679                     case(13): /* if_fcslen */
680                         if(oh.option_length == 1) {
681                                 wblock->data.if_descr.if_fcslen = option_content[0];
682                                 pn->if_fcslen = wblock->data.if_descr.if_fcslen;
683                                 pcapng_debug1("pcapng_read_if_descr_block: if_fcslen %u", wblock->data.if_descr.if_fcslen);
684                                 /* XXX - add sanity check */
685                         } else {
686                                 pcapng_debug1("pcapng_read_if_descr_block: if_fcslen length %u not 1 as expected", oh.option_length);
687                         }
688                         break;
689                     default:
690                         pcapng_debug2("pcapng_read_if_descr_block: unknown option %u - ignoring %u bytes",
691                                       oh.option_code, oh.option_length);
692                 }
693         }
694
695         encap = wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type);
696         if (*wblock->file_encap == WTAP_ENCAP_UNKNOWN) {
697                 *wblock->file_encap = encap;
698         } else {
699                 if (*wblock->file_encap != encap) {
700                         *wblock->file_encap = WTAP_ENCAP_PER_PACKET;
701                 }
702         }
703
704         int_data.wtap_encap = encap;
705         int_data.time_units_per_second = time_units_per_second;
706         g_array_append_val(pn->interface_data, int_data);
707         pn->number_of_interfaces++;
708         return block_read;
709 }
710
711
712 static int 
713 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)
714 {
715         int bytes_read;
716         int block_read;
717         int to_read;
718         guint64 file_offset64;
719         pcapng_enhanced_packet_block_t epb;
720         pcapng_packet_block_t pb;
721         guint32 block_total_length;
722         pcapng_option_header_t oh;
723         gint wtap_encap;
724         int pseudo_header_len;
725         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
726
727
728         /* "(Enhanced) Packet Block" read fixed part */
729         errno = WTAP_ERR_CANT_READ;
730         if (enhanced) {
731                 bytes_read = file_read(&epb, 1, sizeof epb, fh);
732                 if (bytes_read != sizeof epb) {
733                         pcapng_debug0("pcapng_read_packet_block: failed to read packet data");
734                         *err = file_error(fh);
735                         return 0;
736                 }
737                 block_read = bytes_read;
738
739                 if (pn->byte_swapped) {
740                         wblock->data.packet.interface_id        = BSWAP32(epb.interface_id);
741                         wblock->data.packet.drops_count         = -1; /* invalid */
742                         wblock->data.packet.ts_high             = BSWAP32(epb.timestamp_high);
743                         wblock->data.packet.ts_low              = BSWAP32(epb.timestamp_low);
744                         wblock->data.packet.cap_len             = BSWAP32(epb.captured_len);
745                         wblock->data.packet.packet_len          = BSWAP32(epb.packet_len);
746                 } else {
747                         wblock->data.packet.interface_id        = epb.interface_id;
748                         wblock->data.packet.drops_count         = -1; /* invalid */
749                         wblock->data.packet.ts_high             = epb.timestamp_high;
750                         wblock->data.packet.ts_low              = epb.timestamp_low;
751                         wblock->data.packet.cap_len             = epb.captured_len;
752                         wblock->data.packet.packet_len          = epb.packet_len;
753                 }
754         } else {
755                 bytes_read = file_read(&pb, 1, sizeof pb, fh);
756                 if (bytes_read != sizeof pb) {
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        = BSWAP16(pb.interface_id);
765                         wblock->data.packet.drops_count         = BSWAP16(pb.drops_count);
766                         wblock->data.packet.ts_high             = BSWAP32(pb.timestamp_high);
767                         wblock->data.packet.ts_low              = BSWAP32(pb.timestamp_low);
768                         wblock->data.packet.cap_len             = BSWAP32(pb.captured_len);
769                         wblock->data.packet.packet_len          = BSWAP32(pb.packet_len);
770                 } else {
771                         wblock->data.packet.interface_id        = pb.interface_id;
772                         wblock->data.packet.drops_count         = pb.drops_count;
773                         wblock->data.packet.ts_high             = pb.timestamp_high;
774                         wblock->data.packet.ts_low              = pb.timestamp_low;
775                         wblock->data.packet.cap_len             = pb.captured_len;
776                         wblock->data.packet.packet_len          = pb.packet_len;
777                 }
778         }
779
780         if (wblock->data.packet.cap_len > wblock->data.packet.packet_len) {
781                 pcapng_debug2("pcapng_read_packet_block:cap_len %d is larger than packet_len %u.",
782                               wblock->data.packet.cap_len, wblock->data.packet.packet_len);
783                 *err = WTAP_ERR_BAD_RECORD;
784                 return 0;
785         }
786         if (wblock->data.packet.cap_len > WTAP_MAX_PACKET_SIZE) {
787                 pcapng_debug2("pcapng_read_packet_block:cap_len %d is larger than WTAP_MAX_PACKET_SIZE %u.",
788                               wblock->data.packet.cap_len, WTAP_MAX_PACKET_SIZE);
789                 *err = WTAP_ERR_BAD_RECORD;
790                 return 0;
791         }
792         pcapng_debug3("pcapng_read_packet_block: packet data: packet_len %u captured_len %u interface_id %u",
793                       wblock->data.packet.packet_len,
794                       wblock->data.packet.cap_len,
795                       wblock->data.packet.interface_id);
796
797         wtap_encap = pcapng_get_encap(wblock->data.packet.interface_id, pn);
798         pcapng_debug3("pcapng_read_packet_block: encapsulation = %d (%s), pseudo header size = %d.",
799                        wtap_encap,
800                        wtap_encap_string(wtap_encap),
801                        pcap_get_phdr_size(wtap_encap, wblock->pseudo_header));
802
803         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
804         pseudo_header_len = pcap_process_pseudo_header(fh,
805                                                        WTAP_FILE_PCAPNG,
806                                                        wtap_encap,
807                                                        pn->byte_swapped,
808                                                        wblock->data.packet.cap_len,
809                                                        TRUE,
810                                                        wblock->packet_header,
811                                                        (union wtap_pseudo_header *)wblock->pseudo_header,
812                                                        err,
813                                                        err_info);
814         if (pseudo_header_len < 0) {
815                 return 0;
816         }
817         wblock->data.packet.pseudo_header_len = (guint32)pseudo_header_len;
818         block_read += pseudo_header_len;
819         if (pseudo_header_len != pcap_get_phdr_size(wtap_encap, wblock->pseudo_header)) {
820                 pcapng_debug1("pcapng_read_packet_block: Could only read %d bytes for pseudo header.",
821                               pseudo_header_len);
822         }
823
824         /* "(Enhanced) Packet Block" read capture data */
825         errno = WTAP_ERR_CANT_READ;
826         bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.packet.cap_len - pseudo_header_len, fh);
827         if (bytes_read != (int) (wblock->data.packet.cap_len - pseudo_header_len)) {
828                 *err = file_error(fh);
829                 pcapng_debug1("pcapng_read_packet_block: couldn't read %u bytes of captured data", 
830                               wblock->data.packet.cap_len - pseudo_header_len);
831                 if (*err == 0)
832                         *err = WTAP_ERR_SHORT_READ;
833                 return 0;
834         }
835         block_read += bytes_read;
836
837         /* jump over potential padding bytes at end of the packet data */
838         if( (wblock->data.packet.cap_len % 4) != 0) {
839                 file_offset64 = file_seek(fh, 4 - (wblock->data.packet.cap_len % 4), SEEK_CUR, err);
840                 if (file_offset64 <= 0) {
841                         if (*err != 0)
842                                 return -1;
843                         return 0;
844                 }
845                 block_read += 4 - (wblock->data.packet.cap_len % 4);
846         }
847
848         /* add padding bytes to "block total length" */
849         /* (the "block total length" of some example files don't contain the packet data padding bytes!) */
850         if (bh->block_total_length % 4) {
851                 block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
852         } else {
853                 block_total_length = bh->block_total_length;
854         }
855
856         /* Option defaults */
857         wblock->data.packet.opt_comment = NULL;
858         wblock->data.packet.drop_count  = -1;
859         wblock->data.packet.pack_flags  = 0;    /* XXX - is 0 ok to signal "not used"? */
860
861         /* Options */
862         errno = WTAP_ERR_CANT_READ;
863         to_read = block_total_length 
864         - (int)sizeof(pcapng_block_header_t) 
865         - block_read    /* fixed and variable part, including padding */
866         - (int)sizeof(bh->block_total_length);
867         while(to_read > 0) {
868                 /* read option */
869                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
870                 if (bytes_read <= 0) {
871                         pcapng_debug0("pcapng_read_packet_block: failed to read option");
872                         return bytes_read;
873                 }
874                 block_read += bytes_read;
875                 to_read -= bytes_read;
876
877                 /* handle option content */
878                 switch(oh.option_code) {
879                     case(0): /* opt_endofopt */
880                         if(to_read != 0) {
881                                 pcapng_debug1("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read);
882                         }
883                         /* padding should be ok here, just get out of this */
884                         to_read = 0;
885                         break;
886                     case(1): /* opt_comment */
887                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
888                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
889                                 pcapng_debug1("pcapng_read_packet_block: opt_comment %s", wblock->data.section.opt_comment);
890                         } else {
891                                 pcapng_debug1("pcapng_read_packet_block: opt_comment length %u seems strange", oh.option_length);
892                         }
893                         break;
894                     case(2): /* pack_flags / epb_flags */
895                         if(oh.option_length == 4) {
896                                 /*  Don't cast a char[] into a guint32--the
897                                  *  char[] may not be aligned correctly.
898                                  */
899                                 memcpy(&wblock->data.packet.pack_flags, option_content, sizeof(guint32));
900                                 if(pn->byte_swapped) 
901                                         wblock->data.packet.pack_flags = BSWAP32(wblock->data.packet.pack_flags);
902                                 pcapng_debug1("pcapng_read_if_descr_block: pack_flags %u (ignored)", wblock->data.packet.pack_flags);
903                         } else {
904                                 pcapng_debug1("pcapng_read_if_descr_block: pack_flags length %u not 4 as expected", oh.option_length);
905                         }
906                         break;
907                     default:
908                         pcapng_debug2("pcapng_read_packet_block: unknown option %u - ignoring %u bytes",
909                                       oh.option_code, oh.option_length);
910                 }
911         }
912
913         return block_read;
914 }
915
916
917 static int 
918 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_)
919 {
920         int bytes_read;
921         int block_read;
922         guint64 file_offset64;
923         gint encap;
924         int pseudo_header_len;
925         pcapng_simple_packet_block_t spb;
926
927
928         /* "Simple Packet Block" read fixed part */
929         errno = WTAP_ERR_CANT_READ;
930         bytes_read = file_read(&spb, 1, sizeof spb, fh);
931         if (bytes_read != sizeof spb) {
932                 pcapng_debug0("pcapng_read_simple_packet_block: failed to read packet data");
933                 *err = file_error(fh);
934                 return 0;
935         }
936         block_read = bytes_read;
937
938         if (pn->byte_swapped) {
939                 wblock->data.simple_packet.packet_len   = BSWAP32(spb.packet_len);
940         } else {
941                 wblock->data.simple_packet.packet_len   = spb.packet_len;
942         }
943
944         wblock->data.simple_packet.cap_len = bh->block_total_length 
945                                              - (guint32)sizeof(pcapng_simple_packet_block_t) 
946                                              - (guint32)sizeof(bh->block_total_length);
947
948         if (wblock->data.simple_packet.cap_len > WTAP_MAX_PACKET_SIZE) {
949                 pcapng_debug2("pcapng_read_simple_packet_block:cap_len %d is larger than WTAP_MAX_PACKET_SIZE %u.",
950                               wblock->data.simple_packet.cap_len, WTAP_MAX_PACKET_SIZE);
951                 *err = WTAP_ERR_BAD_RECORD;
952                 return 0;
953         }
954         pcapng_debug1("pcapng_read_simple_packet_block: packet data: packet_len %u",
955                        wblock->data.simple_packet.packet_len);
956
957         encap = pcapng_get_encap(0, pn);
958         pcapng_debug1("pcapng_read_simple_packet_block: Need to read pseudo header of size %d",
959                       pcap_get_phdr_size(encap, wblock->pseudo_header));
960
961         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
962         pseudo_header_len = pcap_process_pseudo_header(fh,
963                                                        WTAP_FILE_PCAPNG,
964                                                        encap,
965                                                        pn->byte_swapped,
966                                                        wblock->data.simple_packet.cap_len,
967                                                        TRUE,
968                                                        wblock->packet_header,
969                                                        (union wtap_pseudo_header *)wblock->pseudo_header,
970                                                        err,
971                                                        err_info);
972         if (pseudo_header_len < 0) {
973                 return 0;
974         }
975         wblock->data.simple_packet.pseudo_header_len = (guint32)pseudo_header_len;
976         block_read += pseudo_header_len;
977         if (pseudo_header_len != pcap_get_phdr_size(encap, wblock->pseudo_header)) {
978                 pcapng_debug1("pcapng_read_simple_packet_block: Could only read %d bytes for pseudo header.",
979                               pseudo_header_len);
980         }
981
982         /* XXX - implement other linktypes then Ethernet */
983         /* (or even better share the code with libpcap.c) */
984
985         /* Ethernet FCS length, might be overwritten by "per packet" options */
986         memset((void *)wblock->pseudo_header, 0, sizeof(union wtap_pseudo_header));
987         ((union wtap_pseudo_header *) wblock->pseudo_header)->eth.fcs_len = pn->if_fcslen;
988
989         /* "Simple Packet Block" read capture data */
990         errno = WTAP_ERR_CANT_READ;
991         bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.simple_packet.cap_len, fh);
992         if (bytes_read != (int) wblock->data.simple_packet.cap_len) {
993                 *err = file_error(fh);
994                 pcapng_debug1("pcapng_read_simple_packet_block: couldn't read %u bytes of captured data", 
995                               wblock->data.simple_packet.cap_len);
996                 if (*err == 0)
997                         *err = WTAP_ERR_SHORT_READ;
998                 return 0;
999         }
1000         block_read += bytes_read;
1001
1002         /* jump over potential padding bytes at end of the packet data */
1003         if ((wblock->data.simple_packet.cap_len % 4) != 0) {
1004                 file_offset64 = file_seek(fh, 4 - (wblock->data.simple_packet.cap_len % 4), SEEK_CUR, err);
1005                 if (file_offset64 <= 0) {
1006                         if (*err != 0)
1007                                 return -1;
1008                         return 0;
1009                 }
1010                 block_read += 4 - (wblock->data.simple_packet.cap_len % 4);
1011         }
1012
1013         return block_read;
1014 }
1015
1016 static int 
1017 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_)
1018 {
1019         int bytes_read;
1020         int block_read;
1021         int to_read;
1022         pcapng_interface_statistics_block_t isb;
1023         pcapng_option_header_t oh;
1024         char option_content[100]; /* XXX - size might need to be increased, if we see longer options */
1025
1026
1027         /* "Interface Statistics Block" read fixed part */
1028         errno = WTAP_ERR_CANT_READ;
1029         bytes_read = file_read(&isb, 1, sizeof isb, fh);
1030         if (bytes_read != sizeof isb) {
1031                 pcapng_debug0("pcapng_read_interface_statistics_block: failed to read packet data");
1032                 *err = file_error(fh);
1033                 return 0;
1034         }
1035         block_read = bytes_read;
1036
1037         if(pn->byte_swapped) {
1038                 wblock->data.if_stats.interface_id      = BSWAP64(isb.interface_id);
1039                 wblock->data.if_stats.ts_high           = BSWAP32(isb.timestamp_high);
1040                 wblock->data.if_stats.ts_low            = BSWAP32(isb.timestamp_low);
1041         } else {
1042                 wblock->data.if_stats.interface_id      = isb.interface_id;
1043                 wblock->data.if_stats.ts_high           = isb.timestamp_high;
1044                 wblock->data.if_stats.ts_low            = isb.timestamp_low;
1045         }
1046         pcapng_debug1("pcapng_read_interface_statistics_block: interface_id %" G_GINT64_MODIFIER "u", wblock->data.if_stats.interface_id);
1047
1048         /* Option defaults */
1049         wblock->data.if_stats.opt_comment = NULL;
1050         wblock->data.if_stats.isb_ifrecv  = -1;
1051         wblock->data.if_stats.isb_ifdrop  = -1;
1052
1053         /* Options */
1054         errno = WTAP_ERR_CANT_READ;
1055         to_read = bh->block_total_length 
1056         - sizeof(pcapng_block_header_t) 
1057         - block_read    /* fixed and variable part, including padding */
1058         - sizeof(bh->block_total_length);
1059         while(to_read > 0) {
1060                 /* read option */
1061                 bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info);
1062                 if (bytes_read <= 0) {
1063                         pcapng_debug0("pcapng_read_interface_statistics_block: failed to read option");
1064                         return bytes_read;
1065                 }
1066                 block_read += bytes_read;
1067                 to_read -= bytes_read;
1068
1069                 /* handle option content */
1070                 switch(oh.option_code) {
1071                     case(0): /* opt_endofopt */
1072                         if(to_read != 0) {
1073                                 pcapng_debug1("pcapng_read_interface_statistics_block: %u bytes after opt_endofopt", to_read);
1074                         }
1075                         /* padding should be ok here, just get out of this */
1076                         to_read = 0;
1077                         break;
1078                     case(1): /* opt_comment */
1079                         if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) {
1080                                 wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content));
1081                                 pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment %s", wblock->data.section.opt_comment);
1082                         } else {
1083                                 pcapng_debug1("pcapng_read_interface_statistics_block: opt_comment length %u seems strange", oh.option_length);
1084                         }
1085                         break;
1086                     case(4): /* isb_ifrecv */
1087                         if(oh.option_length == 8) {
1088                                 /*  Don't cast a char[] into a guint32--the
1089                                  *  char[] may not be aligned correctly.
1090                                  */
1091                                 memcpy(&wblock->data.if_stats.isb_ifrecv, option_content, sizeof(guint64));
1092                                 if(pn->byte_swapped) 
1093                                         wblock->data.if_stats.isb_ifrecv = BSWAP64(wblock->data.if_stats.isb_ifrecv);
1094                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifrecv);
1095                         } else {
1096                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifrecv length %u not 8 as expected", oh.option_length);
1097                         }
1098                         break;
1099                     case(5): /* isb_ifdrop */
1100                         if(oh.option_length == 8) {
1101                                 /*  Don't cast a char[] into a guint32--the
1102                                  *  char[] may not be aligned correctly.
1103                                  */
1104                                 memcpy(&wblock->data.if_stats.isb_ifdrop, option_content, sizeof(guint64));
1105                                 if(pn->byte_swapped) 
1106                                         wblock->data.if_stats.isb_ifdrop = BSWAP64(wblock->data.if_stats.isb_ifdrop);
1107                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop %" G_GINT64_MODIFIER "u", wblock->data.if_stats.isb_ifdrop);
1108                         } else {
1109                                 pcapng_debug1("pcapng_read_interface_statistics_block: isb_ifdrop length %u not 8 as expected", oh.option_length);
1110                         }
1111                         break;
1112                     default:
1113                         pcapng_debug2("pcapng_read_interface_statistics_block: unknown option %u - ignoring %u bytes",
1114                                       oh.option_code, oh.option_length);
1115                 }
1116         }
1117
1118     return block_read;
1119 }
1120
1121
1122 static int 
1123 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_)
1124 {
1125         int block_read;
1126         guint64 file_offset64;
1127         guint32 block_total_length;
1128
1129
1130         /* add padding bytes to "block total length" */
1131         /* (the "block total length" of some example files don't contain any padding bytes!) */
1132         if (bh->block_total_length % 4) {
1133                 block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
1134         } else {
1135                 block_total_length = bh->block_total_length;
1136         }
1137
1138         block_read = block_total_length - (guint32)sizeof(pcapng_block_header_t) - (guint32)sizeof(bh->block_total_length);
1139
1140         /* jump over this unknown block */
1141         file_offset64 = file_seek(fh, block_read, SEEK_CUR, err);
1142         if (file_offset64 <= 0) {
1143                 if (*err != 0)
1144                         return -1;
1145                 return 0;
1146         }
1147
1148         return block_read;
1149 }
1150
1151
1152 static int 
1153 pcapng_read_block(FILE_T fh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
1154 {
1155         int block_read;
1156         int bytes_read;
1157         pcapng_block_header_t bh;
1158         guint32 block_total_length;
1159
1160
1161         /* Try to read the (next) block header */
1162         errno = WTAP_ERR_CANT_READ;
1163         bytes_read = file_read(&bh, 1, sizeof bh, fh);
1164         if (bytes_read != sizeof bh) {
1165                 pcapng_debug0("pcapng_read_block: end of file");
1166                 *err = file_error(fh);
1167                 if (*err != 0)
1168                         return -1;
1169                 return 0;
1170         }
1171
1172         block_read = bytes_read;
1173         if (pn->byte_swapped) {
1174                 bh.block_type         = BSWAP32(bh.block_type);
1175                 bh.block_total_length = BSWAP32(bh.block_total_length);
1176         }
1177
1178         wblock->type = bh.block_type;
1179
1180         pcapng_debug1("pcapng_read_block: block_type 0x%x", bh.block_type);
1181
1182         switch(bh.block_type) {
1183                 case(BLOCK_TYPE_SHB):
1184                         bytes_read = pcapng_read_section_header_block(fh, &bh, pn, wblock, err, err_info);
1185                         break;
1186                 case(BLOCK_TYPE_IDB):
1187                         bytes_read = pcapng_read_if_descr_block(fh, &bh, pn, wblock, err, err_info);
1188                         break;
1189                 case(BLOCK_TYPE_PB):
1190                         bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, FALSE);
1191                         break;
1192                 case(BLOCK_TYPE_SPB):
1193                         bytes_read = pcapng_read_simple_packet_block(fh, &bh, pn, wblock, err, err_info);
1194                         break;
1195                 case(BLOCK_TYPE_EPB):
1196                         bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info, TRUE);
1197                         break;
1198                 case(BLOCK_TYPE_ISB):
1199                         bytes_read = pcapng_read_interface_statistics_block(fh, &bh, pn, wblock, err, err_info);
1200                         break;
1201                 default:
1202                         pcapng_debug2("pcapng_read_block: Unknown block_type: 0x%x (block ignored), block total length %d", bh.block_type, bh.block_total_length);
1203                         bytes_read = pcapng_read_unknown_block(fh, &bh, pn, wblock, err, err_info);
1204         }
1205
1206         if (bytes_read <= 0) {
1207                 return bytes_read;
1208         }
1209         block_read += bytes_read;
1210
1211         /* sanity check: first and second block lengths must match */
1212         errno = WTAP_ERR_CANT_READ;
1213         bytes_read = file_read(&block_total_length, 1, sizeof block_total_length, fh);
1214         if (bytes_read != sizeof block_total_length) {
1215                 pcapng_debug0("pcapng_read_block: couldn't read second block length");
1216                 *err = file_error(fh);
1217                 if (*err != 0)
1218                         return -1;
1219                 return 0;
1220         }
1221         block_read += bytes_read;
1222
1223         if (pn->byte_swapped)
1224                 block_total_length = BSWAP32(block_total_length);
1225
1226         if (!(block_total_length == bh.block_total_length)) {
1227                 pcapng_debug2("pcapng_read_block: total block lengths (first %u and second %u) don't match", 
1228                               bh.block_total_length, block_total_length);
1229                 return 0;
1230         }
1231
1232         return block_read;
1233 }
1234
1235
1236 /* classic wtap: open capture file */
1237 int 
1238 pcapng_open(wtap *wth, int *err, gchar **err_info)
1239 {
1240         int bytes_read;
1241         pcapng_t pn;
1242         wtapng_block_t wblock;
1243         pcapng_t *pcapng;
1244
1245         /* we don't know the byte swapping of the file yet */
1246         pn.byte_swapped = FALSE;
1247         pn.if_fcslen = -1;
1248         pn.version_major = -1;
1249         pn.version_minor = -1;
1250         pn.interface_data = NULL;
1251         pn.number_of_interfaces = 0;
1252
1253         /* we don't expect any packet blocks yet */
1254         wblock.frame_buffer = NULL;
1255         wblock.pseudo_header = NULL;
1256         wblock.packet_header = NULL;
1257         wblock.file_encap = &wth->file_encap;
1258
1259         pcapng_debug0("pcapng_open: opening file");
1260         /* read first block */
1261         bytes_read = pcapng_read_block(wth->fh, &pn, &wblock, err, err_info);
1262         if (bytes_read <= 0) {
1263                 pcapng_debug0("pcapng_open: couldn't read first SHB");
1264                 *err = file_error(wth->fh);
1265                 if (*err != 0)
1266                         return -1;
1267                 return 0;
1268         }
1269         wth->data_offset += bytes_read;
1270
1271         /* first block must be a "Section Header Block" */
1272         if (wblock.type != BLOCK_TYPE_SHB) {
1273                 /*
1274                  * XXX - check for damage from transferring a file
1275                  * between Windows and UN*X as text rather than
1276                  * binary data?
1277                  */
1278                 pcapng_debug1("pcapng_open: first block type %u not SHB", wblock.type);
1279                 return 0;
1280         }
1281
1282         wth->file_encap = WTAP_ENCAP_UNKNOWN;
1283         wth->snapshot_length = 0;
1284         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
1285         pcapng = (pcapng_t *)g_malloc(sizeof(pcapng_t));
1286         wth->priv = (void *)pcapng;
1287         *pcapng = pn;
1288         wth->subtype_read = pcapng_read;
1289         wth->subtype_seek_read = pcapng_seek_read;
1290         wth->subtype_close = pcapng_close;
1291         wth->file_type = WTAP_FILE_PCAPNG;
1292
1293         return 1;
1294 }
1295
1296
1297 /* classic wtap: read packet */
1298 static gboolean 
1299 pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
1300 {
1301         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1302         int bytes_read;
1303         guint64 ts;
1304         wtapng_block_t wblock;
1305
1306         pcapng_debug1("pcapng_read: wth->data_offset is initially %" G_GINT64_MODIFIER "u", wth->data_offset);
1307         *data_offset = wth->data_offset;
1308         pcapng_debug1("pcapng_read: *data_offset is initially set to %" G_GINT64_MODIFIER "u", *data_offset);
1309
1310         /* XXX - This should be done in the packet block reading function and
1311          * should make use of the caplen of the packet.
1312          */
1313         if (wth->snapshot_length > 0) {
1314                 buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
1315         } else {
1316                 buffer_assure_space(wth->frame_buffer, WTAP_MAX_PACKET_SIZE);
1317         }
1318
1319         wblock.frame_buffer  = buffer_start_ptr(wth->frame_buffer);
1320         wblock.pseudo_header = &wth->pseudo_header;
1321         wblock.packet_header = &wth->phdr;
1322         wblock.file_encap    = &wth->file_encap;
1323
1324         /* read next block */
1325         while (1) {
1326                 bytes_read = pcapng_read_block(wth->fh, pcapng, &wblock, err, err_info);
1327                 if (bytes_read <= 0) {
1328                         pcapng_debug0("pcapng_read: couldn't read packet block");
1329                         return FALSE;
1330                 }
1331
1332                 /* block must be a "Packet Block" or an "Enhanced Packet Block" -> otherwise continue */
1333                 if (wblock.type == BLOCK_TYPE_PB || wblock.type == BLOCK_TYPE_EPB) {
1334                         break;
1335                 }
1336
1337                 /* XXX - improve handling of "unknown" blocks */
1338                 pcapng_debug1("pcapng_read: block type 0x%x not PB/EPB", wblock.type);
1339                 *data_offset += bytes_read;
1340                 pcapng_debug1("pcapng_read: *data_offset is updated to %" G_GINT64_MODIFIER "u", *data_offset);
1341         }
1342
1343         /* Combine the two 32-bit pieces of the timestamp into one 64-bit value */
1344         ts = (((guint64)wblock.data.packet.ts_high) << 32) | ((guint64)wblock.data.packet.ts_low);
1345
1346         wth->phdr.caplen = wblock.data.packet.cap_len - wblock.data.packet.pseudo_header_len;
1347         wth->phdr.len = wblock.data.packet.packet_len - wblock.data.packet.pseudo_header_len;
1348         if (wblock.data.packet.interface_id < pcapng->number_of_interfaces) {
1349                 interface_data_t int_data;
1350                 guint64 time_units_per_second;
1351                 gint id;
1352                 
1353                 id = (gint)wblock.data.packet.interface_id;
1354                 int_data = g_array_index(pcapng->interface_data, interface_data_t, id);
1355                 time_units_per_second = int_data.time_units_per_second;
1356                 wth->phdr.pkt_encap = int_data.wtap_encap;
1357                 wth->phdr.ts.secs = (time_t)(ts / time_units_per_second);
1358                 wth->phdr.ts.nsecs = (int)(((ts % time_units_per_second) * 1000000000) / time_units_per_second);
1359         } else {
1360                 pcapng_debug1("pcapng_read: interface_id %d too large", wblock.data.packet.interface_id);
1361                 wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
1362                 *err = WTAP_ERR_BAD_RECORD;
1363                 *err_info = g_strdup_printf("pcapng: interface index %u is too large", wblock.data.packet.interface_id);
1364                 return FALSE;
1365         }
1366
1367         /*pcapng_debug2("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/
1368         wth->data_offset = *data_offset + bytes_read;
1369         pcapng_debug1("pcapng_read: wth->data_offset is finally %" G_GINT64_MODIFIER "u", wth->data_offset);
1370
1371         return TRUE;
1372 }
1373
1374
1375 /* classic wtap: seek to file position and read packet */
1376 static gboolean
1377 pcapng_seek_read(wtap *wth, gint64 seek_off,
1378     union wtap_pseudo_header *pseudo_header, guchar *pd, int length _U_,
1379     int *err, gchar **err_info)
1380 {
1381         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1382         guint64 bytes_read64;
1383         int bytes_read;
1384         wtapng_block_t wblock;
1385
1386
1387         /* seek to the right file position */
1388         bytes_read64 = file_seek(wth->random_fh, seek_off, SEEK_SET, err);
1389         if (bytes_read64 <= 0) {
1390                 return FALSE;   /* Seek error */
1391         }
1392         pcapng_debug1("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
1393
1394         wblock.frame_buffer = pd;
1395         wblock.pseudo_header = pseudo_header;
1396         wblock.packet_header = &wth->phdr;
1397         wblock.file_encap = &wth->file_encap;
1398
1399         /* read the block */
1400         bytes_read = pcapng_read_block(wth->random_fh, pcapng, &wblock, err, err_info);
1401         if (bytes_read <= 0) {
1402                 *err = file_error(wth->random_fh);
1403                 pcapng_debug3("pcapng_seek_read: couldn't read packet block (err=%d, errno=%d, bytes_read=%d).",
1404                               *err, errno, bytes_read);
1405                 return FALSE;
1406         }
1407
1408         /* block must be a "Packet Block" or an "Enhanced Packet Block" */
1409         if (wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB) {
1410                 pcapng_debug1("pcapng_seek_read: block type %u not PB/EPB", wblock.type);
1411                 return FALSE;
1412         }
1413
1414         return TRUE;
1415 }
1416
1417
1418 /* classic wtap: close capture file */
1419 static void
1420 pcapng_close(wtap *wth)
1421 {
1422         pcapng_t *pcapng = (pcapng_t *)wth->priv;
1423
1424         pcapng_debug0("pcapng_close: closing file");
1425         if (pcapng->interface_data != NULL) {
1426                 g_array_free(pcapng->interface_data, TRUE);
1427         }
1428 }
1429
1430
1431
1432 typedef struct {
1433         GArray *interface_data;
1434         guint number_of_interfaces;
1435 } pcapng_dump_t;
1436
1437 static gboolean
1438 pcapng_write_section_header_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1439 {
1440         pcapng_block_header_t bh;
1441         pcapng_section_header_block_t shb;
1442         size_t nwritten;
1443
1444
1445         /* write block header */
1446         bh.block_type = wblock->type;
1447         bh.block_total_length = sizeof(bh) + sizeof(shb) /* + options */ + 4;
1448
1449         nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
1450         if (nwritten != sizeof bh) {
1451                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1452                         *err = wtap_dump_file_ferror(wdh);
1453                 else
1454                         *err = WTAP_ERR_SHORT_WRITE;
1455                 return FALSE;
1456         }
1457         wdh->bytes_dumped += sizeof bh;
1458
1459         /* write block fixed content */
1460         /* XXX - get these values from wblock? */
1461         shb.magic = 0x1A2B3C4D;
1462         shb.version_major = 1;
1463         shb.version_minor = 0;
1464         shb.section_length = -1;
1465
1466         nwritten = wtap_dump_file_write(wdh, &shb, sizeof shb);
1467         if (nwritten != sizeof shb) {
1468                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1469                         *err = wtap_dump_file_ferror(wdh);
1470                 else
1471                         *err = WTAP_ERR_SHORT_WRITE;
1472                 return FALSE;
1473         }
1474         wdh->bytes_dumped += sizeof shb;
1475
1476         /* XXX - write (optional) block options */
1477
1478         /* write block footer */
1479         nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
1480         if (nwritten != sizeof bh.block_total_length) {
1481                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1482                         *err = wtap_dump_file_ferror(wdh);
1483                 else
1484                         *err = WTAP_ERR_SHORT_WRITE;
1485                 return FALSE;
1486         }
1487         wdh->bytes_dumped += sizeof bh.block_total_length;
1488
1489         return TRUE;
1490 }
1491
1492
1493
1494 static gboolean
1495 pcapng_write_if_descr_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1496 {
1497         pcapng_block_header_t bh;
1498         pcapng_interface_description_block_t idb;
1499         size_t nwritten;
1500
1501
1502         pcapng_debug3("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d",
1503                       wblock->data.if_descr.link_type,
1504                       wtap_encap_string(wtap_pcap_encap_to_wtap_encap(wblock->data.if_descr.link_type)),
1505                       wblock->data.if_descr.snap_len);
1506
1507         if (wblock->data.if_descr.link_type == (guint16)-1) {
1508                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
1509                 return FALSE;
1510         }
1511
1512         /* write block header */
1513         bh.block_type = wblock->type;
1514         bh.block_total_length = sizeof(bh) + sizeof(idb) /* + options */ + 4;
1515
1516         nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
1517         if (nwritten != sizeof bh) {
1518                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1519                         *err = wtap_dump_file_ferror(wdh);
1520                 else
1521                         *err = WTAP_ERR_SHORT_WRITE;
1522                 return FALSE;
1523         }
1524         wdh->bytes_dumped += sizeof bh;
1525
1526         /* write block fixed content */
1527         idb.linktype    = wblock->data.if_descr.link_type;
1528         idb.reserved    = 0;
1529         idb.snaplen     = wblock->data.if_descr.snap_len;
1530
1531         nwritten = wtap_dump_file_write(wdh, &idb, sizeof idb);
1532         if (nwritten != sizeof idb) {
1533                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1534                         *err = wtap_dump_file_ferror(wdh);
1535                 else
1536                         *err = WTAP_ERR_SHORT_WRITE;
1537                 return FALSE;
1538         }
1539         wdh->bytes_dumped += sizeof idb;
1540
1541         /* XXX - write (optional) block options */
1542
1543         /* write block footer */
1544         nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
1545         if (nwritten != sizeof bh.block_total_length) {
1546                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1547                         *err = wtap_dump_file_ferror(wdh);
1548                 else
1549                         *err = WTAP_ERR_SHORT_WRITE;
1550                 return FALSE;
1551         }
1552         wdh->bytes_dumped += sizeof bh.block_total_length;
1553
1554         return TRUE;
1555 }
1556
1557
1558 static gboolean
1559 pcapng_write_packet_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
1560 {
1561         pcapng_block_header_t bh;
1562         pcapng_enhanced_packet_block_t epb;
1563         size_t nwritten;
1564         const guint32 zero_pad = 0;
1565         guint32 pad_len;
1566         guint32 phdr_len;
1567         
1568         phdr_len = (guint32)pcap_get_phdr_size(wblock->data.packet.wtap_encap, wblock->pseudo_header);
1569         if ((phdr_len + wblock->data.packet.cap_len) % 4) {
1570                 pad_len = 4 - ((phdr_len + wblock->data.packet.cap_len) % 4);
1571         } else {
1572                 pad_len = 0;
1573         }
1574
1575         /* write (enhanced) packet block header */
1576         bh.block_type = wblock->type;
1577         bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + wblock->data.packet.cap_len + pad_len /* + options */ + 4;
1578
1579         nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
1580         if (nwritten != sizeof bh) {
1581                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1582                         *err = wtap_dump_file_ferror(wdh);
1583                 else
1584                         *err = WTAP_ERR_SHORT_WRITE;
1585                 return FALSE;
1586         }
1587         wdh->bytes_dumped += sizeof bh;
1588
1589         /* write block fixed content */
1590         epb.interface_id        = wblock->data.packet.interface_id;
1591         epb.timestamp_high      = wblock->data.packet.ts_high;
1592         epb.timestamp_low       = wblock->data.packet.ts_low;
1593         epb.captured_len        = wblock->data.packet.cap_len + phdr_len;
1594         epb.packet_len          = wblock->data.packet.packet_len + phdr_len;
1595
1596         nwritten = wtap_dump_file_write(wdh, &epb, sizeof epb);
1597         if (nwritten != sizeof epb) {
1598                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1599                         *err = wtap_dump_file_ferror(wdh);
1600                 else
1601                         *err = WTAP_ERR_SHORT_WRITE;
1602                 return FALSE;
1603         }
1604         wdh->bytes_dumped += sizeof epb;
1605
1606         /* write pseudo header */
1607         if (!pcap_write_phdr(wdh, wblock->data.packet.wtap_encap, wblock->pseudo_header, err)) {
1608                 return FALSE;
1609         }
1610         wdh->bytes_dumped += phdr_len;
1611
1612         /* write packet data */
1613         nwritten = wtap_dump_file_write(wdh, wblock->frame_buffer, wblock->data.packet.cap_len);
1614         if (nwritten != wblock->data.packet.cap_len) {
1615                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1616                         *err = wtap_dump_file_ferror(wdh);
1617                 else
1618                         *err = WTAP_ERR_SHORT_WRITE;
1619                 return FALSE;
1620         }
1621         wdh->bytes_dumped += wblock->data.packet.cap_len;
1622
1623         /* write padding (if any) */
1624         if (pad_len != 0) {
1625                 nwritten = wtap_dump_file_write(wdh, &zero_pad, pad_len);
1626                 if (nwritten != pad_len) {
1627                         if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1628                                 *err = wtap_dump_file_ferror(wdh);
1629                         else
1630                                 *err = WTAP_ERR_SHORT_WRITE;
1631                         return FALSE;
1632                 }
1633                 wdh->bytes_dumped += pad_len;
1634         }
1635
1636         /* XXX - write (optional) block options */
1637
1638         /* write block footer */
1639         nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
1640         if (nwritten != sizeof bh.block_total_length) {
1641                 if (nwritten == 0 && wtap_dump_file_ferror(wdh))
1642                         *err = wtap_dump_file_ferror(wdh);
1643                 else
1644                         *err = WTAP_ERR_SHORT_WRITE;
1645                 return FALSE;
1646         }
1647         wdh->bytes_dumped += sizeof bh.block_total_length;
1648
1649         return TRUE;
1650 }
1651
1652
1653 static gboolean
1654 pcapng_write_block(wtap_dumper *wdh, /*pcapng_t *pn, */wtapng_block_t *wblock, int *err)
1655 {
1656         switch(wblock->type) {
1657             case(BLOCK_TYPE_SHB):
1658                 return pcapng_write_section_header_block(wdh, wblock, err);
1659             case(BLOCK_TYPE_IDB):
1660                 return pcapng_write_if_descr_block(wdh, wblock, err);
1661             case(BLOCK_TYPE_PB):
1662                 /* Packet Block is obsolete */
1663                 return FALSE;
1664             case(BLOCK_TYPE_EPB):
1665                 return pcapng_write_packet_block(wdh, wblock, err);
1666             default:
1667                 pcapng_debug1("Unknown block_type: 0x%x", wblock->type);
1668                 return FALSE;
1669         }
1670 }
1671
1672
1673 static guint32
1674 pcapng_lookup_interface_id_by_encap(int wtap_encap, wtap_dumper *wdh)
1675 {
1676         gint i;
1677         interface_data_t int_data;
1678         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1679
1680         for(i = 0; i < (gint)pcapng->number_of_interfaces; i++) {
1681                 int_data = g_array_index(pcapng->interface_data, interface_data_t, i);
1682                 if (wtap_encap == int_data.wtap_encap) {
1683                         return (guint32)i;
1684                 }
1685         }
1686         return G_MAXUINT32;
1687 }
1688
1689
1690 static gboolean pcapng_dump(wtap_dumper *wdh,
1691         const struct wtap_pkthdr *phdr,
1692         const union wtap_pseudo_header *pseudo_header,
1693         const guchar *pd, int *err)
1694 {
1695         wtapng_block_t wblock;
1696         interface_data_t int_data;
1697         guint32 interface_id;
1698         guint64 ts;
1699         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1700
1701         pcapng_debug2("pcapng_dump: encap = %d (%s)",
1702                       phdr->pkt_encap,
1703                       wtap_encap_string(phdr->pkt_encap));
1704
1705         interface_id = pcapng_lookup_interface_id_by_encap(phdr->pkt_encap, wdh);
1706         if (interface_id == G_MAXUINT32) {
1707                 /* write the interface description block */
1708                 wblock.frame_buffer            = NULL;
1709                 wblock.pseudo_header           = NULL;
1710                 wblock.packet_header           = NULL;
1711                 wblock.file_encap              = NULL;
1712                 wblock.type                    = BLOCK_TYPE_IDB;
1713                 wblock.data.if_descr.link_type = wtap_wtap_encap_to_pcap_encap(phdr->pkt_encap);
1714                 wblock.data.if_descr.snap_len  = wdh->snaplen; /* XXX */
1715         
1716                 /* XXX - options unused */
1717                 wblock.data.if_descr.if_speed   = -1;
1718                 wblock.data.if_descr.if_tsresol = 6;    /* default: usec */
1719                 wblock.data.if_descr.if_os      = NULL;
1720                 wblock.data.if_descr.if_fcslen  = -1;
1721         
1722                 if (!pcapng_write_block(wdh, &wblock, err)) {
1723                         return FALSE;
1724                 }
1725
1726                 interface_id = pcapng->number_of_interfaces;
1727                 int_data.wtap_encap = phdr->pkt_encap;
1728                 int_data.time_units_per_second = 0;
1729                 g_array_append_val(pcapng->interface_data, int_data);
1730                 pcapng->number_of_interfaces++;
1731
1732                 pcapng_debug3("pcapng_dump: added interface description block with index %u for encap = %d (%s).",
1733                               interface_id,
1734                               phdr->pkt_encap,
1735                               wtap_encap_string(phdr->pkt_encap));
1736         }
1737
1738         wblock.frame_buffer  = pd;
1739         wblock.pseudo_header = pseudo_header;
1740         wblock.packet_header = NULL;
1741         wblock.file_encap    = NULL;
1742
1743         /* write the (enhanced) packet block */
1744         wblock.type = BLOCK_TYPE_EPB;
1745
1746         /* default is to write out in microsecond resolution */
1747         ts = (((guint64)phdr->ts.secs) * 1000000) + (phdr->ts.nsecs / 1000);
1748
1749         /* Split the 64-bit timestamp into two 32-bit pieces */
1750         wblock.data.packet.ts_high      = (guint32)(ts >> 32);
1751         wblock.data.packet.ts_low       = (guint32)ts;
1752         
1753         wblock.data.packet.cap_len      = phdr->caplen;
1754         wblock.data.packet.packet_len   = phdr->len;
1755         wblock.data.packet.interface_id = interface_id;
1756         wblock.data.packet.wtap_encap   = phdr->pkt_encap;
1757
1758         /* currently unused */
1759         wblock.data.packet.drop_count   = -1;
1760         wblock.data.packet.opt_comment  = NULL;
1761
1762         if (!pcapng_write_block(wdh, &wblock, err)) {
1763                 return FALSE;
1764         }
1765
1766         return TRUE;
1767 }
1768
1769
1770 /* Finish writing to a dump file.
1771    Returns TRUE on success, FALSE on failure. */
1772 static gboolean pcapng_dump_close(wtap_dumper *wdh, int *err _U_)
1773 {
1774         pcapng_dump_t *pcapng = (pcapng_dump_t *)wdh->priv;
1775
1776         pcapng_debug0("pcapng_dump_close");
1777         g_array_free(pcapng->interface_data, TRUE);
1778         pcapng->number_of_interfaces = 0;
1779         return TRUE;
1780 }
1781
1782
1783 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1784    failure */
1785 gboolean 
1786 pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
1787 {
1788         wtapng_block_t wblock;
1789         pcapng_dump_t *pcapng;
1790
1791         wblock.frame_buffer  = NULL;
1792         wblock.pseudo_header = NULL;
1793         wblock.packet_header = NULL;
1794         wblock.file_encap    = NULL;
1795
1796         pcapng_debug0("pcapng_dump_open");
1797         /* This is a pcapng file */
1798         wdh->subtype_write = pcapng_dump;
1799         wdh->subtype_close = pcapng_dump_close;
1800         pcapng = (pcapng_dump_t *)g_malloc(sizeof(pcapng_dump_t));
1801         wdh->priv = (void *)pcapng;
1802         pcapng->interface_data = g_array_new(FALSE, FALSE, sizeof(interface_data_t));
1803         pcapng->number_of_interfaces = 0;
1804
1805         /* write the section header block */
1806         wblock.type = BLOCK_TYPE_SHB;
1807         wblock.data.section.section_length = -1;
1808
1809         /* XXX - options unused */
1810         wblock.data.section.opt_comment   = NULL;
1811         wblock.data.section.shb_hardware  = NULL;
1812         wblock.data.section.shb_os        = NULL;
1813         wblock.data.section.shb_user_appl = NULL;
1814
1815         if (!pcapng_write_block(wdh, &wblock, err)) {
1816                 return FALSE;
1817         }
1818         pcapng_debug0("pcapng_dump_open: wrote section header block.");
1819
1820         return TRUE;
1821 }
1822
1823
1824 /* Returns 0 if we could write the specified encapsulation type,
1825    an error indication otherwise. */
1826 int pcapng_dump_can_write_encap(int wtap_encap)
1827 {
1828         pcapng_debug2("pcapng_dump_can_write_encap: encap = %d (%s)",
1829                       wtap_encap,
1830                       wtap_encap_string(wtap_encap));
1831         
1832         /* Per-packet encapsulations is supported. */
1833         if (wtap_encap == WTAP_ENCAP_PER_PACKET)
1834                 return 0;
1835
1836         /* Make sure we can figure out this DLT type */
1837         if (wtap_wtap_encap_to_pcap_encap(wtap_encap) == -1)
1838                 return WTAP_ERR_UNSUPPORTED_ENCAP;
1839
1840         return 0;
1841 }