source: lib/format_linux.c @ 939bea7

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

Be more verbose about warnings (so we can pinpoint what's going on faster)

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