source: lib/format_linux.c @ c69b593

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since c69b593 was c69b593, checked in by Shane Alcock <salcock@…>, 11 years ago
  • More strict aliasing fixes
  • Property mode set to 100644
File size: 23.5 KB
RevLine 
[97e39a7]1/*
2 * This file is part of libtrace
3 *
[238d50a]4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
[97e39a7]7 * Authors: Daniel Lawson
[238d50a]8 *          Perry Lorier
9 *          Shane Alcock
[97e39a7]10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
[293999b]30 * $Id$
[97e39a7]31 *
32 */
33
[238d50a]34
[97e39a7]35#include "libtrace.h"
36#include "libtrace_int.h"
37#include "format_helper.h"
38#include "config.h"
[91b72d3]39#include <stdlib.h>
[97e39a7]40
41#ifdef HAVE_INTTYPES_H
42#  include <inttypes.h>
43#else
44# error "Can't find inttypes.h"
45#endif
46
47#include <sys/socket.h>
48#include <netpacket/packet.h>
49#include <net/ethernet.h>
50#include <net/if_arp.h>
51
[edb18ce]52#include <string.h>
53#include <net/if.h>
54#include <sys/ioctl.h>
[d0fd73c]55#include <errno.h>
[91b72d3]56#include <unistd.h>
[edb18ce]57
[3a14f3b]58#include <assert.h>
[c4cf162]59
[238d50a]60/* This format module deals with using the Linux Native capture format.
61 *
62 * Linux Native is a LIVE capture format.
63 *
64 * This format also supports writing which will write packets out to the
65 * network as a form of packet replay. This should not be confused with the
66 * RT protocol which is intended to transfer captured packet records between
67 * RT-speaking programs.
68 */
69
[89404f5]70/* Declared in linux/if_arp.h but not in net/if_arp.h sigh */
71#ifndef ARPHRD_NONE
72#define ARPHRD_NONE 0xfffe
73#endif
74
[50bbce8]75struct tpacket_stats {
76        unsigned int tp_packets;
77        unsigned int tp_drops;
78};
79
[1aa4bf7]80typedef enum { TS_NONE, TS_TIMEVAL, TS_TIMESPEC } timestamptype_t;
81
[238d50a]82struct linux_format_data_t {
83        /* The file descriptor being used for the capture */
[97e39a7]84        int fd;
[238d50a]85        /* The snap length for the capture */
[411f3c7]86        int snaplen;
[238d50a]87        /* Flag indicating whether the interface should be placed in
88         * promiscuous mode */
[411f3c7]89        int promisc;
[238d50a]90        /* The timestamp format used by the capture */ 
[1aa4bf7]91        timestamptype_t timestamptype;
[238d50a]92        /* A BPF filter that is applied to every captured packet */
[394706e]93        libtrace_filter_t *filter;
[238d50a]94        /* Statistics for the capture process, e.g. dropped packet counts */
[50bbce8]95        struct tpacket_stats stats;
[238d50a]96        /* Flag indicating whether the statistics are current or not */
[50bbce8]97        int stats_valid;
[97e39a7]98};
99
[1aa4bf7]100
[238d50a]101/* Note that this structure is passed over the wire in rt encapsulation, and
102 * thus we need to be careful with data sizes.  timeval's and timespec's
103 * can also change their size on 32/64 machines.
[7fa118f]104 */
[238d50a]105
106/* Format header for encapsulating packets captured using linux native */
[97e39a7]107struct libtrace_linuxnative_header {
[238d50a]108        /* Timestamp of the packet, as a timeval */
[7fa118f]109        struct {
110                uint32_t tv_sec;
111                uint32_t tv_usec;
112        } tv;
[238d50a]113        /* Timestamp of the packet, as a timespec */
[7fa118f]114        struct {
115                uint32_t tv_sec;
116                uint32_t tv_nsec;
117        } ts;
[238d50a]118        /* The timestamp format used by the process that captured this packet */
[7fa118f]119        uint8_t timestamptype;
[238d50a]120        /* Wire length */
[7fa118f]121        uint32_t wirelen;
[238d50a]122        /* Capture length */
[7fa118f]123        uint32_t caplen;
[238d50a]124        /* The linux native header itself */
[97e39a7]125        struct sockaddr_ll hdr;
126};
127
[238d50a]128struct linux_output_format_data_t {
129        /* The file descriptor used to write the packets */
[e4e95499]130        int fd;
131};
132
[238d50a]133#define FORMAT(x) ((struct linux_format_data_t*)(x))
134#define DATAOUT(x) ((struct linux_output_format_data_t*)((x)->format_data))
[97e39a7]135
[91b72d3]136static int linuxnative_probe_filename(const char *filename)
137{
138        /* Is this an interface? */
139        return (if_nametoindex(filename) != 0);
140}
141
[411f3c7]142static int linuxnative_init_input(libtrace_t *libtrace) 
143{
[238d50a]144        libtrace->format_data = (struct linux_format_data_t *)
145                malloc(sizeof(struct linux_format_data_t));
[411f3c7]146        FORMAT(libtrace->format_data)->fd = -1;
[3ed9a80]147        FORMAT(libtrace->format_data)->promisc = -1;
[cdcaef6]148        FORMAT(libtrace->format_data)->snaplen = LIBTRACE_PACKET_BUFSIZE;
[394706e]149        FORMAT(libtrace->format_data)->filter = NULL;
[50bbce8]150        FORMAT(libtrace->format_data)->stats_valid = 0;
[411f3c7]151
152        return 0;
153}
154
[e4e95499]155static int linuxnative_init_output(libtrace_out_t *libtrace)
156{
[238d50a]157        libtrace->format_data = (struct linux_output_format_data_t*)
158                malloc(sizeof(struct linux_output_format_data_t));
[e4e95499]159        DATAOUT(libtrace)->fd = -1;
160
161        return 0;
162}
163
[411f3c7]164static int linuxnative_start_input(libtrace_t *libtrace)
165{
166        struct sockaddr_ll addr;
[d0fd73c]167        int one = 1;
[9a5b234]168        memset(&addr,0,sizeof(addr));
[394706e]169        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
[238d50a]170       
171        /* Create a raw socket for reading packets on */
[97e39a7]172        FORMAT(libtrace->format_data)->fd = 
173                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
174        if (FORMAT(libtrace->format_data)->fd==-1) {
[4b6495c3]175                trace_set_err(libtrace, errno, "Could not create raw socket");
[97e39a7]176                free(libtrace->format_data);
[566e404]177                return -1;
[97e39a7]178        }
[238d50a]179
180        /* Bind to the capture interface */
[97e39a7]181        addr.sll_family = AF_PACKET;
182        addr.sll_protocol = htons(ETH_P_ALL);
183        if (strlen(libtrace->uridata)) {
184                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
185                if (addr.sll_ifindex == 0) {
186                        close(FORMAT(libtrace->format_data)->fd);
[205809b]187                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
[97e39a7]188                        free(libtrace->format_data);
[566e404]189                        return -1;
[97e39a7]190                }
191        }
192        else {
193                addr.sll_ifindex = 0;
194        }
195        if (bind(FORMAT(libtrace->format_data)->fd,
196                                (struct sockaddr*)&addr,
[4bd8a5b]197                                (socklen_t)sizeof(addr))==-1) {
[97e39a7]198                free(libtrace->format_data);
[4b6495c3]199                trace_set_err(libtrace, errno, "Failed to bind to interface %s", libtrace->uridata);
[566e404]200                return -1;
[97e39a7]201        }
[3ed9a80]202
203        /* If promisc hasn't been specified, set it to "true" if we're
204         * capturing on one interface, or "false" if we're capturing on
205         * all interfaces.
206         */ 
207        if (FORMAT(libtrace->format_data)->promisc==-1) {
208                if (addr.sll_ifindex!=0)
209                        FORMAT(libtrace->format_data)->promisc=1;
210                else
211                        FORMAT(libtrace->format_data)->promisc=0;
212        }
[238d50a]213       
214        /* Enable promiscuous mode, if requested */                     
[3ed9a80]215        if (FORMAT(libtrace->format_data)->promisc) {
[97e39a7]216                struct packet_mreq mreq;
217                socklen_t socklen = sizeof(mreq);
[9a5b234]218                memset(&mreq,0,sizeof(mreq));
[97e39a7]219                mreq.mr_ifindex = addr.sll_ifindex;
220                mreq.mr_type = PACKET_MR_PROMISC;
[cdcaef6]221                if (setsockopt(FORMAT(libtrace->format_data)->fd,
[97e39a7]222                                SOL_PACKET,
223                                PACKET_ADD_MEMBERSHIP,
224                                &mreq,
[cdcaef6]225                                socklen)==-1) {
226                        perror("setsockopt(PROMISC)");
227                }
[97e39a7]228        }
[238d50a]229
230        /* Set the timestamp option on the socket - aim for the most detailed
231         * clock resolution possible */
[1aa4bf7]232#ifdef SO_TIMESTAMPNS
233        if (setsockopt(FORMAT(libtrace->format_data)->fd,
234                        SOL_SOCKET,
235                        SO_TIMESTAMPNS,
236                        &one,
237                        (socklen_t)sizeof(one))!=-1) {
238                FORMAT(libtrace->format_data)->timestamptype = TS_TIMESPEC;
239        }
240        else
241        /* DANGER: This is a dangling else to only do the next setsockopt() if we fail the first! */
242#endif
[3b10b9f]243        if (setsockopt(FORMAT(libtrace->format_data)->fd,
[d0fd73c]244                        SOL_SOCKET,
245                        SO_TIMESTAMP,
246                        &one,
[1aa4bf7]247                        (socklen_t)sizeof(one))!=-1) {
248                FORMAT(libtrace->format_data)->timestamptype = TS_TIMEVAL;
[3b10b9f]249        }
[1aa4bf7]250        else 
251                FORMAT(libtrace->format_data)->timestamptype = TS_NONE;
[d0fd73c]252
[3a14f3b]253        /* Push BPF filter into the kernel. At this stage we can safely assume
254         * that the filterstring has been compiled, or the filter was supplied
255         * pre-compiled.
[394706e]256         */
257        if (filter != NULL) {
[3a14f3b]258                assert(filter->flag == 1);
[394706e]259                if (setsockopt(FORMAT(libtrace->format_data)->fd,
260                                        SOL_SOCKET,
261                                        SO_ATTACH_FILTER,
262                                        &filter->filter,
263                                        sizeof(filter->filter)) == -1) {
264                        perror("setsockopt(SO_ATTACH_FILTER)");
265                } else { 
266                        /* The socket accepted the filter, so we need to
267                         * consume any buffered packets that were received
268                         * between opening the socket and applying the filter.
269                         */
270                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
271                        while(recv(FORMAT(libtrace->format_data)->fd,
272                                        buf,
273                                        (size_t) LIBTRACE_PACKET_BUFSIZE,
274                                        MSG_DONTWAIT) != -1) { }
275                        free(buf);
276                }
277        }
[50bbce8]278
279        FORMAT(libtrace->format_data)->stats_valid=0;
[394706e]280                                       
[566e404]281        return 0;
[97e39a7]282}
283
[e4e95499]284static int linuxnative_start_output(libtrace_out_t *libtrace)
285{
286        FORMAT(libtrace->format_data)->fd = 
287                                socket(PF_PACKET, SOCK_RAW, 0);
288        if (FORMAT(libtrace->format_data)->fd==-1) {
289                free(libtrace->format_data);
290                return -1;
291        }
[50bbce8]292        FORMAT(libtrace->format_data)->stats_valid=0;
[e4e95499]293
294        return 0;
295}
296
[411f3c7]297static int linuxnative_pause_input(libtrace_t *libtrace)
298{
[97e39a7]299        close(FORMAT(libtrace->format_data)->fd);
[411f3c7]300        FORMAT(libtrace->format_data)->fd=-1;
301
302        return 0;
303}
304
305static int linuxnative_fin_input(libtrace_t *libtrace) 
306{
[394706e]307        if (FORMAT(libtrace->format_data)->filter != NULL)
308                free(FORMAT(libtrace->format_data)->filter);
[4b6495c3]309        if (libtrace->format_data)
310                free(libtrace->format_data);
[394706e]311       
[97e39a7]312        return 0;
313}
314
[e4e95499]315static int linuxnative_fin_output(libtrace_out_t *libtrace)
316{
317        close(DATAOUT(libtrace)->fd);
318        DATAOUT(libtrace)->fd=-1;
319        free(libtrace->format_data);
320        return 0;
321}
322
[238d50a]323/* Compiles a libtrace BPF filter for use with a linux native socket */
[394706e]324static int linuxnative_configure_bpf(libtrace_t *libtrace, 
325                libtrace_filter_t *filter) {
326#ifdef HAVE_LIBPCAP
327        struct ifreq ifr;
328        unsigned int arphrd;
329        libtrace_dlt_t dlt;
330        libtrace_filter_t *f;
331        int sock;
332        pcap_t *pcap;
333
[3a14f3b]334        /* Take a copy of the filter object as it was passed in */
[394706e]335        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
336        memcpy(f, filter, sizeof(libtrace_filter_t));
337       
[3a14f3b]338        /* If we are passed a filter with "flag" set to zero, then we must
339         * compile the filterstring before continuing. This involves
340         * determining the linktype, passing the filterstring to libpcap to
341         * compile, and saving the result for trace_start() to push into the
342         * kernel.
343         * If flag is set to one, then the filter was probably generated using
344         * trace_create_filter_from_bytecode() and so we don't need to do
345         * anything (we've just copied it above).
346         */
347        if (f->flag == 0) {
348                sock = socket(PF_INET, SOCK_STREAM, 0);
349                memset(&ifr, 0, sizeof(struct ifreq));
350                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
351                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
352                        perror("Can't get HWADDR for interface");
353                        return -1;
354                }
[f2fae49]355                close(sock);
[3a14f3b]356
357                arphrd = ifr.ifr_hwaddr.sa_family;
358                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
359
360                pcap = pcap_open_dead(dlt, 
361                                FORMAT(libtrace->format_data)->snaplen);
[394706e]362
[3a14f3b]363                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
364                        perror("PCAP failed to compile the filterstring");
365                        return -1;
366                }
[394706e]367
[3a14f3b]368                pcap_close(pcap);
369               
370                /* Set the "flag" to indicate that the filterstring has been
371                 * compiled
372                 */
373                f->flag = 1;
374        }
375       
[394706e]376        if (FORMAT(libtrace->format_data)->filter != NULL)
377                free(FORMAT(libtrace->format_data)->filter);
378       
379        FORMAT(libtrace->format_data)->filter = f;
[3a14f3b]380       
[394706e]381        return 0;
382#else
383        return -1
384#endif
385}
[411f3c7]386static int linuxnative_config_input(libtrace_t *libtrace,
387                trace_option_t option,
388                void *data)
389{
390        switch(option) {
391                case TRACE_OPTION_SNAPLEN:
392                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
393                        return 0;
394                case TRACE_OPTION_PROMISC:
395                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
396                        return 0;
397                case TRACE_OPTION_FILTER:
[394706e]398                        return linuxnative_configure_bpf(libtrace, 
399                                        (libtrace_filter_t *) data);
[646aca1]400                case TRACE_OPTION_META_FREQ:
[cd7eec7]401                        /* No meta-data for this format */
402                        break;
[646aca1]403                case TRACE_OPTION_EVENT_REALTIME:
[238d50a]404                        /* Live captures are always going to be in trace time */
[646aca1]405                        break;
[411f3c7]406                /* Avoid default: so that future options will cause a warning
407                 * here to remind us to implement it, or flag it as
408                 * unimplementable
409                 */
410        }
[205809b]411       
[708f9ae]412        /* Don't set an error - trace_config will try to deal with the
413         * option and will set an error if it fails */
[411f3c7]414        return -1;
415}
416
[f0fb38f]417static int linuxnative_prepare_packet(libtrace_t *libtrace, 
418                libtrace_packet_t *packet, void *buffer, 
419                libtrace_rt_types_t rt_type, uint32_t flags) {
420
421        if (packet->buffer != buffer &&
422                        packet->buf_control == TRACE_CTRL_PACKET) {
423                free(packet->buffer);
424        }
425
426        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
427                packet->buf_control = TRACE_CTRL_PACKET;
428        } else
429                packet->buf_control = TRACE_CTRL_EXTERNAL;
430
431
432        packet->buffer = buffer;
433        packet->header = buffer;
434        packet->payload = (char *)buffer + 
435                sizeof(struct libtrace_linuxnative_header);
436        packet->type = rt_type;
437
438        if (libtrace->format_data == NULL) {
439                if (linuxnative_init_input(libtrace))
440                        return -1;
441        }
442        return 0;
443       
444}
445
[411f3c7]446#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
447
[3b10b9f]448/* 20 isn't enough on x86_64 */
449#define CMSG_BUF_SIZE 128
[e4e95499]450static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
451{
[566e404]452        struct libtrace_linuxnative_header *hdr;
[d0fd73c]453        struct msghdr msghdr;
454        struct iovec iovec;
455        unsigned char controlbuf[CMSG_BUF_SIZE];
456        struct cmsghdr *cmsg;
[edb18ce]457        socklen_t socklen;
[411f3c7]458        int snaplen;
[f0fb38f]459        uint32_t flags = 0;
460       
[566e404]461        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
[4bd8a5b]462                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
[cdcaef6]463                if (!packet->buffer) {
464                        perror("Cannot allocate buffer");
465                }
[566e404]466        }
467
[f0fb38f]468        flags |= TRACE_PREP_OWN_BUFFER;
469       
[cab58c5]470        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
[566e404]471
[85a79b0]472        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
[edb18ce]473        socklen=sizeof(hdr->hdr);
[411f3c7]474        snaplen=LIBTRACE_MIN(
475                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
476                        (int)FORMAT(libtrace->format_data)->snaplen);
[d0fd73c]477
[238d50a]478        /* Prepare the msghdr and iovec for the kernel to write the
479         * captured packet into. The msghdr will point to the part of our
480         * buffer reserved for sll header, while the iovec will point at
481         * the buffer following the sll header. */
482
[d0fd73c]483        msghdr.msg_name = &hdr->hdr;
484        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
485
486        msghdr.msg_iov = &iovec;
487        msghdr.msg_iovlen = 1;
488
489        msghdr.msg_control = &controlbuf;
490        msghdr.msg_controllen = CMSG_BUF_SIZE;
491        msghdr.msg_flags = 0;
492
[1f44884]493        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
[d0fd73c]494        iovec.iov_len = snaplen;
495
496        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
497
[d7e8e67]498        if (hdr->wirelen==~0U) {
[d0fd73c]499                trace_set_err(libtrace,errno,"recvmsg");
[97e39a7]500                return -1;
[d0fd73c]501        }
[97e39a7]502
[d7e8e67]503        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
[411f3c7]504
[238d50a]505        /* Extract the timestamps from the msghdr and store them in our
506         * linux native encapsulation, so that we can preserve the formatting
507         * across multiple architectures */
508
[d0fd73c]509        for (cmsg = CMSG_FIRSTHDR(&msghdr);
510                        cmsg != NULL;
511                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
512                if (cmsg->cmsg_level == SOL_SOCKET
513                        && cmsg->cmsg_type == SO_TIMESTAMP
[3b10b9f]514                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
[c69b593]515                       
516                        struct timeval *tv;
517                        tv = (struct timeval *)CMSG_DATA(cmsg);
518                       
519                       
520                        hdr->tv.tv_sec = tv->tv_sec;
521                        hdr->tv.tv_usec = tv->tv_usec;
[1aa4bf7]522                        hdr->timestamptype = TS_TIMEVAL;
523                        break;
524                } 
525#ifdef SO_TIMESTAMPNS
526                else if (cmsg->cmsg_level == SOL_SOCKET
527                        && cmsg->cmsg_type == SO_TIMESTAMPNS
528                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
[c69b593]529
530                        struct timespec *tv;
531                        tv = (struct timespec *)CMSG_DATA(cmsg);
532
533                        hdr->ts.tv_sec = tv->tv_sec;
534                        hdr->ts.tv_nsec = tv->tv_nsec;
[1aa4bf7]535                        hdr->timestamptype = TS_TIMESPEC;
[d0fd73c]536                        break;
537                }
[1aa4bf7]538#endif
[d0fd73c]539        }
540
[238d50a]541        /* Did we not get given a timestamp? Try to get one from the
542         * file descriptor directly */
[1aa4bf7]543        if (cmsg == NULL) {
[7fa118f]544                struct timeval tv;
[1aa4bf7]545                if (ioctl(FORMAT(libtrace->format_data)->fd, 
[7fa118f]546                                  SIOCGSTAMP,&tv)==0) {
547                        hdr->tv.tv_sec = tv.tv_sec;
548                        hdr->tv.tv_usec = tv.tv_usec;
[1aa4bf7]549                        hdr->timestamptype = TS_TIMEVAL;
550                }
551                else {
552                        hdr->timestamptype = TS_NONE;
553                }
554        }
[97e39a7]555
[238d50a]556        /* Buffer contains all of our packet (including our custom header) so
557         * we just need to get prepare_packet to set all our packet pointers
558         * appropriately */
559       
[f0fb38f]560        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
561                                packet->type, flags))
562                return -1;
563       
[97e39a7]564        return hdr->wirelen+sizeof(*hdr);
565}
566
[e4e95499]567static int linuxnative_write_packet(libtrace_out_t *trace, 
[85a79b0]568                libtrace_packet_t *packet) 
[e4e95499]569{
570        struct sockaddr_ll hdr;
571
572        hdr.sll_family = AF_PACKET;
573        hdr.sll_protocol = 0;
[030aa3f]574        hdr.sll_ifindex = if_nametoindex(trace->uridata);
[e4e95499]575        hdr.sll_hatype = 0;
576        hdr.sll_pkttype = 0;
[99ff3d9]577        hdr.sll_halen = htons(6); /* FIXME */
[013de36e]578        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
[e4e95499]579
[238d50a]580        /* This is pretty easy, just send the payload using sendto() (after
581         * setting up the sll header properly, of course) */
[e4e95499]582        return sendto(DATAOUT(trace)->fd,
583                        packet->payload,
584                        trace_get_capture_length(packet),
585                        0,
[4bd8a5b]586                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
[e4e95499]587
588}
589
[97e39a7]590static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
[c042b5c]591        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
592                                ->hdr.sll_hatype);
[238d50a]593        /* Convert the ARPHRD type into an appropriate libtrace link type */
594
[fc2e63f]595        switch (linktype) {
[51c83a4]596                case ARPHRD_ETHER:
[97e39a7]597                        return TRACE_TYPE_ETH;
[8c747709]598                case ARPHRD_PPP:
599                        return TRACE_TYPE_NONE;
[ef3660cb]600                case ARPHRD_80211_RADIOTAP:
601                        return TRACE_TYPE_80211_RADIO;
602                case ARPHRD_IEEE80211:
603                        return TRACE_TYPE_80211;
[496b8e5]604                case ARPHRD_SIT:
[89404f5]605                case ARPHRD_NONE:
[496b8e5]606                        return TRACE_TYPE_NONE;
[97e39a7]607                default: /* shrug, beyond me! */
[9cad9c9]608                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
[85a79b0]609                        return (libtrace_linktype_t)~0U;
[97e39a7]610        }
611}
612
[431548c5]613static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
[97e39a7]614        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
615                case PACKET_OUTGOING:
[27bd348]616                case PACKET_LOOPBACK:
[431548c5]617                        return TRACE_DIR_OUTGOING;
[97e39a7]618                default:
[431548c5]619                        return TRACE_DIR_INCOMING;
[97e39a7]620        }
621}
622
[1008250]623static libtrace_direction_t linuxnative_set_direction(
[f2fae49]624                libtrace_packet_t *packet,
[1008250]625                libtrace_direction_t direction) {
626
627        switch (direction) {
628                case TRACE_DIR_OUTGOING:
629                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_OUTGOING;
630                        return TRACE_DIR_OUTGOING;
631                case TRACE_DIR_INCOMING:
[27bd348]632                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
[1008250]633                        return TRACE_DIR_INCOMING;
634                default:
635                        return -1;
636        }
637}
638
[1aa4bf7]639static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
640{
641        struct libtrace_linuxnative_header *hdr = 
642                (struct libtrace_linuxnative_header*) packet->buffer;
643        /* We have to upconvert from timeval to timespec */
644        if (hdr->timestamptype == TS_TIMEVAL) {
645                struct timespec ts;
646                ts.tv_sec = hdr->tv.tv_sec;
647                ts.tv_nsec = hdr->tv.tv_usec*1000;
648                return ts;
649        }
[7fa118f]650        else {
651                struct timespec ts;
652                ts.tv_sec = hdr->ts.tv_sec;
653                ts.tv_nsec = hdr->ts.tv_nsec;
654                return ts;
655        }
[1aa4bf7]656}
657
[411f3c7]658static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
659{
[1aa4bf7]660        struct libtrace_linuxnative_header *hdr = 
661                (struct libtrace_linuxnative_header*) packet->buffer;
662        /* We have to downconvert from timespec to timeval */
663        if (hdr->timestamptype == TS_TIMESPEC) {
664                struct timeval tv;
665                tv.tv_sec = hdr->ts.tv_sec;
666                tv.tv_usec = hdr->ts.tv_nsec/1000;
667                return tv;
668        }
[7fa118f]669        else {
670                struct timeval tv;
671                tv.tv_sec = hdr->tv.tv_sec;
672                tv.tv_usec = hdr->tv.tv_usec;
673                return tv;
674        }
[97e39a7]675}
676
[411f3c7]677static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
678{
679        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
680}
681
682static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
683{
[97e39a7]684        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
685}
686
[85a79b0]687static int linuxnative_get_framing_length(UNUSED
688                const libtrace_packet_t *packet) 
[411f3c7]689{
[97e39a7]690        return sizeof(struct libtrace_linuxnative_header);
691}
692
[f68d5b8]693static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
694                size_t size) {
695
696        struct libtrace_linuxnative_header *linux_hdr = NULL;
697        assert(packet);
698        if (size > trace_get_capture_length(packet)) {
699                /* We should avoid making a packet larger */
700                return trace_get_capture_length(packet);
701        }
702       
703        /* Reset the cached capture length */
704        packet->capture_length = -1;
705
706        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
707        linux_hdr->caplen = size;
708        return trace_get_capture_length(packet);
709}
710
[97e39a7]711static int linuxnative_get_fd(const libtrace_t *trace) {
[f0fb38f]712        if (trace->format_data == NULL)
713                return -1;
[97e39a7]714        return FORMAT(trace->format_data)->fd;
715}
716
[25a9201]717/* Linux doesn't keep track how many packets were seen before filtering
718 * so we can't tell how many packets were filtered.  Bugger.  So annoying.
[4f87b817]719 *
720 * Since we tell libtrace that we do support filtering, if we don't declare
721 * this here as failing, libtrace will happily report for us that it didn't
722 * filter any packets, so don't lie -- return that we don't know.
[25a9201]723 */
[d267f4d]724static uint64_t linuxnative_get_filtered_packets(libtrace_t *trace UNUSED) {
[25a9201]725        return UINT64_MAX;
726}
727
[238d50a]728/* Number of packets that passed filtering */
[50bbce8]729static uint64_t linuxnative_get_captured_packets(libtrace_t *trace) {
[f0fb38f]730        if (trace->format_data == NULL)
731                return UINT64_MAX;
732        if (FORMAT(trace->format_data)->fd == -1) {
733                /* This is probably a 'dead' trace so obviously we can't query
734                 * the socket for capture counts, can we? */
735                return UINT64_MAX;
736        }
737       
[95fee28]738        if ((FORMAT(trace->format_data)->stats_valid & 1) 
739                        || FORMAT(trace->format_data)->stats_valid == 0) {
[50bbce8]740                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
741                getsockopt(FORMAT(trace->format_data)->fd, 
742                                SOL_PACKET,
743                                PACKET_STATISTICS,
744                                &FORMAT(trace->format_data)->stats,
745                                &len);
[95fee28]746                FORMAT(trace->format_data)->stats_valid |= 1;
[50bbce8]747        }
748
749        return FORMAT(trace->format_data)->stats.tp_packets;
750}
751
[25a9201]752/* Number of packets that got past filtering and were then dropped because
753 * of lack of space
754 */
[50bbce8]755static uint64_t linuxnative_get_dropped_packets(libtrace_t *trace) {
[f0fb38f]756        if (trace->format_data == NULL)
757                return UINT64_MAX;
758        if (FORMAT(trace->format_data)->fd == -1) {
759                /* This is probably a 'dead' trace so obviously we can't query
760                 * the socket for drop counts, can we? */
761                return UINT64_MAX;
762        }
763       
[95fee28]764        if ((FORMAT(trace->format_data)->stats_valid & 2)
765                        || (FORMAT(trace->format_data)->stats_valid==0)) {
[50bbce8]766                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
767                getsockopt(FORMAT(trace->format_data)->fd, 
768                                SOL_PACKET,
769                                PACKET_STATISTICS,
770                                &FORMAT(trace->format_data)->stats,
771                                &len);
[95fee28]772                FORMAT(trace->format_data)->stats_valid |= 2;
[50bbce8]773        }
774
775        return FORMAT(trace->format_data)->stats.tp_drops;
776}
777
[33d83d4]778static void linuxnative_help(void) {
[97e39a7]779        printf("linuxnative format module: $Revision$\n");
780        printf("Supported input URIs:\n");
[238d50a]781        printf("\tint:eth0\n");
[97e39a7]782        printf("\n");
783        printf("Supported output URIs:\n");
[238d50a]784        printf("\tint:eth0\n");
[97e39a7]785        printf("\n");
786        return;
787}
788static struct libtrace_format_t linuxnative = {
789        "int",
[293999b]790        "$Id$",
[97e39a7]791        TRACE_FORMAT_LINUX_NATIVE,
[91b72d3]792        linuxnative_probe_filename,     /* probe filename */
793        NULL,                           /* probe magic */
[97e39a7]794        linuxnative_init_input,         /* init_input */
[411f3c7]795        linuxnative_config_input,       /* config_input */
796        linuxnative_start_input,        /* start_input */
797        linuxnative_pause_input,        /* pause_input */
[e4e95499]798        linuxnative_init_output,        /* init_output */
[97e39a7]799        NULL,                           /* config_output */
[e4e95499]800        linuxnative_start_output,       /* start_ouput */
[97e39a7]801        linuxnative_fin_input,          /* fin_input */
[e4e95499]802        linuxnative_fin_output,         /* fin_output */
[97e39a7]803        linuxnative_read_packet,        /* read_packet */
[f0fb38f]804        linuxnative_prepare_packet,     /* prepare_packet */
[97e39a7]805        NULL,                           /* fin_packet */
[e4e95499]806        linuxnative_write_packet,       /* write_packet */
[97e39a7]807        linuxnative_get_link_type,      /* get_link_type */
808        linuxnative_get_direction,      /* get_direction */
[1008250]809        linuxnative_set_direction,      /* set_direction */
[97e39a7]810        NULL,                           /* get_erf_timestamp */
811        linuxnative_get_timeval,        /* get_timeval */
[1aa4bf7]812        linuxnative_get_timespec,       /* get_timespec */
[97e39a7]813        NULL,                           /* get_seconds */
814        NULL,                           /* seek_erf */
815        NULL,                           /* seek_timeval */
816        NULL,                           /* seek_seconds */
[411f3c7]817        linuxnative_get_capture_length, /* get_capture_length */
[97e39a7]818        linuxnative_get_wire_length,    /* get_wire_length */
819        linuxnative_get_framing_length, /* get_framing_length */
[f68d5b8]820        linuxnative_set_capture_length, /* set_capture_length */
[f2fae49]821        NULL,                           /* get_received_packets */
[25a9201]822        linuxnative_get_filtered_packets,/* get_filtered_packets */
[50bbce8]823        linuxnative_get_dropped_packets,/* get_dropped_packets */
824        linuxnative_get_captured_packets,/* get_captured_packets */
[97e39a7]825        linuxnative_get_fd,             /* get_fd */
[411f3c7]826        trace_event_device,             /* trace_event */
[97e39a7]827        linuxnative_help,               /* help */
828        NULL
829};
830
[33d83d4]831void linuxnative_constructor(void) {
[97e39a7]832        register_format(&linuxnative);
833}
Note: See TracBrowser for help on using the repository browser.