source: lib/format_pcapng.c @ 32ee9b2

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 32ee9b2 was 32ee9b2, checked in by Shane Alcock <salcock@…>, 3 years ago

Add new trace_flush_output() to public API

Can be used to force a libtrace output to dump any buffered output
to disk immediately.

Note that if the file is compressed or the output trace format
requires a trailer, the flushed file will still not be properly
readable afterwards as this will not result in any trailers
being written. You'll still have to close the file for that.

Mainly this is useful for ensuring that output file sizes grow
over time in situations where the amount of output is relatively
small, rather than staying stuck at 0 bytes until we either reach
1MB of output or the file is closed. For instance, you could have
a timer that calls trace_flush_output() every 30 seconds so that
the output file size will grow if any packets were written in the
last 30 seconds.

  • Property mode set to 100644
File size: 49.5 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace 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 Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "common.h"
27#include "config.h"
28#include "libtrace.h"
29#include "libtrace_int.h"
30#include "format_helper.h"
31
32#include <sys/stat.h>
33#include <assert.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <stdbool.h>
40#include <math.h>
41
42#define PCAPNG_SECTION_TYPE 0x0A0D0D0A
43#define PCAPNG_INTERFACE_TYPE 0x00000001
44#define PCAPNG_OLD_PACKET_TYPE 0x00000002
45#define PCAPNG_SIMPLE_PACKET_TYPE 0x00000003
46#define PCAPNG_NAME_RESOLUTION_TYPE 0x00000004
47#define PCAPNG_INTERFACE_STATS_TYPE 0x00000005
48#define PCAPNG_ENHANCED_PACKET_TYPE 0x00000006
49#define PCAPNG_CUSTOM_TYPE 0x00000BAD
50#define PCAPNG_CUSTOM_NONCOPY_TYPE 0x40000BAD
51
52#define PACKET_IS_ENHANCED (pcapng_get_record_type(packet) == PCAPNG_ENHANCED_PACKET_TYPE)
53
54#define PACKET_IS_SIMPLE (pcapng_get_record_type(packet) == PCAPNG_SIMPLE_PACKET_TYPE)
55
56#define PACKET_IS_OLD (pcapng_get_record_type(packet) == PCAPNG_OLD_PACKET_TYPE)
57
58
59#define PCAPNG_IFOPT_TSRESOL 9
60
61#define PCAPNG_PKTOPT_DROPCOUNT 4
62
63#define PCAPNG_STATOPT_START 2
64#define PCAPNG_STATOPT_END 3
65#define PCAPNG_STATOPT_IFRECV 4
66#define PCAPNG_STATOPT_IFDROP 5
67#define PCAPNG_STATOPT_FILTERACCEPT 6
68#define PCAPNG_STATOPT_OSDROP 7
69#define PCAPNG_STATOPT_USRDELIV 8
70
71typedef struct pcagng_section_header_t {
72        uint32_t blocktype;
73        uint32_t blocklen;
74        uint32_t ordering;
75        uint16_t majorversion;
76        uint16_t minorversion;
77        uint64_t sectionlen;
78} pcapng_sec_t;
79
80typedef struct pcapng_interface_header_t {
81        uint32_t blocktype;
82        uint32_t blocklen;
83        uint16_t linktype;
84        uint16_t reserved;
85        uint32_t snaplen;
86} pcapng_int_t;
87
88typedef struct pcapng_nrb_header_t {
89        uint32_t blocktype;
90        uint32_t blocklen;
91} pcapng_nrb_t;
92
93typedef struct pcapng_enhanced_packet_t {
94        uint32_t blocktype;
95        uint32_t blocklen;
96        uint32_t interfaceid;
97        uint32_t timestamp_high;
98        uint32_t timestamp_low;
99        uint32_t caplen;
100        uint32_t wlen;
101} pcapng_epkt_t;
102
103typedef struct pcapng_simple_packet_t {
104        uint32_t blocktype;
105        uint32_t blocklen;
106        uint32_t wlen;
107} pcapng_spkt_t;
108
109typedef struct pcapng_old_packet_t {
110        uint32_t blocktype;
111        uint32_t blocklen;
112        uint16_t interfaceid;
113        uint16_t drops;
114        uint32_t timestamp_high;
115        uint32_t timestamp_low;
116        uint32_t caplen;
117        uint32_t wlen;
118} pcapng_opkt_t;
119
120typedef struct pcapng_stats_header_t {
121        uint32_t blocktype;
122        uint32_t blocklen;
123        uint32_t interfaceid;
124        uint32_t timestamp_high;
125        uint32_t timestamp_low;
126} pcapng_stats_t;
127
128typedef struct pcapng_custom_header_t {
129        uint32_t blocktype;
130        uint32_t blocklen;
131        uint32_t pen;
132} pcapng_custom_t;
133
134typedef struct pcapng_interface_t pcapng_interface_t;
135
136struct pcapng_interface_t {
137
138        uint16_t id;
139        libtrace_dlt_t linktype;
140        uint32_t snaplen;
141        uint32_t tsresol;
142
143        uint64_t received;
144        uint64_t dropped;       /* as reported by interface stats */
145        uint64_t dropcounter;   /* as reported by packet records */
146        uint64_t accepted;
147        uint64_t osdropped;
148        uint64_t laststats;
149
150};
151
152struct pcapng_format_data_t {
153        bool started;
154        bool realtime;
155
156        /* Section data */
157        bool byteswapped;
158
159        /* Interface data */
160        pcapng_interface_t **interfaces;
161        uint16_t allocatedinterfaces;
162        uint16_t nextintid;
163};
164
165struct pcapng_optheader {
166        uint16_t optcode;
167        uint16_t optlen;
168};
169
170struct pcapng_peeker {
171        uint32_t blocktype;
172        uint32_t blocklen;
173};
174
175
176#define DATA(x) ((struct pcapng_format_data_t *)((x)->format_data))
177
178static pcapng_interface_t *lookup_interface(libtrace_t *libtrace,
179                uint32_t intid) {
180
181
182        if (intid >= DATA(libtrace)->nextintid) {
183                return NULL;
184        }
185
186        return DATA(libtrace)->interfaces[intid];
187
188}
189
190static inline uint32_t pcapng_get_record_type(const libtrace_packet_t *packet) {
191
192        uint32_t *btype = (uint32_t *)packet->header;
193
194        if (DATA(packet->trace)->byteswapped)
195                return byteswap32(*btype);
196        return *btype;
197}
198
199static int pcapng_probe_magic(io_t *io) {
200
201        pcapng_sec_t sechdr;
202        int len;
203
204        len = wandio_peek(io, &sechdr, sizeof(sechdr));
205        if (len < (int)sizeof(sechdr)) {
206                return 0;
207        }
208
209        if (sechdr.blocktype == PCAPNG_SECTION_TYPE) {
210                return 1;
211        }
212        return 0;
213}
214
215
216static int pcapng_init_input(libtrace_t *libtrace) {
217        libtrace->format_data = malloc(sizeof(struct pcapng_format_data_t));
218        if (libtrace->format_data == NULL) {
219                trace_set_err(libtrace, ENOMEM, "Out of memory!");
220                return -1;
221        }
222
223        DATA(libtrace)->started = false;
224        DATA(libtrace)->realtime = false;
225        DATA(libtrace)->byteswapped = true;
226        DATA(libtrace)->interfaces = (pcapng_interface_t **)calloc(10, \
227                        sizeof(pcapng_interface_t));
228        DATA(libtrace)->allocatedinterfaces = 10;
229        DATA(libtrace)->nextintid = 0;
230
231        return 0;
232}
233
234static int pcapng_start_input(libtrace_t *libtrace) {
235
236        if (!libtrace->io) {
237                libtrace->io = trace_open_file(libtrace);
238        }
239
240        if (!libtrace->io)
241                return -1;
242
243        return 0;
244}
245
246static int pcapng_config_input(libtrace_t *libtrace, trace_option_t option,
247                void *data) {
248
249        switch(option) {
250                case TRACE_OPTION_EVENT_REALTIME:
251                        if (*(int *)data != 0) {
252                                DATA(libtrace)->realtime = true;
253                        } else {
254                                DATA(libtrace)->realtime = false;
255                        }
256                        return 0;
257                case TRACE_OPTION_META_FREQ:
258                case TRACE_OPTION_SNAPLEN:
259                case TRACE_OPTION_PROMISC:
260                case TRACE_OPTION_FILTER:
261                case TRACE_OPTION_HASHER:
262                case TRACE_OPTION_REPLAY_SPEEDUP:
263                        break;
264        }
265
266        trace_set_err(libtrace, TRACE_ERR_UNKNOWN_OPTION, "Unknown option %i",
267                        option);
268        return -1;
269}
270
271static int pcapng_fin_input(libtrace_t *libtrace) {
272
273        int i = 0;
274
275        for (i = 0; i < DATA(libtrace)->allocatedinterfaces; i++) {
276                free(DATA(libtrace)->interfaces[i]);
277        }
278
279        free(DATA(libtrace)->interfaces);
280
281        if (libtrace->io) {
282                wandio_destroy(libtrace->io);
283        }
284        free(libtrace->format_data);
285        return 0;
286}
287
288static char *pcapng_parse_next_option(libtrace_t *libtrace, char **pktbuf,
289                uint16_t *code, uint16_t *length) {
290
291        struct pcapng_optheader *opthdr = (struct pcapng_optheader *)*pktbuf;
292        int to_skip;
293        int padding = 0;
294        char *optval;
295
296        if (DATA(libtrace)->byteswapped) {
297                *code = byteswap16(opthdr->optcode);
298                *length = byteswap16(opthdr->optlen);
299        } else {
300                *code = opthdr->optcode;
301                *length = opthdr->optlen;
302        }
303
304        optval = *pktbuf + sizeof(struct pcapng_optheader);
305
306        if ((*length % 4) > 0) {
307                padding = (4 - (*length % 4));
308        } else {
309                padding = 0;
310        }
311
312        to_skip = (*length) + padding;
313        *pktbuf = optval + to_skip;
314
315        return optval;
316}
317
318static inline int skip_block(libtrace_t *libtrace, uint32_t toread) {
319        int err;
320
321        while (toread > 0) {
322                char buf[4096];
323                int nextread;
324
325                if (toread < 4096) {
326                        nextread = toread;
327                } else {
328                        nextread = 4096;
329                }
330
331                err = wandio_read(libtrace->io, buf, nextread);
332                if (err < 0) {
333                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
334                                "Reading section header options");
335                        return -1;
336                }
337                if (err == 0) {
338                        return 0;
339                }
340                toread -= err;
341        }
342
343        return 1;
344
345}
346
347static inline int pcapng_read_body(libtrace_t *libtrace, char *body,
348                uint32_t to_read) {
349
350        int err;
351
352        err = wandio_read(libtrace->io, body, to_read);
353        if (err < 0) {
354                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
355                        "Failed to read pcapng interface options");
356                return err;
357        }
358
359        if (err == 0) {
360                return err;
361        }
362
363        if (err < (int)to_read) {
364                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
365                        "Incomplete pcapng interface header block");
366                return -1;
367        }
368
369        return to_read;
370}
371
372static int pcapng_get_framing_length(const libtrace_packet_t *packet) {
373
374        switch(pcapng_get_record_type(packet)) {
375                case PCAPNG_SECTION_TYPE:
376                        return sizeof(pcapng_sec_t);
377                case PCAPNG_INTERFACE_TYPE:
378                        return sizeof(pcapng_int_t);
379                case PCAPNG_ENHANCED_PACKET_TYPE:
380                        return sizeof(pcapng_epkt_t);
381                case PCAPNG_SIMPLE_PACKET_TYPE:
382                        return sizeof(pcapng_spkt_t);
383                case PCAPNG_OLD_PACKET_TYPE:
384                        return sizeof(pcapng_opkt_t);
385                case PCAPNG_INTERFACE_STATS_TYPE:
386                        return sizeof(pcapng_stats_t);
387                case PCAPNG_NAME_RESOLUTION_TYPE:
388                        return sizeof(pcapng_nrb_t);
389                case PCAPNG_CUSTOM_TYPE:
390                case PCAPNG_CUSTOM_NONCOPY_TYPE:
391                        return sizeof(pcapng_custom_t);
392        }
393
394        /* If we get here, we aren't a valid pcapng packet */
395        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
396                        "Invalid RT type for pcapng packet: %u",
397                        packet->type);
398        return -1;
399
400}
401
402static int pcapng_prepare_packet(libtrace_t *libtrace,
403                libtrace_packet_t *packet, void *buffer,
404                libtrace_rt_types_t rt_type, uint32_t flags) {
405
406        int hdrlen;
407
408        if (packet->buffer != buffer &&
409                        packet->buf_control == TRACE_CTRL_PACKET) {
410                free(packet->buffer);
411        }
412
413        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
414                packet->buf_control = TRACE_CTRL_PACKET;
415        } else {
416                packet->buf_control = TRACE_CTRL_EXTERNAL;
417        }
418
419        packet->type = rt_type;
420        packet->buffer = buffer;
421        packet->header = buffer;
422
423        hdrlen = pcapng_get_framing_length(packet);
424        if (hdrlen < 0) {
425                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
426                                "X Invalid RT type for pcapng packet: %u",
427                                packet->type);
428                return -1;
429        }
430        packet->payload = ((char *)packet->buffer) + hdrlen;
431
432        return 0;
433}
434
435static int pcapng_read_section(libtrace_t *libtrace,
436                libtrace_packet_t *packet, uint32_t flags) {
437
438        pcapng_sec_t *sechdr;
439        int err;
440        uint32_t to_read;
441        char *bodyptr = NULL;
442
443        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_sec_t));
444        sechdr = (pcapng_sec_t *)packet->buffer;
445
446        if (err < 0) {
447                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
448                        "Reading pcapng section header block");
449                return -1;
450        }
451
452        if (err == 0) {
453                return 0;
454        }
455
456        if (err < (int)(sizeof(sechdr))) {
457                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
458                        "Incomplete pcapng section header block");
459                return -1;
460        }
461
462        assert(sechdr->blocktype == PCAPNG_SECTION_TYPE);
463
464        if (sechdr->ordering == 0x1A2B3C4D) {
465                DATA(libtrace)->byteswapped = false;
466        } else if (sechdr->ordering == 0x4D3C2B1A) {
467                DATA(libtrace)->byteswapped = true;
468        } else {
469                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
470                                "Parsing pcapng section header block");
471                return -1;
472        }
473
474
475        if (DATA(libtrace)->byteswapped) {
476                if (byteswap16(sechdr->majorversion) != 1 && byteswap16(sechdr->minorversion) != 0) {
477                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
478                                "Parsing pcapng version numbers");
479                        return -1;
480                }
481                to_read = byteswap32(sechdr->blocklen) - sizeof(pcapng_sec_t);
482        } else {
483                if (sechdr->majorversion != 1 && sechdr->minorversion != 0) {
484                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
485                                "Parsing pcapng version numbers");
486                        return -1;
487                }
488                to_read = sechdr->blocklen - sizeof(pcapng_sec_t);
489        }
490
491        /* Read all of the options etc. -- we don't need them for now, but
492         * we have to skip forward to the next useful header. */
493        bodyptr = packet->buffer + sizeof(pcapng_sec_t);
494        err = pcapng_read_body(libtrace, bodyptr, to_read);
495        if (err <= 0) {
496                return err;
497        }
498
499        packet->type = TRACE_RT_PCAPNG_META;
500        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
501                        packet->type, flags)) {
502                return -1;
503        }
504
505        return 1;
506}
507
508static int pcapng_read_interface(libtrace_t *libtrace,
509                libtrace_packet_t *packet, uint32_t flags) {
510
511        pcapng_int_t *inthdr;
512        int err;
513        uint32_t to_read;
514        pcapng_interface_t *newint;
515        uint16_t optcode, optlen;
516        char *optval = NULL;
517        char *bodyptr = NULL;
518
519        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_int_t));
520
521        if (err < 0) {
522                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
523                        "Reading pcapng interface header block");
524                return -1;
525        }
526
527        if (err == 0) {
528                return 0;
529        }
530
531        if (err < (int)sizeof(inthdr)) {
532                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
533                        "Incomplete pcapng interface header block");
534                return -1;
535        }
536        inthdr = (pcapng_int_t *)packet->buffer;
537
538        newint = (pcapng_interface_t *)malloc(sizeof(pcapng_interface_t));
539
540        newint->id = DATA(libtrace)->nextintid;
541
542        newint->received = 0;
543        newint->dropped = 0;
544        newint->dropcounter = 0;
545        newint->accepted = 0;
546        newint->osdropped = 0;
547        newint->laststats = 0;
548        newint->tsresol = 1000000;
549
550        if (DATA(libtrace)->byteswapped) {
551                assert(byteswap32(inthdr->blocktype) == PCAPNG_INTERFACE_TYPE);
552                newint->snaplen = byteswap32(inthdr->snaplen);
553                newint->linktype = byteswap16(inthdr->linktype);
554                to_read = byteswap32(inthdr->blocklen) - sizeof(pcapng_int_t);
555        } else {
556                assert(inthdr->blocktype == PCAPNG_INTERFACE_TYPE);
557                newint->snaplen = inthdr->snaplen;
558                newint->linktype = inthdr->linktype;
559                to_read = inthdr->blocklen - sizeof(pcapng_int_t);
560        }
561
562        if (DATA(libtrace)->nextintid == DATA(libtrace)->allocatedinterfaces) {
563                DATA(libtrace)->allocatedinterfaces += 10;
564                DATA(libtrace)->interfaces = (pcapng_interface_t **)realloc(
565                        DATA(libtrace)->interfaces,
566                        DATA(libtrace)->allocatedinterfaces * sizeof(
567                                pcapng_interface_t *));
568
569                /* Could memset the new memory to zero, if required */
570        }
571
572        DATA(libtrace)->interfaces[newint->id] = newint;
573        DATA(libtrace)->nextintid += 1;
574
575        bodyptr = packet->buffer + sizeof(pcapng_int_t);
576        err = pcapng_read_body(libtrace, bodyptr, to_read);
577        if (err <= 0) {
578                return err;
579        }
580
581        packet->type = TRACE_RT_PCAPNG_META;
582
583        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
584                        packet->type, flags)) {
585                return -1;
586        }
587
588        do {
589                optval = pcapng_parse_next_option(libtrace, &bodyptr,
590                                &optcode, &optlen);
591                if (optval == NULL) {
592                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
593                                "Failed to read options for pcapng interface");
594                        return -1;
595                }
596
597                if (optcode == PCAPNG_IFOPT_TSRESOL) {
598                        uint8_t *resol = (uint8_t *)optval;
599
600                        if ((*resol & 0x80) != 0) {
601                                newint->tsresol = pow(2, *resol & 0x7f);
602
603                        } else {
604                                newint->tsresol = pow(10, *resol & 0x7f);
605                        }
606                }
607
608        } while (optcode != 0);
609
610        return 1;
611
612}
613
614static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
615                uint32_t flags) {
616
617        /* Just read the NR records and pass them off to the caller. If
618         * they want to do anything with them, they can parse the records
619         * themselves.
620         */
621        pcapng_nrb_t *hdr = NULL;
622        int err;
623        uint32_t to_read;
624        char *bodyptr;
625
626        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_nrb_t));
627
628        if (err < 0) {
629                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng name resolution block");
630                return -1;
631        }
632
633        if (err == 0) {
634                return 0;
635        }
636
637        if (err < (int)sizeof(pcapng_nrb_t)) {
638                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
639                                "Incomplete pcapng name resolution block");
640                return -1;
641        }
642
643        hdr = (pcapng_nrb_t *)packet->buffer;
644
645        /* Read the rest of the packet into the buffer */
646        if (DATA(libtrace)->byteswapped) {
647                assert(byteswap32(hdr->blocktype) == PCAPNG_NAME_RESOLUTION_TYPE);
648                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_nrb_t);
649        } else {
650                assert(hdr->blocktype == PCAPNG_NAME_RESOLUTION_TYPE);
651                to_read = hdr->blocklen - sizeof(pcapng_nrb_t);
652        }
653
654        bodyptr = packet->buffer + sizeof(pcapng_nrb_t);
655        err = pcapng_read_body(libtrace, bodyptr, to_read);
656        if (err <= 0) {
657                return err;
658        }
659
660        packet->type = TRACE_RT_PCAPNG_META;
661        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
662                        packet->type, flags)) {
663                return -1;
664        }
665
666        return sizeof(pcapng_nrb_t) + to_read;
667
668}
669
670static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
671                uint32_t flags) {
672
673        /* Just read the custom records and pass them off to the caller. If
674         * they want to do anything with them, they can parse the records
675         * themselves.
676         */
677        pcapng_custom_t *hdr = NULL;
678        int err;
679        uint32_t to_read;
680        char *bodyptr;
681
682        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_custom_t));
683
684        if (err < 0) {
685                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng custom block");
686                return -1;
687        }
688
689        if (err == 0) {
690                return 0;
691        }
692
693        if (err < (int)sizeof(pcapng_custom_t)) {
694                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
695                                "Incomplete pcapng custom block");
696                return -1;
697        }
698
699        hdr = (pcapng_custom_t *)packet->buffer;
700
701        /* Read the rest of the packet into the buffer */
702        if (DATA(libtrace)->byteswapped) {
703                assert(byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_TYPE ||
704                        byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_NONCOPY_TYPE);
705                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_custom_t);
706        } else {
707                assert(hdr->blocktype == PCAPNG_NAME_RESOLUTION_TYPE ||
708                        hdr->blocktype == PCAPNG_CUSTOM_NONCOPY_TYPE);
709                to_read = hdr->blocklen - sizeof(pcapng_custom_t);
710        }
711
712        bodyptr = packet->buffer + sizeof(pcapng_custom_t);
713        err = pcapng_read_body(libtrace, bodyptr, to_read);
714        if (err <= 0) {
715                return err;
716        }
717
718        packet->type = TRACE_RT_PCAPNG_META;
719        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
720                        packet->type, flags)) {
721                return -1;
722        }
723
724        return sizeof(pcapng_custom_t) + to_read;
725
726}
727
728static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
729                uint32_t flags) {
730        pcapng_stats_t *hdr = NULL;
731        int err;
732        uint32_t to_read;
733        uint32_t ifaceid;
734        uint64_t timestamp;
735        pcapng_interface_t *interface;
736        uint16_t optcode, optlen;
737        char *optval;
738        char *bodyptr;
739
740        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_stats_t));
741
742        if (err < 0) {
743                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng interface stats");
744                return -1;
745        }
746
747        if (err == 0) {
748                return 0;
749        }
750
751        if (err < (int)sizeof(pcapng_stats_t)) {
752                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
753                                "Incomplete pcapng interface stats header");
754                return -1;
755        }
756
757        hdr = (pcapng_stats_t *)packet->buffer;
758
759        /* Read the rest of the packet into the buffer */
760        if (DATA(libtrace)->byteswapped) {
761                assert(byteswap32(hdr->blocktype) == PCAPNG_INTERFACE_STATS_TYPE);
762                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_stats_t);
763                ifaceid = byteswap32(hdr->interfaceid);
764                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
765        } else {
766                assert(hdr->blocktype == PCAPNG_INTERFACE_STATS_TYPE);
767                to_read = hdr->blocklen - sizeof(pcapng_stats_t);
768                ifaceid = hdr->interfaceid;
769                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
770                                hdr->timestamp_low;
771        }
772
773        bodyptr = packet->buffer + sizeof(pcapng_stats_t);
774        err = pcapng_read_body(libtrace, bodyptr, to_read);
775        if (err <= 0) {
776                return err;
777        }
778
779        /* Set packet type based on interface linktype */
780        interface = lookup_interface(libtrace, ifaceid);
781        if (interface == NULL) {
782                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
783                return -1;
784        }
785        packet->type = TRACE_RT_PCAPNG_META;
786
787        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
788                        packet->type, flags)) {
789                return -1;
790        }
791
792        if (timestamp < interface->laststats) {
793                return sizeof(pcapng_stats_t) + to_read;
794        }
795
796        /* All of the stats are stored as options */
797        bodyptr = packet->payload;
798
799        do {
800                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
801                                &optcode, &optlen);
802                if (optval == NULL) {
803                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
804                                "Failed to read options for pcapng enhanced packet");
805                        return -1;
806                }
807
808                if (optcode == PCAPNG_STATOPT_IFRECV) {
809                        uint64_t *recvd = (uint64_t *)optval;
810                        if (DATA(packet->trace)->byteswapped) {
811                                interface->received = byteswap64(*recvd);
812                        } else {
813                                interface->received = *recvd;
814                        }
815                }
816
817                if (optcode == PCAPNG_STATOPT_IFDROP) {
818                        uint64_t *drops = (uint64_t *)optval;
819                        if (DATA(packet->trace)->byteswapped) {
820                                interface->dropped = byteswap64(*drops);
821                        } else {
822                                interface->dropped = *drops;
823                        }
824                }
825
826                if (optcode == PCAPNG_STATOPT_OSDROP) {
827                        uint64_t *drops = (uint64_t *)optval;
828                        if (DATA(packet->trace)->byteswapped) {
829                                interface->osdropped = byteswap64(*drops);
830                        } else {
831                                interface->osdropped = *drops;
832                        }
833                }
834
835                if (optcode == PCAPNG_STATOPT_FILTERACCEPT) {
836                        uint64_t *accepts = (uint64_t *)optval;
837                        if (DATA(packet->trace)->byteswapped) {
838                                interface->accepted = byteswap64(*accepts);
839                        } else {
840                                interface->accepted = *accepts;
841                        }
842                }
843
844        } while (optcode != 0);
845        interface->laststats = timestamp;
846
847        return sizeof(pcapng_stats_t) + to_read;
848
849}
850
851static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
852                uint32_t flags) {
853
854        int err;
855        uint32_t to_read;
856        uint32_t caplen;
857        pcapng_spkt_t *hdr = NULL;
858        pcapng_interface_t *interface;
859        char *bodyptr;
860
861        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_spkt_t));
862
863        if (err < 0) {
864                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng simple packet");
865                return -1;
866        }
867
868        if (err == 0) {
869                return 0;
870        }
871
872        if (err < (int)sizeof(pcapng_spkt_t)) {
873                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
874                                "Incomplete pcapng simple packet header");
875                return -1;
876        }
877
878        hdr = (pcapng_spkt_t *)packet->buffer;
879
880        /* Read the rest of the packet into the buffer */
881        if (DATA(libtrace)->byteswapped) {
882                assert(byteswap32(hdr->blocktype) == PCAPNG_SIMPLE_PACKET_TYPE);
883                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t);
884                caplen = to_read - 4;   /* account for trailing length field */
885        } else {
886                assert(hdr->blocktype == PCAPNG_SIMPLE_PACKET_TYPE);
887                to_read = hdr->blocklen - sizeof(pcapng_spkt_t);
888                caplen = to_read - 4; /* account for trailing length field */
889        }
890
891        bodyptr = packet->buffer + sizeof(pcapng_spkt_t);
892        err = pcapng_read_body(libtrace, bodyptr, to_read);
893        if (err <= 0) {
894                return err;
895        }
896
897        /* Set packet type based on interface linktype.
898         * Assume interface 0, since we have no interface field */
899        interface = lookup_interface(libtrace, 0);
900        if (interface == NULL) {
901                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", 0);
902                return -1;
903        }
904        packet->type = pcapng_linktype_to_rt(interface->linktype);
905
906        /* May as well cache the capture length now, since we've
907         * already got it in the right byte order */
908        packet->capture_length = caplen;
909
910        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
911                        packet->type, flags)) {
912                return -1;
913        }
914        return sizeof(pcapng_spkt_t) + to_read;
915
916}
917
918static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
919                uint32_t flags) {
920        pcapng_epkt_t *hdr = NULL;
921        int err;
922        uint32_t to_read;
923        uint32_t caplen;
924        uint32_t ifaceid;
925        pcapng_interface_t *interface;
926        uint16_t optcode, optlen;
927        char *optval;
928        char *bodyptr;
929
930        err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_epkt_t));
931
932        if (err < 0) {
933                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng enhanced packet");
934                return -1;
935        }
936
937        if (err == 0) {
938                return 0;
939        }
940
941        if (err < (int)sizeof(pcapng_epkt_t)) {
942                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
943                                "Incomplete pcapng enhanced packet header");
944                return -1;
945        }
946
947        hdr = (pcapng_epkt_t *)packet->buffer;
948
949        /* Read the rest of the packet into the buffer */
950        if (DATA(libtrace)->byteswapped) {
951                assert(byteswap32(hdr->blocktype) == PCAPNG_ENHANCED_PACKET_TYPE);
952                caplen = byteswap32(hdr->caplen);
953                to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_epkt_t);
954                ifaceid = byteswap32(hdr->interfaceid);
955        } else {
956                assert(hdr->blocktype == PCAPNG_ENHANCED_PACKET_TYPE);
957                caplen = hdr->caplen;
958                to_read = hdr->blocklen - sizeof(pcapng_epkt_t);
959                ifaceid = hdr->interfaceid;
960        }
961
962        bodyptr = packet->buffer + sizeof(pcapng_epkt_t);
963        err = pcapng_read_body(libtrace, bodyptr, to_read);
964        if (err <= 0) {
965                return err;
966        }
967
968        /* Set packet type based on interface linktype */
969        interface = lookup_interface(libtrace, ifaceid);
970        if (interface == NULL) {
971                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Unknown pcapng interface id: %u", ifaceid);
972                return -1;
973        }
974        packet->type = pcapng_linktype_to_rt(interface->linktype);
975
976        /* May as well cache the capture length now, since we've
977         * already got it in the right byte order */
978        packet->capture_length = caplen;
979
980        if (pcapng_prepare_packet(libtrace, packet, packet->buffer,
981                        packet->type, flags)) {
982                return -1;
983        }
984
985        /* Make sure to parse any useful options */
986        if ((caplen % 4) == 0) {
987                bodyptr = packet->payload + caplen;
988        } else {
989                bodyptr = packet->payload + caplen + (4 - (caplen % 4));
990        }
991
992        do {
993                optval = pcapng_parse_next_option(packet->trace, &bodyptr,
994                                &optcode, &optlen);
995                if (optval == NULL) {
996                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
997                                "Failed to read options for pcapng enhanced packet");
998                        return -1;
999                }
1000
1001                if (optcode == PCAPNG_PKTOPT_DROPCOUNT) {
1002                        uint64_t *drops = (uint64_t *)optval;
1003                        if (DATA(packet->trace)->byteswapped) {
1004                                interface->dropcounter += byteswap64(*drops);
1005                        } else {
1006                                interface->dropcounter += *drops;
1007                        }
1008                }
1009
1010        } while (optcode != 0);
1011        return sizeof(pcapng_epkt_t) + to_read;
1012
1013}
1014
1015static int pcapng_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
1016{
1017        struct pcapng_peeker peeker;
1018        int err = 0;
1019        uint32_t flags = 0;
1020        uint32_t to_read;
1021        uint32_t btype = 0;
1022        int gotpacket = 0;
1023
1024        /* Peek to get next block type */
1025        assert(libtrace->format_data);
1026        assert(libtrace->io);
1027
1028        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
1029                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
1030        }
1031
1032        flags |= TRACE_PREP_OWN_BUFFER;
1033
1034        while (!gotpacket) {
1035
1036                if ((err=is_halted(libtrace)) != -1) {
1037                        return err;
1038                }
1039
1040                err = wandio_peek(libtrace->io, &peeker, sizeof(peeker));
1041                if (err < 0) {
1042                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng packet");
1043                        return -1;
1044                }
1045
1046                if (err == 0) {
1047                        return 0;
1048                }
1049
1050                if (err < (int)sizeof(struct pcapng_peeker)) {
1051                        trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "Incomplete pcapng block");
1052                        return -1;
1053                }
1054
1055                if (DATA(libtrace)->byteswapped) {
1056                        btype = byteswap32(peeker.blocktype);
1057                } else {
1058                        btype = peeker.blocktype;
1059                }
1060
1061                switch (btype) {
1062                        /* Section Header */
1063                        case PCAPNG_SECTION_TYPE:
1064                                err = pcapng_read_section(libtrace, packet, flags);
1065                                gotpacket = 1;
1066                                break;
1067
1068                        /* Interface Header */
1069                        case PCAPNG_INTERFACE_TYPE:
1070                                err = pcapng_read_interface(libtrace, packet, flags);
1071                                gotpacket = 1;
1072                                break;
1073
1074
1075                        case PCAPNG_ENHANCED_PACKET_TYPE:
1076                                err = pcapng_read_enhanced(libtrace, packet,
1077                                                flags);
1078                                gotpacket = 1;
1079                                break;
1080
1081                        case PCAPNG_SIMPLE_PACKET_TYPE:
1082                                err = pcapng_read_simple(libtrace, packet, flags);
1083                                gotpacket = 1;
1084                                break;
1085
1086                        case PCAPNG_INTERFACE_STATS_TYPE:
1087                                err = pcapng_read_stats(libtrace, packet, flags);
1088                                gotpacket = 1;
1089                                break;
1090
1091                        case PCAPNG_NAME_RESOLUTION_TYPE:
1092                                err = pcapng_read_nrb(libtrace, packet, flags);
1093                                gotpacket = 1;
1094                                break;
1095
1096                        case PCAPNG_CUSTOM_TYPE:
1097                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
1098                                err = pcapng_read_custom(libtrace, packet, flags);
1099                                gotpacket = 1;
1100                                break;
1101
1102
1103                        case PCAPNG_OLD_PACKET_TYPE:
1104                                /* TODO */
1105
1106                        /* Everything else -- don't care, skip it */
1107                        default:
1108                                if (DATA(libtrace)->byteswapped) {
1109                                        to_read = byteswap32(peeker.blocklen);
1110                                } else {
1111                                        to_read = peeker.blocklen;
1112                                }
1113                                err = skip_block(libtrace, to_read);
1114                                break;
1115                }
1116        }
1117
1118        if (err <= 0) {
1119                return err;
1120        }
1121
1122        if (DATA(libtrace)->byteswapped)
1123                return byteswap32(peeker.blocklen);
1124        return peeker.blocklen;
1125
1126}
1127
1128static libtrace_linktype_t pcapng_get_link_type(const libtrace_packet_t *packet)
1129{
1130
1131        return pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type));
1132
1133}
1134
1135static libtrace_direction_t pcapng_get_direction(const libtrace_packet_t
1136                *packet) {
1137
1138        /* Defined in format_helper.c */
1139        return pcap_get_direction(packet);
1140}
1141
1142static struct timespec pcapng_get_timespec(const libtrace_packet_t *packet) {
1143
1144        struct timespec ts;
1145        uint64_t timestamp = 0;
1146        uint32_t interfaceid = 0;
1147        pcapng_interface_t *interface;
1148
1149        assert(packet->header);
1150
1151        ts.tv_sec = 0;
1152        ts.tv_nsec = 0;
1153
1154        /* No timestamps in simple packets :( */
1155        if (PACKET_IS_SIMPLE) {
1156                return ts;
1157        }
1158
1159        if (PACKET_IS_ENHANCED) {
1160                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1161
1162                if (DATA(packet->trace)->byteswapped) {
1163                        timestamp = ((uint64_t)(byteswap32(ehdr->timestamp_high)) << 32) + byteswap32(ehdr->timestamp_low);
1164                        interfaceid = byteswap32(ehdr->interfaceid);
1165                } else {
1166                        timestamp = ((uint64_t)(ehdr->timestamp_high) << 32) +
1167                                        ehdr->timestamp_low;
1168                        interfaceid = ehdr->interfaceid;
1169                }
1170        } else if (PACKET_IS_OLD) {
1171                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1172
1173                if (DATA(packet->trace)->byteswapped) {
1174                        timestamp = ((uint64_t)(byteswap32(ohdr->timestamp_high)) << 32) + byteswap32(ohdr->timestamp_low);
1175                        interfaceid = byteswap16(ohdr->interfaceid);
1176                } else {
1177                        timestamp = ((uint64_t)(ohdr->timestamp_high) << 32) +
1178                                        ohdr->timestamp_low;
1179                        interfaceid = ohdr->interfaceid;
1180                }
1181
1182        }
1183
1184        if (timestamp == 0)
1185                return ts;
1186
1187
1188        interface = lookup_interface(packet->trace, interfaceid);
1189        if (interface == NULL) {
1190                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1191                                "Bad interface %u on pcapng packet",
1192                                interfaceid);
1193                return ts;
1194        }
1195
1196        ts.tv_sec = (timestamp / interface->tsresol);
1197        ts.tv_nsec = (uint64_t)(timestamp - (ts.tv_sec * interface->tsresol))
1198                        / ((double)interface->tsresol) * 1000000000;
1199
1200        return ts;
1201
1202}
1203
1204static inline int pcapng_get_wlen_header(const libtrace_packet_t *packet) {
1205
1206        if (PACKET_IS_ENHANCED) {
1207                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1208
1209                if (DATA(packet->trace)->byteswapped) {
1210                        return byteswap32(ehdr->wlen);
1211                } else {
1212                        return ehdr->wlen;
1213                }
1214        } else if (PACKET_IS_SIMPLE) {
1215                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1216
1217                if (DATA(packet->trace)->byteswapped) {
1218                        return byteswap32(shdr->wlen);
1219                } else {
1220                        return shdr->wlen;
1221                }
1222        } else if (PACKET_IS_OLD) {
1223                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1224
1225                if (DATA(packet->trace)->byteswapped) {
1226                        return byteswap32(ohdr->wlen);
1227                } else {
1228                        return ohdr->wlen;
1229                }
1230        }
1231
1232        /* If we get here, we aren't a valid pcapng packet */
1233        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1234                        "Invalid RT type for pcapng packet: %u",
1235                        packet->type);
1236        return -1;
1237}
1238
1239static int pcapng_get_wire_length(const libtrace_packet_t *packet) {
1240
1241        /* First, get the wire length from the packet header */
1242        int baselen = pcapng_get_wlen_header(packet);
1243
1244        if (baselen == -1)
1245                return -1;
1246
1247        /* Then, account for the vagaries of different DLTs */
1248        if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_EN10MB) {
1249                /* Include the missing FCS */
1250                baselen += 4;
1251        } else if (rt_to_pcap_linktype(packet->type) ==
1252                        TRACE_DLT_IEEE802_11_RADIO) {
1253                /* If the packet is Radiotap and the flags field indicates
1254                 * that the FCS is not included in the 802.11 frame, then
1255                 * we need to add 4 to the wire-length to account for it.
1256                 */
1257                uint8_t flags;
1258                void *link;
1259                libtrace_linktype_t linktype;
1260                link = trace_get_packet_buffer(packet, &linktype, NULL);
1261                trace_get_wireless_flags(link, linktype, &flags);
1262                if ((flags & TRACE_RADIOTAP_F_FCS) == 0) {
1263                        baselen += 4;
1264                }
1265        } else if (rt_to_pcap_linktype(packet->type) == TRACE_DLT_LINUX_SLL) {
1266                libtrace_sll_header_t *sll;
1267                sll = (libtrace_sll_header_t *)packet->payload;
1268
1269                /* Account for FCS when dealing with Ethernet packets that are
1270                 * encapsulated in Linux SLL. This should fix the problem
1271                 * where the wire lengths differ if we convert the packet to
1272                 * ERF */
1273                if (ntohs(sll->protocol) == TRACE_ETHERTYPE_LOOPBACK) {
1274                        baselen += 4;
1275                }
1276        }
1277
1278        return baselen;
1279}
1280
1281static int pcapng_get_capture_length(const libtrace_packet_t *packet) {
1282
1283        if (PACKET_IS_ENHANCED) {
1284                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1285
1286                if (DATA(packet->trace)->byteswapped) {
1287                        return byteswap32(ehdr->caplen);
1288                } else {
1289                        return ehdr->caplen;
1290                }
1291        } else if (PACKET_IS_SIMPLE) {
1292                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1293
1294                /* Have to calculate this one by removing all the headers.
1295                 * Don't forget the extra length field at the end!
1296                 */
1297                if (DATA(packet->trace)->byteswapped) {
1298                        return byteswap32(shdr->blocklen) -
1299                                        sizeof(pcapng_spkt_t) - 4;
1300                } else {
1301                        return shdr->blocklen - sizeof(pcapng_spkt_t) - 4;
1302                }
1303        } else if (PACKET_IS_OLD) {
1304                pcapng_opkt_t *ohdr = (pcapng_opkt_t *)packet->header;
1305
1306                if (DATA(packet->trace)->byteswapped) {
1307                        return byteswap32(ohdr->caplen);
1308                } else {
1309                        return ohdr->caplen;
1310                }
1311        }
1312
1313        /* If we get here, we aren't a valid pcapng packet */
1314        trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET,
1315                        "Invalid RT type for pcapng packet: %u",
1316                        packet->type);
1317        return -1;
1318}
1319
1320static size_t pcapng_set_capture_length(libtrace_packet_t *packet,
1321                size_t size) {
1322        uint32_t current;
1323        char *copyto, *copyfrom;
1324        uint32_t tocopy;
1325
1326        if (!(PACKET_IS_SIMPLE) && !(PACKET_IS_ENHANCED)) {
1327                return 0;
1328        }
1329
1330        current = pcapng_get_capture_length(packet);
1331
1332        if (current <= size)
1333                return current;
1334
1335        copyto = (char *)packet->payload + size;
1336        copyfrom = (char *)packet->payload + current;
1337
1338        /* Need to make sure we keep the options and trailing length... */
1339
1340        if (PACKET_IS_SIMPLE) {
1341                tocopy = 4;
1342        } else {
1343                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1344                if (DATA(packet->trace)->byteswapped) {
1345                        tocopy =  byteswap32(ehdr->blocklen) -
1346                                        sizeof(pcapng_epkt_t) - current;
1347                } else {
1348                        tocopy = ehdr->blocklen - sizeof(pcapng_epkt_t) -
1349                                        current;
1350                }
1351        }
1352
1353        memmove(copyto, copyfrom, tocopy);
1354
1355        if (PACKET_IS_SIMPLE) {
1356                pcapng_spkt_t *shdr = (pcapng_spkt_t *)packet->header;
1357
1358                if (DATA(packet->trace)->byteswapped) {
1359                        shdr->blocklen = byteswap32(size + sizeof(pcapng_spkt_t) + tocopy);
1360                } else {
1361                        shdr->blocklen = size + sizeof(pcapng_spkt_t) + tocopy;
1362                }
1363        }
1364
1365        if (PACKET_IS_ENHANCED) {
1366                pcapng_epkt_t *ehdr = (pcapng_epkt_t *)packet->header;
1367
1368                if (DATA(packet->trace)->byteswapped) {
1369                        ehdr->blocklen = byteswap32(size + sizeof(pcapng_epkt_t) + tocopy);
1370                        ehdr->caplen = byteswap32(size);
1371                } else {
1372                        ehdr->blocklen = size + sizeof(pcapng_epkt_t) + tocopy;
1373                        ehdr->caplen = size;
1374                }
1375        }
1376        packet->capture_length = -1;
1377        return trace_get_capture_length(packet);
1378}
1379
1380
1381static struct libtrace_eventobj_t pcapng_event(libtrace_t *libtrace,
1382                libtrace_packet_t *packet) {
1383
1384        libtrace_eventobj_t event = {0,0,0.0,0};
1385
1386        if (DATA(libtrace)->realtime) {
1387                event.size = trace_read_packet(libtrace, packet);
1388                if (event.size < 1) {
1389                        event.type = TRACE_EVENT_TERMINATE;
1390                } else {
1391                        event.type = TRACE_EVENT_PACKET;
1392                }
1393        } else {
1394                event = trace_event_trace(libtrace, packet);
1395        }
1396
1397        return event;
1398}
1399
1400static void pcapng_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
1401
1402        int i = 0;
1403        uint64_t drops = 0;
1404        uint64_t accepted = 0;
1405        uint64_t osdrops = 0;
1406        uint64_t received = 0;
1407
1408        if (!trace->format_data) {
1409                return;
1410        }
1411
1412        /* Add up all known interface stats */
1413        for (i = 0; i < DATA(trace)->nextintid; i++) {
1414                pcapng_interface_t *interface;
1415
1416                interface = lookup_interface(trace, i);
1417                if (interface == NULL) {
1418                        continue;
1419                }
1420
1421                received += interface->received;
1422                osdrops += interface->osdropped;
1423                accepted += interface->accepted;
1424                drops += interface->dropped;
1425
1426        }
1427
1428        stat->dropped = drops + osdrops;
1429        stat->dropped_valid = 1;
1430
1431        stat->received = received;
1432        stat->received_valid = 1;
1433
1434        stat->filtered = received - accepted;
1435        stat->filtered_valid = 1;
1436
1437        stat->captured = accepted;
1438        stat->captured_valid = 1;
1439
1440
1441}
1442
1443static void pcapng_help(void) {
1444        printf("pcapng format module: \n");
1445        printf("Supported input URIs:\n");
1446        printf("\tpcapng:/path/to/file\n");
1447        printf("\tpcapng:/path/to/file.gz\n");
1448        printf("\n");
1449        printf("\te.g.: pcapng:/tmp/trace.pcap\n");
1450        printf("\n");
1451}
1452
1453static struct libtrace_format_t pcapng = {
1454        "pcapng",
1455        "$Id$",
1456        TRACE_FORMAT_PCAPNG,
1457        NULL,                           /* probe filename */
1458        pcapng_probe_magic,             /* probe magic */
1459        pcapng_init_input,              /* init_input */
1460        pcapng_config_input,            /* config_input */
1461        pcapng_start_input,             /* start_input */
1462        NULL,                           /* pause_input */
1463        NULL,                           /* init_output */
1464        NULL,                           /* config_output */
1465        NULL,                           /* start_output */
1466        pcapng_fin_input,               /* fin_input */
1467        NULL,                           /* fin_output */
1468        pcapng_read_packet,             /* read_packet */
1469        pcapng_prepare_packet,          /* prepare_packet */
1470        NULL,                           /* fin_packet */
1471        NULL,                           /* write_packet */
1472        NULL,                           /* flush_output */
1473        pcapng_get_link_type,           /* get_link_type */
1474        pcapng_get_direction,           /* get_direction */
1475        NULL,                           /* set_direction */
1476        NULL,                           /* get_erf_timestamp */
1477        NULL,                           /* get_timeval */
1478        pcapng_get_timespec,            /* get_timespec */
1479        NULL,                           /* get_seconds */
1480        NULL,                           /* seek_erf */
1481        NULL,                           /* seek_timeval */
1482        NULL,                           /* seek_seconds */
1483        pcapng_get_capture_length,      /* get_capture_length */
1484        pcapng_get_wire_length,         /* get_wire_length */
1485        pcapng_get_framing_length,      /* get_framing_length */
1486        pcapng_set_capture_length,      /* set_capture_length */
1487        NULL,                           /* get_received_packets */
1488        NULL,                           /* get_filtered_packets */
1489        NULL,                           /* get_dropped_packets */
1490        pcapng_get_statistics,          /* get_statistics */
1491        NULL,                           /* get_fd */
1492        pcapng_event,                   /* trace_event */
1493        pcapng_help,                    /* help */
1494        NULL,                           /* next pointer */
1495        NON_PARALLEL(false)
1496};
1497
1498void pcapng_constructor(void) {
1499        register_format(&pcapng);
1500}
1501
Note: See TracBrowser for help on using the repository browser.