source: lib/format_bpf.c @ f3f3558

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

Ready for release

  • Property mode set to 100644
File size: 11.0 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_init_input(libtrace_t *libtrace) 
73{
74        libtrace->format_data = (struct libtrace_format_data_t *)
75                malloc(sizeof(struct libtrace_format_data_t));
76        FORMATIN(libtrace)->fd = -1;
77        FORMATIN(libtrace)->promisc = 0;
78        FORMATIN(libtrace)->snaplen = 65536;
79        FORMATIN(libtrace)->stats_valid = 0;
80
81        return 0;
82}
83
84static int bpf_start_input(libtrace_t *libtrace)
85{
86        int bpfid=0;
87        struct bpf_version bv;
88        struct ifreq ifr;
89        unsigned int v;
90
91        /* Find and open a bpf device */
92        do {
93                char buffer[64];
94                snprintf(buffer,sizeof(buffer),"/dev/bpf%d", bpfid);
95                bpfid++;
96               
97                FORMATIN(libtrace)->fd = open(buffer, O_RDONLY);
98        } while(FORMATIN(libtrace)->fd == -1 && errno == EBUSY);
99
100        if (FORMATIN(libtrace)->fd == -1) {
101                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
102                                "No free bpf devices");
103                return -1;
104        }
105
106        /* Check the BPF Version is ok */
107        if (ioctl(FORMATIN(libtrace)->fd, BIOCVERSION, &bv) == -1) {
108                trace_set_err(libtrace,errno,
109                                "Failed to read the bpf version");
110                close(FORMATIN(libtrace)->fd);
111                return -1;
112        }
113
114        if (bv.bv_major != BPF_MAJOR_VERSION) {
115                trace_set_err(libtrace,errno, 
116                        "Unknown kernel BPF version (%d.%d, libtrace requires at least %d.%d)",
117                        bv.bv_major,
118                        bv.bv_minor,
119                        BPF_MAJOR_VERSION,
120                        BPF_MINOR_VERSION);
121                close(FORMATIN(libtrace)->fd);
122                return -1;
123        }
124
125        if (bv.bv_minor < BPF_MINOR_VERSION) {
126                trace_set_err(libtrace,errno, "Kernel version too old (%d.%d, libtrace requires at least %d.%d)",
127                        bv.bv_major,
128                        bv.bv_minor,
129                        BPF_MAJOR_VERSION,
130                        BPF_MINOR_VERSION);
131                close(FORMATIN(libtrace)->fd);
132                return -1;
133        }
134
135        /* We assume the default kernel buffer size is sufficient. */
136        if (ioctl(FORMATIN(libtrace)->fd, BIOCGBLEN,
137                        &FORMATIN(libtrace)->buffersize)==-1) {
138                trace_set_err(libtrace,errno,"Failed to find buffer length");
139                close(FORMATIN(libtrace)->fd);
140                return -1;
141        }
142
143        FORMATIN(libtrace)->buffer = malloc(FORMATIN(libtrace)->buffersize);
144        FORMATIN(libtrace)->bufptr = FORMATIN(libtrace)->buffer;
145        FORMATIN(libtrace)->remaining = 0;
146
147        /* attach to the device */
148        strncpy(ifr.ifr_name, libtrace->uridata, sizeof(ifr.ifr_name));
149        if (ioctl(FORMATIN(libtrace)->fd, BIOCSETIF, &ifr) == -1) {
150                trace_set_err(libtrace,errno,"Failed to attach");
151                close(FORMATIN(libtrace)->fd);
152                return -1;
153        }
154
155        if (ioctl(FORMATIN(libtrace)->fd, BIOCGDLT,
156                         &FORMATIN(libtrace)->linktype) == -1) {
157                trace_set_err(libtrace,errno,"Failed to retrieve link type");
158                close(FORMATIN(libtrace)->fd);
159                return -1;
160        }
161       
162        /* TODO: If BIOCGDLTLIST exists then we should perhaps do something
163         *       with it.  We don't have the same concept of multiple DLT's
164         *       as pcap does.  We grab the rawest possible thing and then
165         *       decode packets by understanding the protocols.  So perhaps
166         *       we should setup a rating of DLT's that we'll prefer in order.
167         *       For example we should try and get 802.11 frames rather than
168         *       802.3 frames.  The general rule should be "whatever actually
169         *       went over the air", although of course if we don't support
170         *       what went over the air we should fall back to something we
171         *       /do/ support.
172         */
173       
174        /* Using timeouts seems sucky.  We'll always use immediate mode.  We
175         * pray the kernel is smart enough that if a another packet arrives
176         * while we're processing this one that it will buffer them into it's
177         * kernel buffer so we can recieve packets later. (It'll need to do this
178         * to deal with us spending time processing the last 'n' packets anyway)
179         */
180       
181        v=1;
182        if (ioctl(FORMATIN(libtrace)->fd, BIOCIMMEDIATE, &v) == -1) {
183                trace_set_err(libtrace,errno,"Failed to set immediate mode");
184                close(FORMATIN(libtrace)->fd);
185                return -1;
186        }
187
188        if (FORMATIN(libtrace)->promisc) {
189                if (ioctl(FORMATIN(libtrace)->fd, BIOCPROMISC, NULL) == -1) {
190                        trace_set_err(libtrace,errno,
191                                "Failed to set promisc mode");
192                        close(FORMATIN(libtrace)->fd);
193                        return -1;
194
195                }
196        }
197
198        FORMATIN(libtrace)->stats_valid = 0;
199
200        /* TODO: we should always set a bpf filter for snapping */
201
202        /* We're done! */
203        return 0;
204}
205
206static uint64_t bpf_get_received_packets(libtrace_t *trace)
207{
208        /* If we're called with stats_valid == 0, or we're called again
209         * then refresh the stats.  Don't refresh the stats if we're called
210         * immediately after get_dropped_packets
211         */
212        if (FORMATIN(trace)->stats_valid != 2) {
213                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
214                FORMATIN(trace)->stats_valid = 1;
215        }
216
217        return FORMATIN(trace)->stats.bs_recv;
218}
219
220static uint64_t bpf_get_dropped_packets(libtrace_t *trace)
221{
222        /* If we're called with stats_valid == 0, or we're called again
223         * then refresh the stats.  Don't refresh the stats if we're called
224         * immediately after get_received_packets
225         */
226        if (!FORMATIN(trace)->stats_valid != 1) {
227                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
228                FORMATIN(trace)->stats_valid = 2;
229        }
230
231        return FORMATIN(trace)->stats.bs_drop;
232}
233
234static int bpf_pause_input(libtrace_t *libtrace)
235{
236        close(FORMATIN(libtrace)->fd);
237        FORMATIN(libtrace)->fd=-1;
238
239        return 0;
240}
241
242static int bpf_fin_input(libtrace_t *libtrace) 
243{
244        free(libtrace->format_data);
245        return 0;
246}
247
248static int bpf_config_input(libtrace_t *libtrace,
249                trace_option_t option,
250                void *data)
251{
252        switch(option) {
253                case TRACE_OPTION_SNAPLEN:
254                        FORMATIN(libtrace)->snaplen=*(int*)data;
255                        return 0;
256                case TRACE_OPTION_PROMISC:
257                        FORMATIN(libtrace)->promisc=*(int*)data;
258                        return 0;
259                case TRACE_OPTION_FILTER:
260                        /* We don't support bpf filters in any special way
261                         * so return an error and let libtrace deal with
262                         * emulating it
263                         */
264                        break;
265                case TRACE_OPTION_META_FREQ:
266                        /* No meta-data for this format */
267                        break;
268                case TRACE_OPTION_EVENT_REALTIME:
269                        /* captures are always realtime */
270                        break;
271
272                /* Avoid default: so that future options will cause a warning
273                 * here to remind us to implement it, or flag it as
274                 * unimplementable
275                 */
276        }
277        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
278                        "Unknown option %i", option);
279        return -1;
280}
281
282static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
283{
284        /* Fill the buffer */
285        if (FORMATIN(libtrace)->remaining<=0) {
286                int ret;
287
288                ret=read(FORMATIN(libtrace)->fd,
289                        FORMATIN(libtrace)->buffer,
290                        FORMATIN(libtrace)->buffersize);
291
292                if (ret == -1) {
293                        trace_set_err(libtrace,errno,"Failed to read");
294                        return -1;
295                }
296
297                if (ret == 0) {
298                        /* EOF */
299                        return 0;
300                }
301
302                FORMATIN(libtrace)->remaining=ret;
303                FORMATIN(libtrace)->bufptr=
304                                FORMATIN(libtrace)->buffer;
305        }
306
307        /* Read one packet out */
308       
309        if (packet->buf_control == TRACE_CTRL_PACKET)
310                free(packet->buffer);
311        packet->buf_control = TRACE_CTRL_EXTERNAL;
312
313        /* Find the bpf header */
314        packet->header=FORMATIN(libtrace)->bufptr;
315
316        /* Find the payload */
317        /* TODO: Pcap deals with a padded FDDI linktype here */
318        packet->payload=FORMATIN(libtrace)->bufptr+BPFHDR(packet)->bh_hdrlen;
319
320        /* Now deal with any padding */
321        FORMATIN(libtrace)->bufptr+=
322                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
323                +BPFHDR(packet)->bh_caplen);
324        FORMATIN(libtrace)->remaining-=
325                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
326                +BPFHDR(packet)->bh_caplen);
327
328        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
329}
330
331static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
332        return pcap_linktype_to_libtrace(FORMATIN(packet->trace)->linktype);
333}
334
335static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet) {
336        /* BPF Sadly can't do direction tagging */
337        return ~0;
338}
339
340static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
341{
342        struct timeval tv;
343        tv=BPFHDR(packet)->bh_tstamp;
344        return tv;
345}
346
347static int bpf_get_capture_length(const libtrace_packet_t *packet)
348{
349        /* BPF Doesn't include the FCS, we do. */
350        return BPFHDR(packet)->bh_caplen+4;
351}
352
353static int bpf_get_wire_length(const libtrace_packet_t *packet) 
354{
355        return BPFHDR(packet)->bh_datalen+4;
356}
357
358static int bpf_get_framing_length(UNUSED
359                const libtrace_packet_t *packet) 
360{
361        return BPFHDR(packet)->bh_hdrlen;
362}
363
364static int bpf_get_fd(const libtrace_t *trace) {
365        return FORMATIN(trace)->fd;
366}
367
368static void bpf_help() {
369        printf("bpf format module: $Revision$\n");
370        printf("Supported input URIs:\n");
371        printf("\tbpf:\n");
372        printf("\n");
373        return;
374}
375static struct libtrace_format_t bpf = {
376        "bpf",
377        "$Id$",
378        TRACE_FORMAT_BPF,
379        bpf_init_input,         /* init_input */
380        bpf_config_input,       /* config_input */
381        bpf_start_input,        /* start_input */
382        bpf_pause_input,        /* pause_input */
383        NULL,                   /* init_output */
384        NULL,                   /* config_output */
385        NULL,                   /* start_ouput */
386        bpf_fin_input,          /* fin_input */
387        NULL,                   /* fin_output */
388        bpf_read_packet,        /* read_packet */
389        NULL,                   /* fin_packet */
390        NULL,                   /* write_packet */
391        bpf_get_link_type,      /* get_link_type */
392        bpf_get_direction,      /* get_direction */
393        NULL,                   /* set_direction */
394        NULL,                   /* get_erf_timestamp */
395        bpf_get_timeval,        /* get_timeval */
396        NULL,                   /* get_seconds */
397        NULL,                   /* seek_erf */
398        NULL,                   /* seek_timeval */
399        NULL,                   /* seek_seconds */
400        bpf_get_capture_length, /* get_capture_length */
401        bpf_get_wire_length,    /* get_wire_length */
402        bpf_get_framing_length, /* get_framing_length */
403        NULL,                   /* set_capture_length */
404        bpf_get_received_packets,/* get_received_packets */
405        NULL,                   /* get_filtered_packets */
406        bpf_get_dropped_packets,/* get_dropped_packets */
407        NULL,                   /* get_captured_packets */
408        bpf_get_fd,             /* get_fd */
409        trace_event_device,     /* trace_event */
410        bpf_help,               /* help */
411        NULL
412};
413
414void bpf_constructor() {
415        register_format(&bpf);
416}
Note: See TracBrowser for help on using the repository browser.