source: lib/format_linux_common.c @ 6327ce6

develop
Last change on this file since 6327ce6 was 6327ce6, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Fix memory leak when configuring bpf filters issue #87

  • Property mode set to 100644
File size: 19.1 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
27/* This file contains the common functions used by both the ring and int
28 * formats.
29 *
30 * Typically these deal with the socket descriptor or common conversions.
31 */
32
33#include "config.h"
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "libtrace_arphrd.h"
38#include <stdlib.h>
39#include <errno.h>
40#include <unistd.h>
41#include <string.h>
42
43#ifdef HAVE_INTTYPES_H
44#  include <inttypes.h>
45#else
46# error "Can't find inttypes.h"
47#endif
48
49#include "format_linux_common.h"
50
51unsigned int rand_seedp = 0;
52
53#ifdef HAVE_NETPACKET_PACKET_H
54
55int linuxcommon_probe_filename(const char *filename)
56{
57        /* Is this an interface? */
58        return (if_nametoindex(filename) != 0);
59}
60
61/* Compiles a libtrace BPF filter for use with a linux native socket */
62static int linuxnative_configure_bpf(libtrace_t *libtrace,
63                libtrace_filter_t *filter) {
64#if defined(HAVE_LIBPCAP) && defined(HAVE_BPF)
65        struct ifreq ifr;
66        unsigned int arphrd;
67        libtrace_dlt_t dlt;
68        int sock;
69        pcap_t *pcap;
70
71        /* If we are passed a filter with "flag" set to zero, then we must
72         * compile the filterstring before continuing. This involves
73         * determining the linktype, passing the filterstring to libpcap to
74         * compile, and saving the result for trace_start() to push into the
75         * kernel.
76         * If flag is set to one, then the filter was probably generated using
77         * trace_create_filter_from_bytecode() and so we don't need to do
78         * anything (we've just copied it above).
79         */
80        if (filter->flag == 0) {
81                sock = socket(PF_INET, SOCK_STREAM, 0);
82                memset(&ifr, 0, sizeof(struct ifreq));
83                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE - 1);
84                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
85                        perror("Can't get HWADDR for interface");
86                        return -1;
87                }
88                close(sock);
89
90                arphrd = ifr.ifr_hwaddr.sa_family;
91                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
92
93                pcap = pcap_open_dead(dlt,
94                                FORMAT_DATA->snaplen);
95
96                if (pcap_compile(pcap, &filter->filter, filter->filterstring, 0, 0) == -1) {
97                        /* Filter didn't compile, set flag to 0 so we can
98                         * detect this when trace_start() is called and
99                         * produce a useful error
100                         */
101                        filter->flag = 0;
102                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
103                                      "Failed to compile BPF filter (%s): %s",
104                                      filter->filterstring, pcap_geterr(pcap));
105                } else {
106                        /* Set the "flag" to indicate that the filterstring
107                         * has been compiled
108                         */
109                        filter->flag = 1;
110                }
111
112                pcap_close(pcap);
113
114        }
115
116        FORMAT_DATA->filter = filter;
117
118        return 0;
119#else
120        return -1;
121#endif
122}
123
124int linuxcommon_config_input(libtrace_t *libtrace,
125                trace_option_t option,
126                void *data)
127{
128        switch(option) {
129                case TRACE_OPTION_SNAPLEN:
130                        FORMAT_DATA->snaplen=*(int*)data;
131                        return 0;
132                case TRACE_OPTION_PROMISC:
133                        FORMAT_DATA->promisc=*(int*)data;
134                        return 0;
135                case TRACE_OPTION_FILTER:
136                        return linuxnative_configure_bpf(libtrace,
137                                        (libtrace_filter_t *) data);
138                case TRACE_OPTION_HASHER:
139                        switch (*((enum hasher_types *)data)) {
140                                case HASHER_BALANCE:
141                                        // Do fanout
142                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
143                                        // Or we could balance to the CPU
144                                        return 0;
145                                case HASHER_BIDIRECTIONAL:
146                                case HASHER_UNIDIRECTIONAL:
147                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_HASH;
148                                        return 0;
149                                case HASHER_CUSTOM:
150                                        return -1;
151                        }
152                        break;
153                case TRACE_OPTION_META_FREQ:
154                        /* No meta-data for this format */
155                        break;
156                case TRACE_OPTION_EVENT_REALTIME:
157                        /* Live captures are always going to be in trace time */
158                        break;
159                case TRACE_OPTION_REPLAY_SPEEDUP:
160                        break;
161                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
162                        break;
163                /* Avoid default: so that future options will cause a warning
164                 * here to remind us to implement it, or flag it as
165                 * unimplementable
166                 */
167        }
168
169        /* Don't set an error - trace_config will try to deal with the
170         * option and will set an error if it fails */
171        return -1;
172}
173
174int linuxcommon_init_input(libtrace_t *libtrace)
175{
176        struct linux_per_stream_t stream_data = ZERO_LINUX_STREAM;
177
178        libtrace->format_data = (struct linux_format_data_t *)
179                malloc(sizeof(struct linux_format_data_t));
180
181        if (!libtrace->format_data) {
182                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
183                        "format data inside linuxcommon_init_input()");
184                return -1;
185        }
186
187        FORMAT_DATA->per_stream =
188                libtrace_list_init(sizeof(stream_data));
189
190        if (!FORMAT_DATA->per_stream) {
191                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to create list for stream data linuxcommon_init_input()");
192                return -1;
193        }
194
195        libtrace_list_push_back(FORMAT_DATA->per_stream, &stream_data);
196
197        FORMAT_DATA->promisc = -1;
198        FORMAT_DATA->snaplen = LIBTRACE_PACKET_BUFSIZE;
199        FORMAT_DATA->filter = NULL;
200        FORMAT_DATA->stats_valid = 0;
201        FORMAT_DATA->stats.tp_drops = 0;
202        FORMAT_DATA->stats.tp_packets = 0;
203        FORMAT_DATA->max_order = MAX_ORDER;
204        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
205        /* Some examples use pid for the group however that would limit a single
206         * application to use only int/ring format, instead using rand */
207        FORMAT_DATA->fanout_group = (uint16_t) (rand_r(&rand_seedp) % 65536);
208        return 0;
209}
210
211int linuxcommon_init_output(libtrace_out_t *libtrace)
212{
213        libtrace->format_data = (struct linux_format_data_out_t*)
214                malloc(sizeof(struct linux_format_data_out_t));
215
216        if (!libtrace->format_data) {
217                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
218                        "format data inside linuxcommon_init_output()");
219                return -1;
220        }
221
222        FORMAT_DATA_OUT->fd = -1;
223        FORMAT_DATA_OUT->tx_ring = NULL;
224        FORMAT_DATA_OUT->txring_offset = 0;
225        FORMAT_DATA_OUT->queue = 0;
226        FORMAT_DATA_OUT->max_order = MAX_ORDER;
227        return 0;
228}
229
230/* Close an input stream, this is safe to be called part way through
231 * initilisation as a cleanup function assuming streams were set to
232 * ZERO_LINUX_STREAM to begin with.
233 *
234 * This works correctly with both int and ring
235 */
236void linuxcommon_close_input_stream(libtrace_t *libtrace,
237                                    struct linux_per_stream_t *stream) {
238        if (stream->fd != -1)
239                close(stream->fd);
240        stream->fd = -1;
241        FORMAT_DATA->dev_stats.if_name[0] = 0;
242
243        /* Don't munmap the rx_ring here -- keep it around as long as
244         * possible to ensure that any packets that the user is still
245         * holding references to remain valid.
246         *
247         * Don't worry, linuxring will munmap the rx_ring as soon as
248         * someone either destroys or restarts the trace. At that point,
249         * any remaining packets from the old ring will be recognisable
250         * as invalid.
251         */
252}
253
254#define REPEAT_16(x) x x x x x x x x x x x x x x x x
255#define xstr(s) str(s)
256#define str(s) #s
257
258/* These don't typically reset however an interface does exist to reset them */
259static int linuxcommon_get_dev_statistics(libtrace_t *libtrace, struct linux_dev_stats *stats) {
260        FILE *file;
261        char line[1024];
262        struct linux_dev_stats tmp_stats;
263
264        file = fopen("/proc/net/dev","r");
265        if (file == NULL) {
266                return -1;
267        }
268
269        /* Skip 2 header lines */
270        if (fgets(line, sizeof(line), file) == NULL) {
271                fclose(file);
272                return -1;
273        }
274
275        if (fgets(line, sizeof(line), file) == NULL) {
276                fclose(file);
277                return -1;
278        }
279
280        while (!(feof(file)||ferror(file))) {
281                int tot;
282                if (fgets(line, sizeof(line), file) == NULL)
283                        break;
284
285                tot = sscanf(line, " %"xstr(IF_NAMESIZE)"[^:]:" REPEAT_16(" %"SCNd64),
286                             tmp_stats.if_name,
287                             &tmp_stats.rx_bytes,
288                             &tmp_stats.rx_packets,
289                             &tmp_stats.rx_errors,
290                             &tmp_stats.rx_drops,
291                             &tmp_stats.rx_fifo,
292                             &tmp_stats.rx_frame,
293                             &tmp_stats.rx_compressed,
294                             &tmp_stats.rx_multicast,
295                             &tmp_stats.tx_bytes,
296                             &tmp_stats.tx_packets,
297                             &tmp_stats.tx_errors,
298                             &tmp_stats.tx_drops,
299                             &tmp_stats.tx_fifo,
300                             &tmp_stats.tx_colls,
301                             &tmp_stats.tx_carrier,
302                             &tmp_stats.tx_compressed);
303                if (tot != 17)
304                        continue;
305                if (strncmp(tmp_stats.if_name, libtrace->uridata, IF_NAMESIZE) == 0) {
306                        *stats = tmp_stats;
307                        fclose(file);
308                        return 0;
309                }
310        }
311        fclose(file);
312        return -1;
313}
314
315/* Start an input stream
316 * - Opens the file descriptor
317 * - Sets promiscuous correctly
318 * - Sets socket option
319 * - Add BPF filter
320 *
321 * The output is ready for int directly, for ring the conversion to ring still
322 * needs to take place.
323 */
324int linuxcommon_start_input_stream(libtrace_t *libtrace,
325                                   struct linux_per_stream_t *stream)
326{
327        struct sockaddr_ll addr;
328        const int one = 1;
329        memset(&addr,0,sizeof(addr));
330        libtrace_filter_t *filter = FORMAT_DATA->filter;
331
332        stream->last_timestamp = 0;
333
334        /* Create a raw socket for reading packets on */
335        stream->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
336        if (stream->fd==-1) {
337                trace_set_err(libtrace, errno, "Could not create raw socket");
338                return -1;
339        }
340
341        /* Bind to the capture interface */
342        addr.sll_family = AF_PACKET;
343        addr.sll_protocol = htons(ETH_P_ALL);
344        if (strlen(libtrace->uridata)) {
345                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
346                if (addr.sll_ifindex == 0) {
347                        linuxcommon_close_input_stream(libtrace, stream);
348                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
349                                      "Failed to find interface %s",
350                                      libtrace->uridata);
351                        return -1;
352                }
353        } else {
354                addr.sll_ifindex = 0;
355        }
356        if (bind(stream->fd,
357                 (struct sockaddr*)&addr,
358                 (socklen_t)sizeof(addr))==-1) {
359                linuxcommon_close_input_stream(libtrace, stream);
360                trace_set_err(libtrace, errno,
361                              "Failed to bind to interface %s",
362                              libtrace->uridata);
363                return -1;
364        }
365
366        /* If promisc hasn't been specified, set it to "true" if we're
367         * capturing on one interface, or "false" if we're capturing on
368         * all interfaces.
369         */
370        if (FORMAT_DATA->promisc==-1) {
371                if (addr.sll_ifindex!=0)
372                        FORMAT_DATA->promisc=1;
373                else
374                        FORMAT_DATA->promisc=0;
375        }
376
377        /* Enable promiscuous mode, if requested */
378        if (FORMAT_DATA->promisc) {
379                struct packet_mreq mreq;
380                socklen_t socklen = sizeof(mreq);
381                memset(&mreq,0,sizeof(mreq));
382                mreq.mr_ifindex = addr.sll_ifindex;
383                mreq.mr_type = PACKET_MR_PROMISC;
384                if (setsockopt(stream->fd,
385                               SOL_PACKET,
386                               PACKET_ADD_MEMBERSHIP,
387                               &mreq,
388                               socklen)==-1) {
389                        perror("setsockopt(PROMISC)");
390                }
391        }
392
393        /* Set the timestamp option on the socket - aim for the most detailed
394         * clock resolution possible */
395#ifdef SO_TIMESTAMPNS
396        if (setsockopt(stream->fd,
397                       SOL_SOCKET,
398                       SO_TIMESTAMPNS,
399                       &one,
400                       (socklen_t)sizeof(one))!=-1) {
401                FORMAT_DATA->timestamptype = TS_TIMESPEC;
402        }
403        else
404        /* DANGER: This is a dangling else to only do the next setsockopt()
405         * if we fail the first! */
406#endif
407                if (setsockopt(stream->fd,
408                               SOL_SOCKET,
409                               SO_TIMESTAMP,
410                               &one,
411                               (socklen_t)sizeof(one))!=-1) {
412                        FORMAT_DATA->timestamptype = TS_TIMEVAL;
413                }
414                else
415                        FORMAT_DATA->timestamptype = TS_NONE;
416
417        /* Push BPF filter into the kernel. At this stage we can safely assume
418         * that the filterstring has been compiled, or the filter was supplied
419         * pre-compiled.
420         */
421#ifdef HAVE_BPF
422        if (filter != NULL) {
423                /* Check if the filter was successfully compiled. If not,
424                 * it is probably a bad filter and we should return an error
425                 * before the caller tries to read any packets */
426                if (filter->flag == 0) {
427                        linuxcommon_close_input_stream(libtrace, stream);
428                        trace_set_err(libtrace, TRACE_ERR_BAD_FILTER,
429                                      "Cannot attach a bad filter to %s",
430                                      libtrace->uridata);
431                        return -1;
432                }
433
434                if (setsockopt(stream->fd,
435                               SOL_SOCKET,
436                               SO_ATTACH_FILTER,
437                               &filter->filter,
438                               sizeof(filter->filter)) == -1) {
439                        perror("setsockopt(SO_ATTACH_FILTER)");
440                }
441        }
442#endif
443
444        /* Consume any buffered packets that were received before the socket
445         * was properly setup, including those which missed the filter and
446         * bind()ing to an interface.
447         *
448         * If packet rate is high this could therotically hang forever. 4K
449         * should be a large enough limit.
450         */
451        int count = 0;
452        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
453        while(count < 4096 &&
454                recv(stream->fd,
455                   buf,
456                   (size_t)LIBTRACE_PACKET_BUFSIZE,
457                   MSG_DONTWAIT) != -1) { count++; }
458        free(buf);
459
460        /* Mark that the stats are valid and apply an offset */
461        FORMAT_DATA->stats_valid = 1;
462        /* Offset by number we ate for each stream and reset stats after pause */
463        FORMAT_DATA->stats.tp_packets = -count;
464        FORMAT_DATA->stats.tp_drops = 0;
465
466        if (linuxcommon_get_dev_statistics(libtrace, &FORMAT_DATA->dev_stats) != 0) {
467                /* Mark this as bad */
468                FORMAT_DATA->dev_stats.if_name[0] = 0;
469        }
470
471        return 0;
472}
473
474int linuxcommon_pause_input(libtrace_t *libtrace)
475{
476        size_t i;
477
478        /* Stop and detach each stream */
479        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
480                struct linux_per_stream_t *stream;
481                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
482                linuxcommon_close_input_stream(libtrace, stream);
483        }
484
485        return 0;
486}
487
488int linuxcommon_fin_input(libtrace_t *libtrace)
489{
490        if (libtrace->format_data) {
491
492                if (FORMAT_DATA->per_stream)
493                        libtrace_list_deinit(FORMAT_DATA->per_stream);
494
495                free(libtrace->format_data);
496        }
497
498        return 0;
499}
500
501int linuxcommon_pregister_thread(libtrace_t *libtrace,
502                                 libtrace_thread_t *t,
503                                 bool reading) {
504        if (reading) {
505                /* XXX TODO remove this oneday make sure hasher thread still works */
506                struct linux_per_stream_t *stream;
507                stream = libtrace_list_get_index(FORMAT_DATA->per_stream,
508                                                 t->perpkt_num)->data;
509                t->format_data = stream;
510                if (!stream) {
511                        /* This should never happen and indicates an
512                         * internal libtrace bug */
513                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
514                                      "Failed to attached thread %d to a stream",
515                                      t->perpkt_num);
516                        return -1;
517                }
518        }
519        return 0;
520}
521
522/* These counters reset with each read */
523static void linuxcommon_update_socket_statistics(libtrace_t *libtrace) {
524        struct tpacket_stats stats;
525        size_t i;
526        socklen_t len = sizeof(stats);
527
528        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
529                struct linux_per_stream_t *stream;
530                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
531                if (stream->fd != -1) {
532                        if (getsockopt(stream->fd,
533                                   SOL_PACKET,
534                                   PACKET_STATISTICS,
535                                   &stats,
536                                   &len) == 0) {
537                                if (FORMAT_DATA->stats_valid==0) {
538                                        FORMAT_DATA->stats.tp_drops = stats.tp_drops;
539                                        FORMAT_DATA->stats.tp_packets = stats.tp_packets;
540                                        FORMAT_DATA->stats_valid = 1;
541                                } else {
542                                        FORMAT_DATA->stats.tp_drops += stats.tp_drops;
543                                        FORMAT_DATA->stats.tp_packets += stats.tp_packets;
544                                }
545                        } else {
546                                perror("getsockopt PACKET_STATISTICS failed");
547                        }
548                }
549        }
550}
551
552#define DEV_DIFF(x) (dev_stats.x - FORMAT_DATA->dev_stats.x)
553/* Note these statistics come from two different sources, the socket itself and
554 * the linux device. As such this means it is highly likely that their is some
555 * margin of error in the returned statistics, we perform basic sanitising so
556 * that these are not too noticable.
557 */
558void linuxcommon_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
559        struct linux_dev_stats dev_stats;
560        if (libtrace->format_data == NULL)
561                return;
562        /* Do we need to consider the case after the trace is closed? */
563        if (FORMAT_DATA_FIRST->fd == -1) {
564                /* This is probably a 'dead' trace so obviously we can't query
565                 * the socket for capture counts, can we? */
566                return;
567        }
568
569        dev_stats.if_name[0] = 0; /* This will be set if we retrive valid stats */
570        /* Do we have starting stats to compare to? */
571        if (FORMAT_DATA->dev_stats.if_name[0] != 0) {
572                linuxcommon_get_dev_statistics(libtrace, &dev_stats);
573        }
574        linuxcommon_update_socket_statistics(libtrace);
575
576        /* filtered count == dev received - socket received */
577        if (FORMAT_DATA->filter != NULL &&
578            FORMAT_DATA->stats_valid &&
579            dev_stats.if_name[0]) {
580                uint64_t filtered = DEV_DIFF(rx_packets) -
581                                    FORMAT_DATA->stats.tp_packets;
582                /* Check the value is sane, due to timing it could be below 0 */
583                if (filtered < UINT64_MAX - 100000) {
584                        stat->filtered += filtered;
585                }
586        }
587
588        /* dropped count == socket dropped + dev dropped */
589        if (FORMAT_DATA->stats_valid) {
590                stat->dropped_valid = 1;
591                stat->dropped = FORMAT_DATA->stats.tp_drops;
592                if (dev_stats.if_name[0]) {
593                        stat->dropped += DEV_DIFF(rx_drops);
594                }
595        }
596
597        /* received count - All good packets even those dropped or filtered */
598        if (dev_stats.if_name[0]) {
599                stat->received_valid = 1;
600                stat->received = DEV_DIFF(rx_packets) + DEV_DIFF(rx_drops);
601        }
602
603        /* captured count - received and but not dropped */
604        if (dev_stats.if_name[0] && FORMAT_DATA->stats_valid) {
605                stat->captured_valid = 1;
606                stat->captured = DEV_DIFF(rx_packets) - FORMAT_DATA->stats.tp_drops;
607        }
608
609        /* errors */
610        if (dev_stats.if_name[0]) {
611                stat->errors_valid = 1;
612                stat->errors = DEV_DIFF(rx_errors);
613        }
614
615}
616
617int linuxcommon_get_fd(const libtrace_t *libtrace) {
618        if (libtrace->format_data == NULL)
619                return -1;
620        return FORMAT_DATA_FIRST->fd;
621}
622
623int linuxcommon_pstart_input(libtrace_t *libtrace,
624                             int (*start_stream)(libtrace_t *, struct linux_per_stream_t*)) {
625        int i = 0;
626        int tot = libtrace->perpkt_thread_count;
627        int iserror = 0;
628        struct linux_per_stream_t empty_stream = ZERO_LINUX_STREAM;
629
630        for (i = 0; i < tot; ++i)
631        {
632                struct linux_per_stream_t *stream;
633                /* Add storage for another stream */
634                if (libtrace_list_get_size(FORMAT_DATA->per_stream) <= (size_t) i)
635                        libtrace_list_push_back(FORMAT_DATA->per_stream, &empty_stream);
636
637                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
638                if (start_stream(libtrace, stream) != 0) {
639                        iserror = 1;
640                        break;
641                }
642                if (linuxcommon_to_packet_fanout(libtrace, stream) != 0)
643                {
644                        iserror = 1;
645                        close(stream->fd);
646                        stream->fd = -1;
647                        break;
648                }
649        }
650
651        if (iserror) {
652                /* Free those that succeeded */
653                for (i = i - 1; i >= 0; i--) {
654                        struct linux_per_stream_t *stream;
655                        stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
656                        linuxcommon_close_input_stream(libtrace, stream);
657                }
658                return -1;
659        }
660
661        return 0;
662}
663
664#else /* HAVE_NETPACKET_PACKET_H */
665
666/* No NETPACKET - So this format is not live */
667void linuxcommon_get_statistics(libtrace_t *libtrace UNUSED,
668                                libtrace_stat_t *stat UNUSED) {
669        return;
670}
671
672#endif /* HAVE_NETPACKET_PACKET_H */
673
Note: See TracBrowser for help on using the repository browser.