source: lib/format_bpf.c @ d5a27e8

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

Update the copyright information
Fix libpcap issue
Remove all swig/python builds

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