source: lib/format_pcap.c @ db84bb2

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since db84bb2 was 5e3f16c, checked in by Richard Sanger <rsanger@…>, 4 years ago

Fix for issue #39 - ring and int pstop() fails on older kernels when using threads

The problem here is that on old kernels without PACKET_FANOUT support
(added in v3.1) will only include the single threaded versions of int
and ring. When used with multiple threads the libtrace API will
fallback to using read rather than pread which does not check message
queues.

To fix this issue, in any format without pread support:

  • We check for new messages with each loop around read_packet as we fill the burst
  • Within read_packet we update the halt to include the pausing state
  • Use a seperate lock to the main lock when reading a burst of packets, otherwise trace_ppause has to wait for a burst to read.

This is not 100% perfect as a single packet might still need to be received
before a generic message can be received.
A proper fix in the future would be to move all format internals purely to the
parallel API.

  • Property mode set to 100644
File size: 24.8 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
39#ifdef HAVE_PCAP_H
40#  include <pcap.h>
41#  ifdef HAVE_PCAP_INT_H
42#    include <pcap-int.h>
43#  endif
44#endif
45
46/* This format module deals with traces captured using the PCAP library. This
47 * format module handles both captures from a live interface and from PCAP
48 * files.
49 *
50 * However, the PCAP file support featured in this code is superceded by our
51 * own implementation of the PCAP file format, called pcapfile. See
52 * format_pcapfile.c for more information.
53 *
54 * Both the live and trace formats support writing, provided your PCAP library
55 * also supports it.
56 *
57 */
58
59/* Formats implemented in this module:
60 *      pcap - deals with PCAP trace files
61 *      pcapint - deals with live PCAP interfaces
62 */
63
64#ifdef HAVE_LIBPCAP
65static struct libtrace_format_t pcap;
66static struct libtrace_format_t pcapint;
67
68#define DATA(x) ((struct pcap_format_data_t*)((x)->format_data))
69#define DATAOUT(x) ((struct pcap_format_data_out_t*)((x)->format_data))
70
71#define INPUT DATA(libtrace)->input
72#define OUTPUT DATAOUT(libtrace)->output
73struct pcap_format_data_t {
74        /** Information about the current state of the input trace */
75        union {
76                /* The PCAP input source */
77                pcap_t *pcap;
78        } input;
79        /* A filter to be applied to all packets read from the source */
80        libtrace_filter_t *filter;
81        /* The snap length to be applied to all captured packets (live only) */
82        int snaplen;
83        /* Whether the capture interface should be set to promiscuous mode
84         * (live only) */
85        int promisc;
86};
87
88struct pcap_format_data_out_t {
89        /* Information about the current state of the output trace */
90        union {
91                struct {
92                        /* The PCAP output device or trace */
93                        pcap_t *pcap;   
94                        /* The PCAP dumper */
95                        pcap_dumper_t *dump;
96                } trace;
97
98        } output;
99};
100
101static int pcap_init_input(libtrace_t *libtrace) {
102        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
103
104        INPUT.pcap = NULL;
105        DATA(libtrace)->filter = NULL;
106        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
107        DATA(libtrace)->promisc = 0;
108
109        return 0;
110}
111
112static int pcap_start_input(libtrace_t *libtrace) {
113        char errbuf[PCAP_ERRBUF_SIZE];
114
115
116        /* Check if the file is already open */
117        if (INPUT.pcap)
118                return 0; /* success */
119
120        /* Open the trace file for reading */
121        if ((INPUT.pcap = 
122                pcap_open_offline(libtrace->uridata,
123                        errbuf)) == NULL) {
124                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
125                                errbuf);
126                return -1;
127        }
128
129        /* If a filter has been configured, compile and apply it */
130        if (DATA(libtrace)->filter) {
131                if (DATA(libtrace)->filter->flag == 0) {
132                        pcap_compile(INPUT.pcap, 
133                                        &DATA(libtrace)->filter->filter,
134                                        DATA(libtrace)->filter->filterstring, 
135                                        1, 0);
136                        DATA(libtrace)->filter->flag = 1;
137                }
138                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter) 
139                                == -1) {
140                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
141                                        pcap_geterr(INPUT.pcap));
142                        return -1;
143                }
144        }
145        return 0;
146}
147
148static int pcap_config_input(libtrace_t *libtrace,
149                trace_option_t option,
150                void *data)
151{
152        switch(option) {
153                case TRACE_OPTION_FILTER:
154                        DATA(libtrace)->filter=data;
155                        return 0;
156                case TRACE_OPTION_SNAPLEN:
157                        /* Snapping isn't supported directly, so fall thru
158                         * and let libtrace deal with it
159                         */
160                case TRACE_OPTION_PROMISC:
161                        /* Can't do promisc on a trace! */
162                case TRACE_OPTION_META_FREQ:
163                        /* No meta data for this format */
164                case TRACE_OPTION_EVENT_REALTIME:
165                        /* We do not support this option for PCAP traces */
166                default:
167                        return -1;
168        }
169        assert(0);
170}
171
172static int pcap_init_output(libtrace_out_t *libtrace) {
173        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
174        OUTPUT.trace.pcap = NULL;
175        OUTPUT.trace.dump = NULL;
176        return 0;
177}
178
179static int pcapint_init_output(libtrace_out_t *libtrace) {
180#ifdef HAVE_PCAP_INJECT
181        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
182        OUTPUT.trace.pcap = NULL;
183        OUTPUT.trace.dump = NULL;
184        return 0;
185#else
186#ifdef HAVE_PCAP_SENDPACKET
187        libtrace->format_data = malloc(sizeof(struct pcap_format_data_out_t));
188        OUTPUT.trace.pcap = NULL;
189        OUTPUT.trace.dump = NULL;
190        return 0;
191#else
192        trace_set_err_out(libtrace,TRACE_ERR_UNSUPPORTED,
193                        "writing not supported by this version of pcap");
194        return -1;
195#endif
196#endif
197}
198
199static int pcapint_init_input(libtrace_t *libtrace) {
200        libtrace->format_data = malloc(sizeof(struct pcap_format_data_t));
201        DATA(libtrace)->filter = NULL;
202        DATA(libtrace)->snaplen = LIBTRACE_PACKET_BUFSIZE;
203        DATA(libtrace)->promisc = 0;
204        return 0; /* success */
205}
206
207static int pcapint_config_input(libtrace_t *libtrace,
208                trace_option_t option,
209                void *data)
210{
211        switch(option) {
212                case TRACE_OPTION_FILTER:
213                        DATA(libtrace)->filter=(libtrace_filter_t*)data;
214                        return 0;
215                case TRACE_OPTION_SNAPLEN:
216                        DATA(libtrace)->snaplen=*(int*)data;
217                        return 0;
218                case TRACE_OPTION_PROMISC:
219                        DATA(libtrace)->promisc=*(int*)data;
220                        return 0;
221                case TRACE_OPTION_META_FREQ:
222                        /* No meta-data for this format */
223                case TRACE_OPTION_EVENT_REALTIME:
224                        /* live interface is always real-time! */
225                default:
226                        /* Don't set an error here - trace_config will try
227                         * to handle the option when we return. If it can't
228                         * deal with it, then it will do the necessary
229                         * error-setting. */
230                        return -1;
231        }
232        assert(0);
233}
234
235static int pcapint_start_input(libtrace_t *libtrace) {
236        char errbuf[PCAP_ERRBUF_SIZE];
237
238#ifdef HAVE_PCAP_CREATE
239        int ret = 0;
240       
241        if ((INPUT.pcap = pcap_create(libtrace->uridata, errbuf)) == NULL) {
242                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
243                return -1; /* failure */
244        }
245        if ((pcap_set_snaplen(INPUT.pcap, DATA(libtrace)->snaplen) == 
246                                PCAP_ERROR_ACTIVATED)) {
247                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
248                return -1; /* failure */
249        }
250
251        if ((pcap_set_promisc(INPUT.pcap, DATA(libtrace)->promisc) == 
252                                PCAP_ERROR_ACTIVATED)) {
253                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
254                return -1; /* failure */
255        }
256       
257        if ((pcap_set_timeout(INPUT.pcap, 1) == PCAP_ERROR_ACTIVATED)) {
258                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
259                return -1; /* failure */
260        }
261
262#ifdef HAVE_PCAP_IMMEDIATE
263        if ((pcap_set_immediate_mode(INPUT.pcap, 1) == PCAP_ERROR_ACTIVATED)) {
264                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
265                return -1; /* failure */
266        }
267#endif
268
269        if ((ret = pcap_activate(INPUT.pcap)) != 0) {
270                if (ret == PCAP_WARNING_PROMISC_NOTSUP) {
271                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,"Promiscuous mode unsupported");
272                        return -1;
273                }
274                if (ret == PCAP_WARNING) {
275                        pcap_perror(INPUT.pcap, "Pcap Warning:");
276                } else {
277                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
278                                        pcap_geterr(INPUT.pcap));
279                        return -1;
280                }
281        }
282                         
283#else   
284
285        /* Open the live device */
286        if ((INPUT.pcap = 
287                        pcap_open_live(libtrace->uridata,
288                        DATA(libtrace)->snaplen,
289                        DATA(libtrace)->promisc,
290                        1,
291                        errbuf)) == NULL) {
292                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",errbuf);
293                return -1; /* failure */
294        }
295#endif
296#ifdef HAVE_PCAP_SETNONBLOCK
297        pcap_setnonblock(INPUT.pcap,0,errbuf);
298#endif
299        /* Set a filter if one is defined */
300        if (DATA(libtrace)->filter) {
301                struct pcap_pkthdr *pcap_hdr = NULL;
302                u_char *pcap_payload = NULL;
303                int pcapret;
304               
305                if (DATA(libtrace)->filter->flag == 0) {
306                        pcap_compile(INPUT.pcap, 
307                                        &DATA(libtrace)->filter->filter,
308                                        DATA(libtrace)->filter->filterstring, 
309                                        1, 0);
310                        DATA(libtrace)->filter->flag = 1;
311                }
312                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
313                        == -1) {
314                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
315                                        pcap_geterr(INPUT.pcap));
316                        return -1; /* failure */
317                }
318
319                /* Consume the first packet in the queue, as this may not
320                 * have had the filter applied to it.
321                 *
322                 * Otherwise we can get problems with the event API, where
323                 * select tells us that there is a packet available but
324                 * calling trace_read_packet will block forever because the
325                 * packet in the queue didn't match the filter so
326                 * pcap_next_ex returns "timed out".
327                 *
328                 * This does mean we may consume a legitimate packet, but
329                 * that's a pretty small downside compared with trace_event
330                 * getting stuck in an infinite loop because of pcap
331                 * wackiness.
332                 *
333                 * For some reason, we only need to consume one packet for
334                 * this to work, so let's hope that holds in the future.
335                 */
336                do {
337                        pcapret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
338                                (const u_char **)&pcap_payload);
339                } while (0);
340
341                if (pcapret < 0)
342                        return -1;
343        }
344        return 0; /* success */
345}
346
347static int pcap_pause_input(libtrace_t *libtrace UNUSED)
348{
349        return 0; /* success */
350}
351
352
353static int pcap_fin_input(libtrace_t *libtrace) 
354{
355        pcap_close(INPUT.pcap);
356        INPUT.pcap=NULL;
357        free(libtrace->format_data);
358        return 0; /* success */
359}
360
361static int pcap_fin_output(libtrace_out_t *libtrace) 
362{
363        if (OUTPUT.trace.dump) {
364                pcap_dump_flush(OUTPUT.trace.dump);
365                pcap_dump_close(OUTPUT.trace.dump);
366        }
367        pcap_close(OUTPUT.trace.pcap);
368        free(libtrace->format_data);
369        return 0;
370}
371
372static int pcapint_fin_output(libtrace_out_t *libtrace)
373{
374        pcap_close(OUTPUT.trace.pcap);
375        free(libtrace->format_data);
376        return 0;
377}
378
379static int pcap_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
380                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
381       
382        if (packet->buffer != buffer &&
383                        packet->buf_control == TRACE_CTRL_PACKET) {
384                        free(packet->buffer);
385        }
386
387        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
388                packet->buf_control = TRACE_CTRL_PACKET;
389        } else
390                packet->buf_control = TRACE_CTRL_EXTERNAL;
391       
392       
393        packet->buffer = buffer;
394        packet->header = buffer;
395        packet->type = rt_type;
396
397        /* Assuming header and payload are sequential in the buffer -
398         * regular pcap often doesn't work like this though, so hopefully
399         * we're not called by something that is reading genuine pcap! */
400        packet->payload = (char *)packet->header + sizeof(struct pcap_pkthdr);
401
402        if (libtrace->format_data == NULL) {
403                if (pcap_init_input(libtrace))
404                        return -1;
405        }
406        return 0;
407}
408
409static int pcap_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
410        int ret = 0;
411        int linktype;
412        uint32_t flags = 0;
413       
414        assert(libtrace->format_data);
415        linktype = pcap_datalink(DATA(libtrace)->input.pcap);
416        packet->type = pcap_linktype_to_rt(linktype);
417
418        /* If we're using the replacement pcap_next_ex() we need to
419         * make sure we have a buffer to *shudder* memcpy into
420         */
421        if (!packet->buffer) {
422                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
423                if (!packet->buffer) {
424                        trace_set_err(libtrace, errno, 
425                                        "Cannot allocate memory");
426                        return -1;
427                }
428                packet->header = packet->buffer;
429                packet->payload = (char *)packet->buffer+sizeof(struct pcap_pkthdr);
430                       
431        }
432
433        flags |= TRACE_PREP_OWN_BUFFER;
434       
435        for(;;) {
436               
437                struct pcap_pkthdr *pcap_hdr = NULL;
438                u_char *pcap_payload = NULL;
439
440                ret = pcap_next_ex(INPUT.pcap, &pcap_hdr, 
441                                (const u_char **)&pcap_payload);
442               
443                packet->header = pcap_hdr;
444                packet->payload = pcap_payload;
445
446                switch(ret) {
447                        case 1: break; /* no error */
448                        case 0:
449                                if ((ret=is_halted(libtrace)) != -1)
450                                        return ret;
451                                continue; /* timeout expired */
452                        case -1:
453                                trace_set_err(libtrace,TRACE_ERR_BAD_PACKET,
454                                                "%s",pcap_geterr(INPUT.pcap));
455                                return -1; /* Error */
456                        case -2:
457                                return 0; /* EOF */
458                }
459
460                /*
461                 * pcap is nasty in that the header and payload aren't
462                 * necessarily located sequentially in memory, but most
463                 * sensible uses of pcap_prepare_packet will involve a
464                 * buffer where header and payload are sequential.
465                 *
466                 * Basically, don't call pcap_prepare_packet here!
467                 *
468                if (pcap_prepare_packet(libtrace, packet, packet->buffer,
469                                packet->type, flags)) {
470                        return -1;
471                }
472                */
473                return ((struct pcap_pkthdr*)packet->header)->len
474                        +sizeof(struct pcap_pkthdr);
475        }
476}
477
478static int pcap_write_packet(libtrace_out_t *libtrace, 
479                libtrace_packet_t *packet) 
480{
481        struct pcap_pkthdr pcap_pkt_hdr;
482        void *link;
483        libtrace_linktype_t linktype;
484        uint32_t remaining;
485
486        link = trace_get_packet_buffer(packet,&linktype,&remaining);
487
488        /* We may have to convert this packet into a suitable PCAP packet */
489
490        /* If this packet cannot be converted to a pcap linktype then
491         * pop off the top header until it can be converted
492         */
493        while (libtrace_to_pcap_linktype(linktype)==TRACE_DLT_ERROR) {
494                if (!demote_packet(packet)) {
495                        trace_set_err_out(libtrace, 
496                                TRACE_ERR_NO_CONVERSION,
497                                "pcap does not support this format");
498                        return -1;
499                }
500
501                link = trace_get_packet_buffer(packet,&linktype,&remaining);
502        }
503
504
505        if (!OUTPUT.trace.pcap) {
506                int linktype=libtrace_to_pcap_dlt(trace_get_link_type(packet));
507                OUTPUT.trace.pcap = pcap_open_dead(linktype,65536);
508                if (!OUTPUT.trace.pcap) {
509                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,
510                                        "Failed to open dead trace: %s\n",
511                                        pcap_geterr(OUTPUT.trace.pcap));
512                }
513                OUTPUT.trace.dump = pcap_dump_open(OUTPUT.trace.pcap,
514                                libtrace->uridata);
515                if (!OUTPUT.trace.dump) {
516                        char *errmsg = pcap_geterr(OUTPUT.trace.pcap);
517                        trace_set_err_out(libtrace,TRACE_ERR_INIT_FAILED,"Failed to open output file: %s\n",
518                                        errmsg ? errmsg : "Unknown error");
519                        return -1;
520                }
521        }
522
523        /* Corrupt packet, or other "non data" packet, so skip it */
524        if (link == NULL) {
525                /* Return "success", but nothing written */
526                return 0;
527        }
528
529        /* Check if the packet was captured using one of the PCAP formats */
530        if (packet->trace->format == &pcap || 
531                        packet->trace->format == &pcapint) {
532                /* Yes - this means we can write it straight out */
533                pcap_dump((u_char*)OUTPUT.trace.dump,
534                                (struct pcap_pkthdr *)packet->header,
535                                packet->payload);
536        } else {
537                /* No - need to fill in a PCAP header with the appropriate
538                 * values */
539
540                /* Leave the manual copy as it is, as it gets around
541                 * some OS's having different structures in pcap_pkt_hdr
542                 */
543                struct timeval ts = trace_get_timeval(packet);
544                pcap_pkt_hdr.ts.tv_sec = ts.tv_sec;
545                pcap_pkt_hdr.ts.tv_usec = ts.tv_usec;
546                pcap_pkt_hdr.caplen = remaining;
547                /* trace_get_wire_length includes FCS, while pcap doesn't */
548                if (trace_get_link_type(packet)==TRACE_TYPE_ETH)
549                        if (trace_get_wire_length(packet) >= 4) { 
550                                pcap_pkt_hdr.len = 
551                                        trace_get_wire_length(packet)-4;
552                        }
553                        else {
554                                pcap_pkt_hdr.len = 0;
555                        }
556                else
557                        pcap_pkt_hdr.len = trace_get_wire_length(packet);
558
559                assert(pcap_pkt_hdr.caplen<65536);
560                assert(pcap_pkt_hdr.len<65536);
561
562                pcap_dump((u_char*)OUTPUT.trace.dump, &pcap_pkt_hdr, packet->payload);
563        }
564        return 0;
565}
566
567static int pcapint_write_packet(libtrace_out_t *libtrace,
568                libtrace_packet_t *packet) 
569{
570        int err;
571
572        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
573                return 0;
574
575        if (!OUTPUT.trace.pcap) {
576                OUTPUT.trace.pcap = (pcap_t *)pcap_open_live(
577                        libtrace->uridata,65536,0,0,NULL);
578        }
579#ifdef HAVE_PCAP_INJECT
580        err=pcap_inject(OUTPUT.trace.pcap,
581                        packet->payload,
582                        trace_get_capture_length(packet));
583        if (err!=(int)trace_get_capture_length(packet))
584                err=-1;
585#else
586#ifdef HAVE_PCAP_SENDPACKET
587        err=pcap_sendpacket(OUTPUT.trace.pcap,
588                        packet->payload,
589                        trace_get_capture_length(packet));
590#else
591    trace_set_err(packet->trace,TRACE_ERR_UNSUPPORTED,"writing is not supported on this platform");
592        return -1;
593#endif
594#endif
595        return err;
596}
597
598static libtrace_linktype_t pcap_get_link_type(const libtrace_packet_t *packet) {
599        /* PCAP doesn't store linktype in the framing header so we need
600         * RT to do it for us
601         */
602        int linktype = rt_to_pcap_linktype(packet->type);
603        return pcap_linktype_to_libtrace(linktype);
604}
605
606static libtrace_direction_t pcap_set_direction(libtrace_packet_t *packet,
607                libtrace_direction_t dir) {
608
609        /* We only support tagging with IN or OUT return error for any others */
610        if(!(dir == TRACE_DIR_OUTGOING || dir == TRACE_DIR_INCOMING))
611                return -1;
612
613        /* PCAP doesn't have a direction field in the header, so we need to
614         * promote to Linux SLL to tag it properly */
615        libtrace_sll_header_t *sll;
616        promote_packet(packet);
617        sll=packet->payload;
618       
619        /* sll->pkttype should be in the endianness of the host that the
620         * trace was taken on.  This is impossible to achieve so we assume
621         * host endianness
622         */
623        if(dir==TRACE_DIR_OUTGOING)
624                sll->pkttype=TRACE_SLL_OUTGOING;
625        else
626                sll->pkttype=TRACE_SLL_HOST;
627        return dir;
628}
629
630static libtrace_direction_t pcap_get_direction(const libtrace_packet_t *packet) {
631        libtrace_direction_t direction  = -1;
632        switch(pcap_get_link_type(packet)) {
633                /* Only packets encapsulated in Linux SLL or PFLOG have any
634                 * direction information */
635
636                case TRACE_TYPE_LINUX_SLL:
637                {
638                        libtrace_sll_header_t *sll;
639                        sll = trace_get_packet_buffer(packet, NULL, NULL);
640                        /* TODO: should check remaining>=sizeof(*sll) */
641                        if (!sll) {
642                                trace_set_err(packet->trace,
643                                        TRACE_ERR_BAD_PACKET,
644                                                "Bad or missing packet");
645                                return -1;
646                        }
647                        /* 0 == LINUX_SLL_HOST */
648                        /* the Waikato Capture point defines "packets
649                         * originating locally" (ie, outbound), with a
650                         * direction of 0, and "packets destined locally"
651                         * (ie, inbound), with a direction of 1.
652                         * This is kind-of-opposite to LINUX_SLL.
653                         * We return consistent values here, however
654                         *
655                         * Note that in recent versions of pcap, you can
656                         * use "inbound" and "outbound" on ppp in linux
657                         */
658                        if (sll->pkttype == TRACE_SLL_OUTGOING) {
659                                direction = TRACE_DIR_OUTGOING;
660                        } else {
661                                direction = TRACE_DIR_INCOMING;
662                        }
663                        break;
664
665                }
666                case TRACE_TYPE_PFLOG:
667                {
668                        libtrace_pflog_header_t *pflog;
669                        pflog = trace_get_packet_buffer(packet, NULL, NULL);
670                        /* TODO: should check remaining >= sizeof(*pflog) */
671                        if (!pflog) {
672                                trace_set_err(packet->trace,
673                                                TRACE_ERR_BAD_PACKET,
674                                                "Bad or missing packet");
675                                return -1;
676                        }
677                        /* enum    { PF_IN=0, PF_OUT=1 }; */
678                        if (ntohs(pflog->dir==0)) {
679
680                                direction = TRACE_DIR_INCOMING;
681                        }
682                        else {
683                                direction = TRACE_DIR_OUTGOING;
684                        }
685                        break;
686                }
687                default:
688                        break;
689        }       
690        return direction;
691}
692
693
694static struct timeval pcap_get_timeval(const libtrace_packet_t *packet) {
695        struct pcap_pkthdr *pcapptr = (struct pcap_pkthdr *)packet->header;
696        struct timeval ts;
697        ts.tv_sec = pcapptr->ts.tv_sec;
698        ts.tv_usec = pcapptr->ts.tv_usec;
699        return ts;
700}
701
702
703static int pcap_get_capture_length(const libtrace_packet_t *packet) {
704        struct pcap_pkthdr *pcapptr = 0;
705        pcapptr = (struct pcap_pkthdr *)packet->header;
706        assert(pcapptr->caplen<=65536);
707
708        return pcapptr->caplen;
709}
710
711static int pcap_get_wire_length(const libtrace_packet_t *packet) {
712        struct pcap_pkthdr *pcapptr = 0;
713        pcapptr = (struct pcap_pkthdr *)packet->header;
714        if (packet->type==pcap_linktype_to_rt(TRACE_DLT_EN10MB))
715                return pcapptr->len+4; /* Include the missing FCS */
716        else if (packet->type==pcap_linktype_to_rt(TRACE_DLT_IEEE802_11_RADIO)) {
717                libtrace_linktype_t linktype;
718                void *link = trace_get_packet_buffer(packet,&linktype,NULL);
719                /* If the packet is Radiotap and the flags field indicates
720                 * that the FCS is not included in the 802.11 frame, then
721                 * we need to add 4 to the wire-length to account for it.
722                 */
723                uint8_t flags;
724                trace_get_wireless_flags(link, 
725                                linktype, &flags);
726                if ((flags & TRACE_RADIOTAP_F_FCS) == 0)
727                        return pcapptr->len + 4;
728        }
729        return pcapptr->len;
730}
731
732static int pcap_get_framing_length(UNUSED const libtrace_packet_t *packet) {
733        return sizeof(struct pcap_pkthdr);
734}
735
736static size_t pcap_set_capture_length(libtrace_packet_t *packet,size_t size) {
737        struct pcap_pkthdr *pcapptr = 0;
738        assert(packet);
739        if (size > trace_get_capture_length(packet)) {
740                /* Can't make a packet larger */
741                return trace_get_capture_length(packet);
742        }
743        /* Reset the cached capture length */
744        packet->capture_length = -1;
745        pcapptr = (struct pcap_pkthdr *)packet->header;
746        pcapptr->caplen = size;
747        return trace_get_capture_length(packet);
748}
749
750static int pcap_get_fd(const libtrace_t *trace) {
751
752        assert(trace->format_data);
753        return pcap_fileno(DATA(trace)->input.pcap);
754}
755
756static void pcap_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
757
758        struct pcap_stat pcapstats;
759        if (pcap_stats(DATA(trace)->input.pcap,&pcapstats)==-1) {
760                char *errmsg = pcap_geterr(DATA(trace)->input.pcap);
761                trace_set_err(trace,TRACE_ERR_UNSUPPORTED,
762                                "Failed to retrieve stats: %s\n",
763                                errmsg ? errmsg : "Unknown pcap error");
764                return;
765        }
766
767        stat->received_valid = 1;
768        stat->received = pcapstats.ps_recv;
769        stat->dropped_valid = 1;
770        stat->dropped = pcapstats.ps_drop;
771}
772
773static void pcap_help(void) {
774        printf("pcap format module: $Revision: 1729 $\n");
775        printf("Supported input URIs:\n");
776        printf("\tpcap:/path/to/file\n");
777        printf("\n");
778        printf("\te.g.: pcap:/tmp/trace.pcap\n");
779        printf("\n");
780        printf("Supported output URIs:\n");
781        printf("\tnone\n");
782        printf("\n");
783}
784
785static void pcapint_help(void) {
786        printf("pcapint format module: $Revision: 1729 $\n");
787        printf("Supported input URIs:\n");
788        printf("\tpcapint:interface\n");
789        printf("\n");
790        printf("\te.g.: pcapint:eth0\n");
791        printf("\n");
792        printf("Supported output URIs:\n");
793        printf("\tnone\n");
794        printf("\n");
795}
796
797
798static struct libtrace_format_t pcap = {
799        "pcap",
800        "$Id$",
801        TRACE_FORMAT_PCAP,
802        NULL,                           /* probe filename */
803        NULL,                           /* probe magic */
804        pcap_init_input,                /* init_input */
805        pcap_config_input,              /* config_input */
806        pcap_start_input,               /* start_input */
807        pcap_pause_input,               /* pause_input */
808        pcap_init_output,               /* init_output */
809        NULL,                           /* config_output */
810        NULL,                           /* start_output */
811        pcap_fin_input,                 /* fin_input */
812        pcap_fin_output,                /* fin_output */
813        pcap_read_packet,               /* read_packet */
814        pcap_prepare_packet,            /* prepare_packet */
815        NULL,                           /* fin_packet */
816        pcap_write_packet,              /* write_packet */
817        pcap_get_link_type,             /* get_link_type */
818        pcap_get_direction,             /* get_direction */
819        pcap_set_direction,             /* set_direction */
820        NULL,                           /* get_erf_timestamp */
821        pcap_get_timeval,               /* get_timeval */
822        NULL,                           /* get_seconds */
823        NULL,                           /* get_timespec */
824        NULL,                           /* seek_erf */
825        NULL,                           /* seek_timeval */
826        NULL,                           /* seek_seconds */
827        pcap_get_capture_length,        /* get_capture_length */
828        pcap_get_wire_length,           /* get_wire_length */
829        pcap_get_framing_length,        /* get_framing_length */
830        pcap_set_capture_length,        /* set_capture_length */
831        NULL,                           /* get_received_packets */
832        NULL,                           /* get_filtered_packets */
833        NULL,                           /* get_dropped_packets */
834        NULL,                           /* get_statistics */
835        NULL,                           /* get_fd */
836        trace_event_trace,              /* trace_event */
837        pcap_help,                      /* help */
838        NULL,                   /* next pointer */
839        NON_PARALLEL(false)
840};
841
842static struct libtrace_format_t pcapint = {
843        "pcapint",
844        "$Id$",
845        TRACE_FORMAT_PCAP,
846        NULL,                           /* probe filename */
847        NULL,                           /* probe magic */
848        pcapint_init_input,             /* init_input */
849        pcapint_config_input,           /* config_input */
850        pcapint_start_input,            /* start_input */
851        pcap_pause_input,               /* pause_input */
852        pcapint_init_output,            /* init_output */
853        NULL,                           /* config_output */
854        NULL,                           /* start_output */
855        pcap_fin_input,                 /* fin_input */
856        pcapint_fin_output,             /* fin_output */
857        pcap_read_packet,               /* read_packet */
858        pcap_prepare_packet,            /* prepare_packet */
859        NULL,                           /* fin_packet */
860        pcapint_write_packet,           /* write_packet */
861        pcap_get_link_type,             /* get_link_type */
862        pcap_get_direction,             /* get_direction */
863        pcap_set_direction,             /* set_direction */
864        NULL,                           /* get_erf_timestamp */
865        pcap_get_timeval,               /* get_timeval */
866        NULL,                           /* get_seconds */
867        NULL,                           /* get_timespec */
868        NULL,                           /* seek_erf */
869        NULL,                           /* seek_timeval */
870        NULL,                           /* seek_seconds */
871        pcap_get_capture_length,        /* get_capture_length */
872        pcap_get_wire_length,           /* get_wire_length */
873        pcap_get_framing_length,        /* get_framing_length */
874        pcap_set_capture_length,        /* set_capture_length */
875        NULL,                           /* get_received_packets */
876        NULL,                           /* get_filtered_packets */
877        NULL,                           /* get_dropped_packets */
878        pcap_get_statistics,            /* get_statistics */
879        pcap_get_fd,                    /* get_fd */
880        trace_event_device,             /* trace_event */
881        pcapint_help,                   /* help */
882        NULL,                   /* next pointer */
883        NON_PARALLEL(true)
884};
885
886void pcap_constructor(void) {
887        register_format(&pcap);
888        register_format(&pcapint);
889}
890
891
892#endif
Note: See TracBrowser for help on using the repository browser.