source: lib/format_linux.c @ 496b8e5

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 496b8e5 was 496b8e5, checked in by Shane Alcock <salcock@…>, 15 years ago

ARPHRD_SIT is now dealt with appropriately

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2004 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: format_template.c,v 1.13 2005/11/22 23:38:56 dlawson Exp $
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                free(libtrace->format_data);
103                return -1;
104        }
105        addr.sll_family = AF_PACKET;
106        addr.sll_protocol = htons(ETH_P_ALL);
107        if (strlen(libtrace->uridata)) {
108                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
109                if (addr.sll_ifindex == 0) {
110                        close(FORMAT(libtrace->format_data)->fd);
111                        free(libtrace->format_data);
112                        return -1;
113                }
114        }
115        else {
116                addr.sll_ifindex = 0;
117        }
118        if (bind(FORMAT(libtrace->format_data)->fd,
119                                (struct sockaddr*)&addr,
120                                sizeof(addr))==-1) {
121                free(libtrace->format_data);
122                return -1;
123        }
124
125        /* If promisc hasn't been specified, set it to "true" if we're
126         * capturing on one interface, or "false" if we're capturing on
127         * all interfaces.
128         */ 
129        if (FORMAT(libtrace->format_data)->promisc==-1) {
130                if (addr.sll_ifindex!=0)
131                        FORMAT(libtrace->format_data)->promisc=1;
132                else
133                        FORMAT(libtrace->format_data)->promisc=0;
134        }
135                               
136        if (FORMAT(libtrace->format_data)->promisc) {
137                struct packet_mreq mreq;
138                socklen_t socklen = sizeof(mreq);
139                memset(&mreq,0,sizeof(mreq));
140                mreq.mr_ifindex = addr.sll_ifindex;
141                mreq.mr_type = PACKET_MR_PROMISC;
142                setsockopt(FORMAT(libtrace->format_data)->fd,
143                                SOL_PACKET,
144                                PACKET_ADD_MEMBERSHIP,
145                                &mreq,
146                                socklen);
147        }
148
149        if (setsockopt(FORMAT(libtrace->format_data)->fd,
150                        SOL_SOCKET,
151                        SO_TIMESTAMP,
152                        &one,
153                        sizeof(one))==-1) {
154                perror("setsockopt(SO_TIMESTAMP)");
155        }
156
157        return 0;
158}
159
160static int linuxnative_start_output(libtrace_out_t *libtrace)
161{
162        FORMAT(libtrace->format_data)->fd = 
163                                socket(PF_PACKET, SOCK_RAW, 0);
164        if (FORMAT(libtrace->format_data)->fd==-1) {
165                free(libtrace->format_data);
166                return -1;
167        }
168
169        return 0;
170}
171
172static int linuxnative_pause_input(libtrace_t *libtrace)
173{
174        close(FORMAT(libtrace->format_data)->fd);
175        FORMAT(libtrace->format_data)->fd=-1;
176
177        return 0;
178}
179
180static int linuxnative_fin_input(libtrace_t *libtrace) 
181{
182        free(libtrace->format_data);
183        return 0;
184}
185
186static int linuxnative_fin_output(libtrace_out_t *libtrace)
187{
188        close(DATAOUT(libtrace)->fd);
189        DATAOUT(libtrace)->fd=-1;
190        free(libtrace->format_data);
191        return 0;
192}
193
194static int linuxnative_config_input(libtrace_t *libtrace,
195                trace_option_t option,
196                void *data)
197{
198        switch(option) {
199                case TRACE_OPTION_SNAPLEN:
200                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
201                        return 0;
202                case TRACE_OPTION_PROMISC:
203                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
204                        return 0;
205                case TRACE_OPTION_FILTER:
206                        /* We don't support bpf filters in any special way
207                         * so return an error and let libtrace deal with
208                         * emulating it
209                         */
210                        break;
211                case TRACE_META_FREQ:
212                        /* No meta-data for this format */
213                        break;
214                /* Avoid default: so that future options will cause a warning
215                 * here to remind us to implement it, or flag it as
216                 * unimplementable
217                 */
218        }
219        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
220                        "Unknown option %i", option);
221        return -1;
222}
223
224#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
225
226/* 20 isn't enough on x86_64 */
227#define CMSG_BUF_SIZE 128
228static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
229{
230        struct libtrace_linuxnative_header *hdr;
231        struct msghdr msghdr;
232        struct iovec iovec;
233        unsigned char controlbuf[CMSG_BUF_SIZE];
234        struct cmsghdr *cmsg;
235        socklen_t socklen;
236        int snaplen;
237
238        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
239                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
240                packet->buf_control = TRACE_CTRL_PACKET;
241        }
242
243        packet->header = packet->buffer;
244        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
245        packet->payload = (char*)packet->buffer+sizeof(*hdr);
246
247        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
248        socklen=sizeof(hdr->hdr);
249        snaplen=LIBTRACE_MIN(
250                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
251                        (int)FORMAT(libtrace->format_data)->snaplen);
252
253        msghdr.msg_name = &hdr->hdr;
254        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
255
256        msghdr.msg_iov = &iovec;
257        msghdr.msg_iovlen = 1;
258
259        msghdr.msg_control = &controlbuf;
260        msghdr.msg_controllen = CMSG_BUF_SIZE;
261        msghdr.msg_flags = 0;
262
263        iovec.iov_base = (void*)packet->payload;
264        iovec.iov_len = snaplen;
265
266        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
267
268        if (hdr->wirelen==-1) {
269                trace_set_err(libtrace,errno,"recvmsg");
270                return -1;
271        }
272
273        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
274
275        for (cmsg = CMSG_FIRSTHDR(&msghdr);
276                        cmsg != NULL;
277                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
278                if (cmsg->cmsg_level == SOL_SOCKET
279                        && cmsg->cmsg_type == SO_TIMESTAMP
280                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
281                        memcpy(&hdr->ts, CMSG_DATA(cmsg),
282                                        sizeof(struct timeval));
283                        break;
284                }
285        }
286
287        if (cmsg == NULL && ioctl(FORMAT(libtrace->format_data)->fd,
288                                SIOCGSTAMP,&hdr->ts)==-1)
289                perror("ioctl(SIOCGSTAMP)");
290
291        return hdr->wirelen+sizeof(*hdr);
292}
293
294static int linuxnative_write_packet(libtrace_out_t *trace, 
295                libtrace_packet_t *packet) 
296{
297        struct sockaddr_ll hdr;
298
299        hdr.sll_family = AF_PACKET;
300        hdr.sll_protocol = 0;
301        hdr.sll_ifindex = if_nametoindex(trace->uridata);
302        hdr.sll_hatype = 0;
303        hdr.sll_pkttype = 0;
304        hdr.sll_halen = htons(6); /* FIXME */
305        memcpy(hdr.sll_addr,packet->payload,hdr.sll_halen);
306
307        return sendto(DATAOUT(trace)->fd,
308                        packet->payload,
309                        trace_get_capture_length(packet),
310                        0,
311                        (struct sockaddr*)&hdr, sizeof(hdr));
312
313}
314
315static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
316        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
317                                ->hdr.sll_hatype);
318        switch (linktype) {
319                case ARPHRD_ETHER:
320                        return TRACE_TYPE_ETH;
321                case ARPHRD_PPP:
322                        return TRACE_TYPE_NONE;
323                case ARPHRD_80211_RADIOTAP:
324                        return TRACE_TYPE_80211_RADIO;
325                case ARPHRD_IEEE80211:
326                        return TRACE_TYPE_80211;
327                case ARPHRD_SIT:
328                        return TRACE_TYPE_NONE;
329                default: /* shrug, beyond me! */
330                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
331                        return (libtrace_linktype_t)~0U;
332        }
333}
334
335static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
336        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
337                case PACKET_OUTGOING:
338                        return TRACE_DIR_OUTGOING;
339                default:
340                        return TRACE_DIR_INCOMING;
341        }
342}
343
344static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
345{
346        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
347}
348
349static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
350{
351        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
352}
353
354static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
355{
356        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
357}
358
359static int linuxnative_get_framing_length(UNUSED
360                const libtrace_packet_t *packet) 
361{
362        return sizeof(struct libtrace_linuxnative_header);
363}
364
365static int linuxnative_get_fd(const libtrace_t *trace) {
366        return FORMAT(trace->format_data)->fd;
367}
368
369static void linuxnative_help(void) {
370        printf("linuxnative format module: $Revision$\n");
371        printf("Supported input URIs:\n");
372        printf("\tint:\n");
373        printf("\n");
374        printf("Supported output URIs:\n");
375        printf("\tnone\n");
376        printf("\n");
377        return;
378}
379static struct libtrace_format_t linuxnative = {
380        "int",
381        "$Id: format_linuxnative.c,v 1.13 2005/11/22 23:38:56 dlawson Exp $",
382        TRACE_FORMAT_LINUX_NATIVE,
383        linuxnative_init_input,         /* init_input */
384        linuxnative_config_input,       /* config_input */
385        linuxnative_start_input,        /* start_input */
386        linuxnative_pause_input,        /* pause_input */
387        linuxnative_init_output,        /* init_output */
388        NULL,                           /* config_output */
389        linuxnative_start_output,       /* start_ouput */
390        linuxnative_fin_input,          /* fin_input */
391        linuxnative_fin_output,         /* fin_output */
392        linuxnative_read_packet,        /* read_packet */
393        NULL,                           /* fin_packet */
394        linuxnative_write_packet,       /* write_packet */
395        linuxnative_get_link_type,      /* get_link_type */
396        linuxnative_get_direction,      /* get_direction */
397        NULL,                           /* set_direction */
398        NULL,                           /* get_erf_timestamp */
399        linuxnative_get_timeval,        /* get_timeval */
400        NULL,                           /* get_seconds */
401        NULL,                           /* seek_erf */
402        NULL,                           /* seek_timeval */
403        NULL,                           /* seek_seconds */
404        linuxnative_get_capture_length, /* get_capture_length */
405        linuxnative_get_wire_length,    /* get_wire_length */
406        linuxnative_get_framing_length, /* get_framing_length */
407        NULL,                           /* set_capture_length */
408        linuxnative_get_fd,             /* get_fd */
409        trace_event_device,             /* trace_event */
410        linuxnative_help,               /* help */
411        NULL
412};
413
414void linuxnative_constructor(void) {
415        register_format(&linuxnative);
416}
Note: See TracBrowser for help on using the repository browser.