source: lib/format_bpf.c @ 73dd29f

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

Sooo, pcap has two types of DLT's "pure" DLT's that are platform dependant,
and "linktype" DLT's that are portable and are what are written to pcap files.

Instead of fudging the two concepts together so much, attempt to disintangle
this mess without exposing too much of the god awful mess to the end user.

  • 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
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};
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)->linktype) == -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 linktype 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_linktype_to_libtrace(FORMATIN(packet->trace)->linktype);
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.