source: lib/format_linux.c @ 44028d4

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