source: lib/format_bpf.c @ 91b72d3

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 91b72d3 was 91b72d3, checked in by Perry Lorier <perry@…>, 13 years ago

Try to autoguess the tracetype if the format uri specify is not present

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Perry Lorier
6 *         
7 * All rights reserved.
8 *
9 * This code has been developed by the University of Waikato WAND
10 * research group. For further information please see http://www.wand.net.nz/
11 *
12 * libtrace is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * libtrace is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with libtrace; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 *
26 * $Id$
27 *
28 */
29
30#include "libtrace.h"
31#include "libtrace_int.h"
32#include "format_helper.h"
33#include "config.h"
34#include "stdlib.h"
35
36#ifdef HAVE_INTTYPES_H
37#  include <inttypes.h>
38#else
39# error "Can't find inttypes.h"
40#endif
41
42#include <sys/socket.h>
43
44#include <sys/types.h>
45#include <sys/time.h>
46#include <sys/ioctl.h>
47
48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
51#include <errno.h>
52#include <fcntl.h>
53
54
55struct libtrace_format_data_t {
56        int fd;
57        int snaplen;
58        int promisc;
59        void *buffer;
60        void *bufptr;
61        unsigned int buffersize;
62        int remaining;
63        unsigned int linktype;
64        struct bpf_stat stats;
65        int stats_valid;
66};
67
68#define FORMATIN(x) ((struct libtrace_format_data_t*)((x->format_data)))
69
70#define BPFHDR(x) ((struct bpf_hdr *)((x)->header))
71
72static int bpf_start_filename(const char *filename)
73{
74        return 0;
75}
76
77static int bpf_init_input(libtrace_t *libtrace) 
78{
79        libtrace->format_data = (struct libtrace_format_data_t *)
80                malloc(sizeof(struct libtrace_format_data_t));
81        FORMATIN(libtrace)->fd = -1;
82        FORMATIN(libtrace)->promisc = 0;
83        FORMATIN(libtrace)->snaplen = 65536;
84        FORMATIN(libtrace)->stats_valid = 0;
85
86        return 0;
87}
88
89static int bpf_start_input(libtrace_t *libtrace)
90{
91        int bpfid=0;
92        struct bpf_version bv;
93        struct ifreq ifr;
94        unsigned int v;
95
96        /* Find and open a bpf device */
97        do {
98                char buffer[64];
99                snprintf(buffer,sizeof(buffer),"/dev/bpf%d", bpfid);
100                bpfid++;
101               
102                FORMATIN(libtrace)->fd = open(buffer, O_RDONLY);
103        } while(FORMATIN(libtrace)->fd == -1 && errno == EBUSY);
104
105        if (FORMATIN(libtrace)->fd == -1) {
106                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
107                                "No free bpf devices");
108                return -1;
109        }
110
111        /* Check the BPF Version is ok */
112        if (ioctl(FORMATIN(libtrace)->fd, BIOCVERSION, &bv) == -1) {
113                trace_set_err(libtrace,errno,
114                                "Failed to read the bpf version");
115                close(FORMATIN(libtrace)->fd);
116                return -1;
117        }
118
119        if (bv.bv_major != BPF_MAJOR_VERSION) {
120                trace_set_err(libtrace,errno, 
121                        "Unknown kernel BPF version (%d.%d, libtrace requires at least %d.%d)",
122                        bv.bv_major,
123                        bv.bv_minor,
124                        BPF_MAJOR_VERSION,
125                        BPF_MINOR_VERSION);
126                close(FORMATIN(libtrace)->fd);
127                return -1;
128        }
129
130        if (bv.bv_minor < BPF_MINOR_VERSION) {
131                trace_set_err(libtrace,errno, "Kernel version too old (%d.%d, libtrace requires at least %d.%d)",
132                        bv.bv_major,
133                        bv.bv_minor,
134                        BPF_MAJOR_VERSION,
135                        BPF_MINOR_VERSION);
136                close(FORMATIN(libtrace)->fd);
137                return -1;
138        }
139
140        /* We assume the default kernel buffer size is sufficient. */
141        if (ioctl(FORMATIN(libtrace)->fd, BIOCGBLEN,
142                        &FORMATIN(libtrace)->buffersize)==-1) {
143                trace_set_err(libtrace,errno,"Failed to find buffer length");
144                close(FORMATIN(libtrace)->fd);
145                return -1;
146        }
147
148        FORMATIN(libtrace)->buffer = malloc(FORMATIN(libtrace)->buffersize);
149        FORMATIN(libtrace)->bufptr = FORMATIN(libtrace)->buffer;
150        FORMATIN(libtrace)->remaining = 0;
151
152        /* attach to the device */
153        strncpy(ifr.ifr_name, libtrace->uridata, sizeof(ifr.ifr_name));
154        if (ioctl(FORMATIN(libtrace)->fd, BIOCSETIF, &ifr) == -1) {
155                trace_set_err(libtrace,errno,"Failed to attach");
156                close(FORMATIN(libtrace)->fd);
157                return -1;
158        }
159
160        if (ioctl(FORMATIN(libtrace)->fd, BIOCGDLT,
161                         &FORMATIN(libtrace)->linktype) == -1) {
162                trace_set_err(libtrace,errno,"Failed to retrieve link type");
163                close(FORMATIN(libtrace)->fd);
164                return -1;
165        }
166       
167        /* TODO: If BIOCGDLTLIST exists then we should perhaps do something
168         *       with it.  We don't have the same concept of multiple DLT's
169         *       as pcap does.  We grab the rawest possible thing and then
170         *       decode packets by understanding the protocols.  So perhaps
171         *       we should setup a rating of DLT's that we'll prefer in order.
172         *       For example we should try and get 802.11 frames rather than
173         *       802.3 frames.  The general rule should be "whatever actually
174         *       went over the air", although of course if we don't support
175         *       what went over the air we should fall back to something we
176         *       /do/ support.
177         */
178       
179        /* Using timeouts seems sucky.  We'll always use immediate mode.  We
180         * pray the kernel is smart enough that if a another packet arrives
181         * while we're processing this one that it will buffer them into it's
182         * kernel buffer so we can recieve packets later. (It'll need to do this
183         * to deal with us spending time processing the last 'n' packets anyway)
184         */
185       
186        v=1;
187        if (ioctl(FORMATIN(libtrace)->fd, BIOCIMMEDIATE, &v) == -1) {
188                trace_set_err(libtrace,errno,"Failed to set immediate mode");
189                close(FORMATIN(libtrace)->fd);
190                return -1;
191        }
192
193        if (FORMATIN(libtrace)->promisc) {
194                if (ioctl(FORMATIN(libtrace)->fd, BIOCPROMISC, NULL) == -1) {
195                        trace_set_err(libtrace,errno,
196                                "Failed to set promisc mode");
197                        close(FORMATIN(libtrace)->fd);
198                        return -1;
199
200                }
201        }
202
203        FORMATIN(libtrace)->stats_valid = 0;
204
205        /* TODO: we should always set a bpf filter for snapping */
206
207        /* We're done! */
208        return 0;
209}
210
211static uint64_t bpf_get_received_packets(libtrace_t *trace)
212{
213        if (trace->format_data == NULL)
214                return (uint64_t)-1;
215
216        if (FORMATIN(trace)->fd == -1) {
217                /* Almost certainly a 'dead' trace so there is no socket
218                 * for us to query */
219                return (uint64_t) -1;
220        }
221        /* If we're called with stats_valid == 0, or we're called again
222         * then refresh the stats.  Don't refresh the stats if we're called
223         * immediately after get_dropped_packets
224         */
225        if ((FORMATIN(trace)->stats_valid & 1)
226                || (FORMATIN(trace)->stats_valid == 0)) {
227                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
228                FORMATIN(trace)->stats_valid |= 1;
229        }
230
231        return FORMATIN(trace)->stats.bs_recv;
232}
233
234static uint64_t bpf_get_dropped_packets(libtrace_t *trace)
235{
236        if (trace->format_data == NULL)
237                return (uint64_t)-1;
238
239        if (FORMATIN(trace)->fd == -1) {
240                /* Almost certainly a 'dead' trace so there is no socket
241                 * for us to query */
242                return (uint64_t) -1;
243        }
244        /* If we're called with stats_valid == 0, or we're called again
245         * then refresh the stats.  Don't refresh the stats if we're called
246         * immediately after get_received_packets
247         */
248        if ((FORMATIN(trace)->stats_valid & 2) 
249                || (FORMATIN(trace)->stats_valid == 0)) {
250                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
251                FORMATIN(trace)->stats_valid |= 2;
252        }
253
254        return FORMATIN(trace)->stats.bs_drop;
255}
256
257static int bpf_pause_input(libtrace_t *libtrace)
258{
259        close(FORMATIN(libtrace)->fd);
260        FORMATIN(libtrace)->fd=-1;
261
262        return 0;
263}
264
265static int bpf_fin_input(libtrace_t *libtrace) 
266{
267        free(libtrace->format_data);
268        return 0;
269}
270
271static int bpf_config_input(libtrace_t *libtrace,
272                trace_option_t option,
273                void *data)
274{
275        switch(option) {
276                case TRACE_OPTION_SNAPLEN:
277                        FORMATIN(libtrace)->snaplen=*(int*)data;
278                        return 0;
279                case TRACE_OPTION_PROMISC:
280                        FORMATIN(libtrace)->promisc=*(int*)data;
281                        return 0;
282                case TRACE_OPTION_FILTER:
283                        /* We don't support bpf filters in any special way
284                         * so return an error and let libtrace deal with
285                         * emulating it
286                         */
287                        break;
288                case TRACE_OPTION_META_FREQ:
289                        /* No meta-data for this format */
290                        break;
291                case TRACE_OPTION_EVENT_REALTIME:
292                        /* captures are always realtime */
293                        break;
294
295                /* Avoid default: so that future options will cause a warning
296                 * here to remind us to implement it, or flag it as
297                 * unimplementable
298                 */
299        }
300        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
301                        "Unknown option %i", option);
302        return -1;
303}
304
305static int bpf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
306                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
307        if (packet->buffer != buffer &&
308                        packet->buf_control == TRACE_CTRL_PACKET) {
309                free(packet->buffer);
310        }
311
312        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
313                packet->buf_control = TRACE_CTRL_PACKET;
314        } else
315                packet->buf_control = TRACE_CTRL_EXTERNAL;
316
317
318        packet->buffer = buffer;
319        packet->header = buffer;
320        packet->type = rt_type;
321
322        /* Find the payload */
323        /* TODO: Pcap deals with a padded FDDI linktype here */
324        packet->payload=(char *)buffer + BPFHDR(packet)->bh_hdrlen;
325
326        if (libtrace->format_data == NULL) {
327                if (bpf_init_input(libtrace))
328                        return -1;
329        }
330
331        return 0;
332}
333       
334static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
335{
336        uint32_t flags = 0;
337       
338        /* Fill the buffer */
339        if (FORMATIN(libtrace)->remaining<=0) {
340                int ret;
341
342                ret=read(FORMATIN(libtrace)->fd,
343                        FORMATIN(libtrace)->buffer,
344                        FORMATIN(libtrace)->buffersize);
345
346                if (ret == -1) {
347                        trace_set_err(libtrace,errno,"Failed to read");
348                        return -1;
349                }
350
351                if (ret == 0) {
352                        /* EOF */
353                        return 0;
354                }
355
356                FORMATIN(libtrace)->remaining=ret;
357                FORMATIN(libtrace)->bufptr=
358                                FORMATIN(libtrace)->buffer;
359        }
360        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
361        /* Read one packet out */
362       
363        if (packet->buf_control == TRACE_CTRL_PACKET)
364                free(packet->buffer);
365
366        if (bpf_prepare_packet(libtrace, packet, FORMATIN(libtrace)->bufptr,
367                TRACE_RT_DATA_BPF, flags)) {
368                return -1;
369        }
370       
371
372        /* Now deal with any padding */
373        FORMATIN(libtrace)->bufptr+=
374                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
375                +BPFHDR(packet)->bh_caplen);
376        FORMATIN(libtrace)->remaining-=
377                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
378                +BPFHDR(packet)->bh_caplen);
379
380        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
381}
382
383static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
384        return pcap_linktype_to_libtrace(FORMATIN(packet->trace)->linktype);
385}
386
387static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet) {
388        /* BPF Sadly can't do direction tagging */
389        return ~0;
390}
391
392static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
393{
394        struct timeval tv;
395        /* OpenBSD uses a bpf_timeval rather than a timeval so we must copy
396         * each timeval element individually rather than doing a structure
397         * assignment */
398        tv.tv_sec = BPFHDR(packet)->bh_tstamp.tv_sec;
399        tv.tv_usec = BPFHDR(packet)->bh_tstamp.tv_usec;
400
401        return tv;
402}
403
404static int bpf_get_capture_length(const libtrace_packet_t *packet)
405{
406        /* BPF Doesn't include the FCS, we do. */
407        return BPFHDR(packet)->bh_caplen+4;
408}
409
410static int bpf_get_wire_length(const libtrace_packet_t *packet) 
411{
412        return BPFHDR(packet)->bh_datalen+4;
413}
414
415static int bpf_get_framing_length(UNUSED
416                const libtrace_packet_t *packet) 
417{
418        return BPFHDR(packet)->bh_hdrlen;
419}
420
421static int bpf_get_fd(const libtrace_t *trace) {
422        return FORMATIN(trace)->fd;
423}
424
425static void bpf_help() {
426        printf("bpf format module: $Revision$\n");
427        printf("Supported input URIs:\n");
428        printf("\tbpf:\n");
429        printf("\n");
430        return;
431}
432static struct libtrace_format_t bpf = {
433        "bpf",
434        "$Id$",
435        TRACE_FORMAT_BPF,
436        bpf_probe_filename,     /* probe filename */
437        NULL,                   /* probe magic */
438        bpf_init_input,         /* init_input */
439        bpf_config_input,       /* config_input */
440        bpf_start_input,        /* start_input */
441        bpf_pause_input,        /* pause_input */
442        NULL,                   /* init_output */
443        NULL,                   /* config_output */
444        NULL,                   /* start_ouput */
445        bpf_fin_input,          /* fin_input */
446        NULL,                   /* fin_output */
447        bpf_read_packet,        /* read_packet */
448        bpf_prepare_packet,     /* prepare_packet */
449        NULL,                   /* fin_packet */
450        NULL,                   /* write_packet */
451        bpf_get_link_type,      /* get_link_type */
452        bpf_get_direction,      /* get_direction */
453        NULL,                   /* set_direction */
454        NULL,                   /* get_erf_timestamp */
455        bpf_get_timeval,        /* get_timeval */
456        NULL,                   /* get_seconds */
457        NULL,                   /* seek_erf */
458        NULL,                   /* seek_timeval */
459        NULL,                   /* seek_seconds */
460        bpf_get_capture_length, /* get_capture_length */
461        bpf_get_wire_length,    /* get_wire_length */
462        bpf_get_framing_length, /* get_framing_length */
463        NULL,                   /* set_capture_length */
464        bpf_get_received_packets,/* get_received_packets */
465        NULL,                   /* get_filtered_packets */
466        bpf_get_dropped_packets,/* get_dropped_packets */
467        NULL,                   /* get_captured_packets */
468        bpf_get_fd,             /* get_fd */
469        trace_event_device,     /* trace_event */
470        bpf_help,               /* help */
471        NULL
472};
473
474void bpf_constructor() {
475        register_format(&bpf);
476}
Note: See TracBrowser for help on using the repository browser.