source: lib/format_bpf.c @ a81d2fc

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

Update bpf format to deal with the renaming of metadata frequency option

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