source: lib/format_bpf.c @ 5361eae

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

Compile correctly on MacOS
(Prefer net/bpf.h over pcap-bpf.h)

  • Property mode set to 100644
File size: 9.8 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
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 dlt;
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,
153                         &FORMATIN(libtrace)->dlt) == -1) {
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;
232                case TRACE_META_FREQ:
233                        /* No meta-data for this format */
234                        break;
235                /* Avoid default: so that future options will cause a warning
236                 * here to remind us to implement it, or flag it as
237                 * unimplementable
238                 */
239        }
240        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
241                        "Unknown option %i", option);
242        return -1;
243}
244
245static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
246{
247        /* Fill the buffer */
248        if (FORMATIN(libtrace)->remaining<=0) {
249                int ret;
250
251                ret=read(FORMATIN(libtrace)->fd,
252                        FORMATIN(libtrace)->buffer,
253                        FORMATIN(libtrace)->buffersize);
254
255                if (ret == -1) {
256                        trace_set_err(libtrace,errno,"Failed to read");
257                        return -1;
258                }
259
260                if (ret == 0) {
261                        /* EOF */
262                        return 0;
263                }
264
265                FORMATIN(libtrace)->remaining=ret;
266                FORMATIN(libtrace)->bufptr=
267                                FORMATIN(libtrace)->buffer;
268        }
269
270        /* Read one packet out */
271       
272        if (packet->buf_control == TRACE_CTRL_PACKET)
273                free(packet->buffer);
274        packet->buf_control = TRACE_CTRL_EXTERNAL;
275
276        /* Find the bpf header */
277        packet->header=FORMATIN(libtrace)->bufptr;
278
279        /* Find the payload */
280        /* TODO: Pcap deals with a padded FDDI dlt here */
281        packet->payload=FORMATIN(libtrace)->bufptr+BPFHDR(packet)->bh_hdrlen;
282
283        /* Now deal with any padding */
284        FORMATIN(libtrace)->bufptr+=
285                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
286                +BPFHDR(packet)->bh_caplen);
287        FORMATIN(libtrace)->remaining-=
288                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
289                +BPFHDR(packet)->bh_caplen);
290
291        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
292}
293
294static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
295        return pcap_dlt_to_libtrace(FORMATIN(packet->trace)->dlt);
296}
297
298static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet) {
299        /* BPF Sadly can't do direction tagging */
300        return ~0;
301}
302
303static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
304{
305        struct timeval tv;
306        tv=BPFHDR(packet)->bh_tstamp;
307        return tv;
308}
309
310static int bpf_get_capture_length(const libtrace_packet_t *packet)
311{
312        /* BPF Doesn't include the FCS, we do. */
313        return BPFHDR(packet)->bh_caplen+4;
314}
315
316static int bpf_get_wire_length(const libtrace_packet_t *packet) 
317{
318        return BPFHDR(packet)->bh_datalen+4;
319}
320
321static int bpf_get_framing_length(UNUSED
322                const libtrace_packet_t *packet) 
323{
324        return BPFHDR(packet)->bh_hdrlen;
325}
326
327static int bpf_get_fd(const libtrace_t *trace) {
328        return FORMATIN(trace)->fd;
329}
330
331static void bpf_help() {
332        printf("bpf format module: $Revision$\n");
333        printf("Supported input URIs:\n");
334        printf("\tbpf:\n");
335        printf("\n");
336        return;
337}
338static struct libtrace_format_t bpf = {
339        "bpf",
340        "$Id: format_bpf.c,v 1.13 2005/11/22 23:38:56 dlawson Exp $",
341        TRACE_FORMAT_BPF,
342        bpf_init_input,         /* init_input */
343        bpf_config_input,       /* config_input */
344        bpf_start_input,        /* start_input */
345        bpf_pause_input,        /* pause_input */
346        NULL,                   /* init_output */
347        NULL,                   /* config_output */
348        NULL,                   /* start_ouput */
349        bpf_fin_input,          /* fin_input */
350        NULL,                   /* fin_output */
351        bpf_read_packet,        /* read_packet */
352        NULL,                   /* fin_packet */
353        NULL,                   /* write_packet */
354        bpf_get_link_type,      /* get_link_type */
355        bpf_get_direction,      /* get_direction */
356        NULL,                   /* set_direction */
357        NULL,                   /* get_erf_timestamp */
358        bpf_get_timeval,        /* get_timeval */
359        NULL,                   /* get_seconds */
360        NULL,                   /* seek_erf */
361        NULL,                   /* seek_timeval */
362        NULL,                   /* seek_seconds */
363        bpf_get_capture_length, /* get_capture_length */
364        bpf_get_wire_length,    /* get_wire_length */
365        bpf_get_framing_length, /* get_framing_length */
366        NULL,                   /* set_capture_length */
367        bpf_get_fd,             /* get_fd */
368        trace_event_device,     /* trace_event */
369        bpf_help,               /* help */
370        NULL
371};
372
373void bpf_constructor() {
374        register_format(&bpf);
375}
Note: See TracBrowser for help on using the repository browser.