source: lib/format_linux.c @ 27bd348

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

Fix bug in direction setting

  • Property mode set to 100644
File size: 11.7 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "config.h"
35#include "stdlib.h"
36
37#ifdef HAVE_INTTYPES_H
38#  include <inttypes.h>
39#else
40# error "Can't find inttypes.h"
41#endif
42
43#include <sys/socket.h>
44#include <netpacket/packet.h>
45#include <net/ethernet.h>
46#include <net/if_arp.h>
47
48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
51#include <errno.h>
52
53
54struct libtrace_format_data_t {
55        int fd;
56        int snaplen;
57        int promisc;
58};
59
60struct libtrace_linuxnative_header {
61        struct timeval ts;
62        int wirelen;
63        int caplen;
64        struct sockaddr_ll hdr;
65};
66
67struct libtrace_linuxnative_format_data_t {
68        int fd;
69};
70
71#define FORMAT(x) ((struct libtrace_format_data_t*)(x))
72#define DATAOUT(x) ((struct libtrace_linuxnative_format_data_t*)((x)->format_data))
73
74static int linuxnative_init_input(libtrace_t *libtrace) 
75{
76        libtrace->format_data = (struct libtrace_format_data_t *)
77                malloc(sizeof(struct libtrace_format_data_t));
78        FORMAT(libtrace->format_data)->fd = -1;
79        FORMAT(libtrace->format_data)->promisc = -1;
80        FORMAT(libtrace->format_data)->snaplen = 65536;
81
82        return 0;
83}
84
85static int linuxnative_init_output(libtrace_out_t *libtrace)
86{
87        libtrace->format_data = (struct libtrace_linuxnative_format_data_t*)
88                malloc(sizeof(struct libtrace_linuxnative_format_data_t));
89        DATAOUT(libtrace)->fd = -1;
90
91        return 0;
92}
93
94static int linuxnative_start_input(libtrace_t *libtrace)
95{
96        struct sockaddr_ll addr;
97        int one = 1;
98        memset(&addr,0,sizeof(addr));
99        FORMAT(libtrace->format_data)->fd = 
100                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
101        if (FORMAT(libtrace->format_data)->fd==-1) {
102                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Could not create raw socket");
103                free(libtrace->format_data);
104                return -1;
105        }
106        addr.sll_family = AF_PACKET;
107        addr.sll_protocol = htons(ETH_P_ALL);
108        if (strlen(libtrace->uridata)) {
109                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
110                if (addr.sll_ifindex == 0) {
111                        close(FORMAT(libtrace->format_data)->fd);
112                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
113                        free(libtrace->format_data);
114                        return -1;
115                }
116        }
117        else {
118                addr.sll_ifindex = 0;
119        }
120        if (bind(FORMAT(libtrace->format_data)->fd,
121                                (struct sockaddr*)&addr,
122                                (socklen_t)sizeof(addr))==-1) {
123                free(libtrace->format_data);
124                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to bind to interface %s", libtrace->uridata);
125                return -1;
126        }
127
128        /* If promisc hasn't been specified, set it to "true" if we're
129         * capturing on one interface, or "false" if we're capturing on
130         * all interfaces.
131         */ 
132        if (FORMAT(libtrace->format_data)->promisc==-1) {
133                if (addr.sll_ifindex!=0)
134                        FORMAT(libtrace->format_data)->promisc=1;
135                else
136                        FORMAT(libtrace->format_data)->promisc=0;
137        }
138                               
139        if (FORMAT(libtrace->format_data)->promisc) {
140                struct packet_mreq mreq;
141                socklen_t socklen = sizeof(mreq);
142                memset(&mreq,0,sizeof(mreq));
143                mreq.mr_ifindex = addr.sll_ifindex;
144                mreq.mr_type = PACKET_MR_PROMISC;
145                setsockopt(FORMAT(libtrace->format_data)->fd,
146                                SOL_PACKET,
147                                PACKET_ADD_MEMBERSHIP,
148                                &mreq,
149                                socklen);
150        }
151
152        if (setsockopt(FORMAT(libtrace->format_data)->fd,
153                        SOL_SOCKET,
154                        SO_TIMESTAMP,
155                        &one,
156                        (socklen_t)sizeof(one))==-1) {
157                perror("setsockopt(SO_TIMESTAMP)");
158        }
159
160        return 0;
161}
162
163static int linuxnative_start_output(libtrace_out_t *libtrace)
164{
165        FORMAT(libtrace->format_data)->fd = 
166                                socket(PF_PACKET, SOCK_RAW, 0);
167        if (FORMAT(libtrace->format_data)->fd==-1) {
168                free(libtrace->format_data);
169                return -1;
170        }
171
172        return 0;
173}
174
175static int linuxnative_pause_input(libtrace_t *libtrace)
176{
177        close(FORMAT(libtrace->format_data)->fd);
178        FORMAT(libtrace->format_data)->fd=-1;
179
180        return 0;
181}
182
183static int linuxnative_fin_input(libtrace_t *libtrace) 
184{
185        free(libtrace->format_data);
186        return 0;
187}
188
189static int linuxnative_fin_output(libtrace_out_t *libtrace)
190{
191        close(DATAOUT(libtrace)->fd);
192        DATAOUT(libtrace)->fd=-1;
193        free(libtrace->format_data);
194        return 0;
195}
196
197static int linuxnative_config_input(libtrace_t *libtrace,
198                trace_option_t option,
199                void *data)
200{
201        switch(option) {
202                case TRACE_OPTION_SNAPLEN:
203                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
204                        return 0;
205                case TRACE_OPTION_PROMISC:
206                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
207                        return 0;
208                case TRACE_OPTION_FILTER:
209                        /* We don't support bpf filters in any special way
210                         * so return an error and let libtrace deal with
211                         * emulating it
212                         */
213                        break;
214                case TRACE_OPTION_META_FREQ:
215                        /* No meta-data for this format */
216                        break;
217                case TRACE_OPTION_EVENT_REALTIME:
218                        break;
219                /* Avoid default: so that future options will cause a warning
220                 * here to remind us to implement it, or flag it as
221                 * unimplementable
222                 */
223        }
224       
225        /* Don't set an error - trace_config will try to deal with the
226         * option and will set an error if it fails */
227        return -1;
228}
229
230#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
231
232/* 20 isn't enough on x86_64 */
233#define CMSG_BUF_SIZE 128
234static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
235{
236        struct libtrace_linuxnative_header *hdr;
237        struct msghdr msghdr;
238        struct iovec iovec;
239        unsigned char controlbuf[CMSG_BUF_SIZE];
240        struct cmsghdr *cmsg;
241        socklen_t socklen;
242        int snaplen;
243
244        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
245                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
246                packet->buf_control = TRACE_CTRL_PACKET;
247        }
248
249        packet->header = packet->buffer;
250        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
251        packet->payload = (char*)packet->buffer+sizeof(*hdr);
252
253        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
254        socklen=sizeof(hdr->hdr);
255        snaplen=LIBTRACE_MIN(
256                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
257                        (int)FORMAT(libtrace->format_data)->snaplen);
258
259        msghdr.msg_name = &hdr->hdr;
260        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
261
262        msghdr.msg_iov = &iovec;
263        msghdr.msg_iovlen = 1;
264
265        msghdr.msg_control = &controlbuf;
266        msghdr.msg_controllen = CMSG_BUF_SIZE;
267        msghdr.msg_flags = 0;
268
269        iovec.iov_base = (void*)packet->payload;
270        iovec.iov_len = snaplen;
271
272        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
273
274        if (hdr->wirelen==-1) {
275                trace_set_err(libtrace,errno,"recvmsg");
276                return -1;
277        }
278
279        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
280
281        for (cmsg = CMSG_FIRSTHDR(&msghdr);
282                        cmsg != NULL;
283                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
284                if (cmsg->cmsg_level == SOL_SOCKET
285                        && cmsg->cmsg_type == SO_TIMESTAMP
286                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
287                        memcpy(&hdr->ts, CMSG_DATA(cmsg),
288                                        sizeof(struct timeval));
289                        break;
290                }
291        }
292
293        if (cmsg == NULL && ioctl(FORMAT(libtrace->format_data)->fd,
294                                SIOCGSTAMP,&hdr->ts)==-1)
295                perror("ioctl(SIOCGSTAMP)");
296
297        return hdr->wirelen+sizeof(*hdr);
298}
299
300static int linuxnative_write_packet(libtrace_out_t *trace, 
301                libtrace_packet_t *packet) 
302{
303        struct sockaddr_ll hdr;
304
305        hdr.sll_family = AF_PACKET;
306        hdr.sll_protocol = 0;
307        hdr.sll_ifindex = if_nametoindex(trace->uridata);
308        hdr.sll_hatype = 0;
309        hdr.sll_pkttype = 0;
310        hdr.sll_halen = htons(6); /* FIXME */
311        memcpy(hdr.sll_addr,packet->payload,(size_t)hdr.sll_halen);
312
313        return sendto(DATAOUT(trace)->fd,
314                        packet->payload,
315                        trace_get_capture_length(packet),
316                        0,
317                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
318
319}
320
321static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
322        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
323                                ->hdr.sll_hatype);
324        switch (linktype) {
325                case ARPHRD_ETHER:
326                        return TRACE_TYPE_ETH;
327                case ARPHRD_PPP:
328                        return TRACE_TYPE_NONE;
329                case ARPHRD_80211_RADIOTAP:
330                        return TRACE_TYPE_80211_RADIO;
331                case ARPHRD_IEEE80211:
332                        return TRACE_TYPE_80211;
333                case ARPHRD_SIT:
334                        return TRACE_TYPE_NONE;
335                default: /* shrug, beyond me! */
336                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
337                        return (libtrace_linktype_t)~0U;
338        }
339}
340
341static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
342        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
343                case PACKET_OUTGOING:
344                case PACKET_LOOPBACK:
345                        return TRACE_DIR_OUTGOING;
346                default:
347                        return TRACE_DIR_INCOMING;
348        }
349}
350
351static libtrace_direction_t linuxnative_set_direction(
352                const libtrace_packet_t *packet,
353                libtrace_direction_t direction) {
354
355        switch (direction) {
356                case TRACE_DIR_OUTGOING:
357                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_OUTGOING;
358                        return TRACE_DIR_OUTGOING;
359                case TRACE_DIR_INCOMING:
360                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
361                        return TRACE_DIR_INCOMING;
362                default:
363                        return -1;
364        }
365}
366
367static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
368{
369        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
370}
371
372static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
373{
374        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
375}
376
377static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
378{
379        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
380}
381
382static int linuxnative_get_framing_length(UNUSED
383                const libtrace_packet_t *packet) 
384{
385        return sizeof(struct libtrace_linuxnative_header);
386}
387
388static int linuxnative_get_fd(const libtrace_t *trace) {
389        return FORMAT(trace->format_data)->fd;
390}
391
392static void linuxnative_help(void) {
393        printf("linuxnative format module: $Revision$\n");
394        printf("Supported input URIs:\n");
395        printf("\tint:\n");
396        printf("\n");
397        printf("Supported output URIs:\n");
398        printf("\tnone\n");
399        printf("\n");
400        return;
401}
402static struct libtrace_format_t linuxnative = {
403        "int",
404        "$Id$",
405        TRACE_FORMAT_LINUX_NATIVE,
406        linuxnative_init_input,         /* init_input */
407        linuxnative_config_input,       /* config_input */
408        linuxnative_start_input,        /* start_input */
409        linuxnative_pause_input,        /* pause_input */
410        linuxnative_init_output,        /* init_output */
411        NULL,                           /* config_output */
412        linuxnative_start_output,       /* start_ouput */
413        linuxnative_fin_input,          /* fin_input */
414        linuxnative_fin_output,         /* fin_output */
415        linuxnative_read_packet,        /* read_packet */
416        NULL,                           /* fin_packet */
417        linuxnative_write_packet,       /* write_packet */
418        linuxnative_get_link_type,      /* get_link_type */
419        linuxnative_get_direction,      /* get_direction */
420        linuxnative_set_direction,      /* set_direction */
421        NULL,                           /* get_erf_timestamp */
422        linuxnative_get_timeval,        /* get_timeval */
423        NULL,                           /* get_seconds */
424        NULL,                           /* seek_erf */
425        NULL,                           /* seek_timeval */
426        NULL,                           /* seek_seconds */
427        linuxnative_get_capture_length, /* get_capture_length */
428        linuxnative_get_wire_length,    /* get_wire_length */
429        linuxnative_get_framing_length, /* get_framing_length */
430        NULL,                           /* set_capture_length */
431        linuxnative_get_fd,             /* get_fd */
432        trace_event_device,             /* trace_event */
433        linuxnative_help,               /* help */
434        NULL
435};
436
437void linuxnative_constructor(void) {
438        register_format(&linuxnative);
439}
Note: See TracBrowser for help on using the repository browser.