source: lib/format_linux.c @ d0fd73c

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

Author: Tom Young

Here is a patch to use the control message block, rather than the ioctl for
getting the time stamp. It seems to work for me. As far as i can tell, the
control block stuff has been used for ages (it looked like it was in 2.4.24)
but it should fall back to the ioctl anyway if it has to.

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