source: lib/format_erf.c @ 509ee47

develop
Last change on this file since 509ee47 was 509ee47, checked in by Shane Alcock <salcock@…>, 2 years ago

Add option to allow users to specify a constant ERF framing length.

This can be useful for situations where

a) the input uses ERF (or some derivative thereof)
b) the link type and ERF record type are constant for the

duration of the capture

c) performance is critical

This option allows users to simply tell libtrace what the ERF
framing length on every packet is going to be, so libtrace
doesn't have to repeatedly derive the framing length for each
packet it processes. At high packet rates, the time taken to
do this calculation can really add up and it makes no sense
to risk dropping packets because you're busy calculating a value
that is always a single constant value.

  • Property mode set to 100644
File size: 27.1 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27#define _GNU_SOURCE
28
29#include "config.h"
30#include "common.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "format_erf.h"
35#include "wandio.h"
36
37#include <errno.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42
43
44#ifdef WIN32
45#  include <io.h>
46#  include <share.h>
47#  define PATH_MAX _MAX_PATH
48#else
49#  include <netdb.h>
50#  ifndef PATH_MAX
51#       define PATH_MAX 4096
52#  endif
53#  include <sys/ioctl.h>
54#endif
55
56/* This format module deals with reading and writing ERF traces. ERF is the
57 * trace format developed by Endace for use by DAG hardware capture cards.
58 *
59 * ERF is not a live capture format.
60 *
61 */
62
63
64static struct libtrace_format_t erfformat;
65
66#define DATA(x) ((struct erf_format_data_t *)x->format_data)
67#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
68
69#define IN_OPTIONS DATA(libtrace)->options
70#define OUTPUT DATAOUT(libtrace)
71#define OUT_OPTIONS DATAOUT(libtrace)->options
72
73/* "Global" data that is stored for each ERF input trace */
74struct erf_format_data_t {
75       
76        /* Index used for seeking within a trace */
77        struct {
78                /* The index itself */
79                io_t *index;
80                /* The offset of the index */
81                off_t index_len;
82                /* Indicates the existence of an index */
83                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
84        } seek;
85
86        /* Number of packets that were dropped during the capture */
87        uint64_t drops;
88
89        /* Config options for the input trace */
90        struct {
91                /* Flag indicating whether the event API should replicate the
92                 * time gaps between each packet or return a PACKET event for
93                 * each packet */
94                int real_time;
95        } options;
96};
97
98/* "Global" data that is stored for each ERF output trace */
99struct erf_format_data_out_t {
100
101        /* Config options for the output trace */
102        struct {
103                /* Compression level for the output file */
104                int level;
105                /* Compression type */
106                int compress_type;
107                /* File flags used to open the file, e.g. O_CREATE */
108                int fileflag;
109        } options;
110
111        /* The output file itself */
112        iow_t *file;
113       
114};
115
116typedef struct erf_index_t {
117        uint64_t timestamp;
118        uint64_t offset; 
119} erf_index_t;
120
121/* Ethernet packets have a 2 byte padding before the packet
122 * so that the IP header is aligned on a 32 bit boundary.
123 */
124static inline int erf_get_padding(const libtrace_packet_t *packet)
125{
126        dag_record_t *erfptr = (dag_record_t *)packet->header;
127
128        switch(packet->trace->format->type) {
129                case TRACE_FORMAT_ERF:
130                case TRACE_FORMAT_NDAG:
131                case TRACE_FORMAT_RAWERF:
132                case TRACE_FORMAT_DPDK_NDAG:
133                        switch((erfptr->type & 0x7f)) {
134                                case TYPE_ETH:
135                                case TYPE_COLOR_ETH:
136                                case TYPE_DSM_COLOR_ETH:
137                                case TYPE_COLOR_HASH_ETH:
138                                        return 2;
139                                default:
140                                        return 0;
141                        }
142                        break;
143                default:
144                        switch(trace_get_link_type(packet)) {
145                                case TRACE_TYPE_ETH:    return 2;
146                                default:                return 0;
147                        }
148                        break;
149        }
150        return 0;
151}
152
153int erf_is_color_type(uint8_t erf_type)
154{
155        switch(erf_type & 0x7f) {
156                case TYPE_COLOR_HDLC_POS:
157                case TYPE_DSM_COLOR_HDLC_POS:
158                case TYPE_COLOR_ETH:
159                case TYPE_DSM_COLOR_ETH:
160                case TYPE_COLOR_HASH_POS:
161                case TYPE_COLOR_HASH_ETH:
162                        return 1;
163        }
164
165        return 0;
166}
167
168int erf_get_framing_length(const libtrace_packet_t *packet)
169{
170        uint16_t extsize = 0;
171        dag_record_t *erfptr = NULL;
172        uint64_t *exthdr = NULL;
173        uint8_t *firstbyte;
174
175        erfptr = (dag_record_t *)packet->header;
176        if ((erfptr->type & 0x80) == 0x80) {
177                /* Extension headers are present */
178                exthdr = (uint64_t *)((char *)packet->header + dag_record_size);
179                extsize += 8;
180
181                firstbyte = (uint8_t *)exthdr;
182                while ((*firstbyte & 0x80) == 0x80) {
183                        extsize += 8;
184                        exthdr ++;
185                        firstbyte = (uint8_t *)exthdr;
186                        if (extsize > ntohs(erfptr->rlen)) {
187                                trace_set_err(packet->trace, TRACE_ERR_BAD_PACKET, "Extension size is greater than dag record record length in erf_get_framing_length()");
188                                return -1;
189                        }
190                }
191        }
192        return dag_record_size + extsize + erf_get_padding(packet);
193}
194
195/* Attempts to determine whether a given trace file is using the ERF format
196 *
197 * Returns 1 if the trace is probably ERF, 0 otherwise
198 */
199static int erf_probe_magic(io_t *io)
200{
201        char buffer[4096];
202        int len;
203        dag_record_t *erf;
204        len = wandio_peek(io, buffer, sizeof(buffer));
205        if (len < (int)dag_record_size) {
206                return 0; /* False */
207        }
208        erf = (dag_record_t *) buffer;
209        /* If the record is too short */
210        if (ntohs(erf->rlen) < dag_record_size) {
211                return 0;
212        }
213        /* There aren't any erf traces before 1995-01-01 */
214        if (bswap_le_to_host64(erf->ts) < 0x2f0539b000000000ULL) {
215                return 0;
216        }
217        /* And not pcap! */
218        if (bswap_le_to_host64(erf->ts) >>32 == 0xa1b2c3d4) {
219                return 0;
220        }
221        /* And not the other pcap! */
222        if (bswap_le_to_host64(erf->ts) >>32 == 0xd4c3b2a1) {
223                return 0;
224        }
225        /* Is this a proper typed packet */
226        if ((erf->type & 0x7f) > ERF_TYPE_MAX) {
227                return 0;
228        }
229        /* We should put some more tests in here. */
230        /* Yeah, this is probably ERF */
231        return 1;
232}
233
234static int erf_init_input(libtrace_t *libtrace) {
235        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
236
237        if (!libtrace->format_data) {
238                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
239                        "format data inside erf_init_input()");
240                return -1;
241        }
242
243        IN_OPTIONS.real_time = 0;
244        DATA(libtrace)->drops = 0;
245
246        return 0; /* success */
247}
248
249static int erf_config_input(libtrace_t *libtrace, trace_option_t option,
250                void *value) {
251
252        switch (option) {
253                case TRACE_OPTION_EVENT_REALTIME:
254                        IN_OPTIONS.real_time = *(int *)value;
255                        return 0;
256                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
257                        trace_set_err(libtrace, TRACE_ERR_OPTION_UNAVAIL,
258                                        "Setting constant framing length is not supported for %s:", libtrace->format->name);
259                        return -1;
260                case TRACE_OPTION_SNAPLEN:
261                case TRACE_OPTION_PROMISC:
262                case TRACE_OPTION_FILTER:
263                case TRACE_OPTION_META_FREQ:
264                        trace_set_err(libtrace, TRACE_ERR_OPTION_UNAVAIL,
265                                        "Unsupported option");
266                        return -1;
267                default:
268                        /* Unknown option */
269                        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
270                                        "Unknown option");
271                        return -1;
272        }
273}
274
275static int erf_start_input(libtrace_t *libtrace) 
276{
277        if (libtrace->io)
278                return 0; /* Success -- already done. */
279
280        libtrace->io = trace_open_file(libtrace);
281
282        if (!libtrace->io)
283                return -1;
284
285        DATA(libtrace)->drops = 0;
286        return 0; /* success */
287}
288
289/* Raw ERF is a special case -- we want to force libwandio to treat the file
290 * as uncompressed so we can't just use trace_open_file() */
291static int rawerf_start_input(libtrace_t *libtrace)
292{
293        if (libtrace->io)
294                return 0; 
295
296        libtrace->io = wandio_create_uncompressed(libtrace->uridata);
297
298        if (!libtrace->io) {
299                if (errno != 0) {
300                        trace_set_err(libtrace, errno, "Unable to open raw ERF file %s", libtrace->uridata);
301                }
302                return -1;
303        }
304
305        DATA(libtrace)->drops = 0;
306
307        return 0; /* success */
308}
309
310/* Binary search through the index to find the closest point before
311 * the packet.  Consider in future having a btree index perhaps?
312 */
313static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
314{
315        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
316        size_t min_off = 0;
317        off_t current;
318        erf_index_t record;
319        do {
320                current=(max_off+min_off)>>2;
321
322                wandio_seek(DATA(libtrace)->seek.index,
323                                (int64_t)(current*sizeof(record)),
324                                SEEK_SET);
325                wandio_read(DATA(libtrace)->seek.index,
326                                &record,sizeof(record));
327                if (record.timestamp < erfts) {
328                        min_off=current;
329                }
330                if (record.timestamp > erfts) {
331                        max_off=current;
332                }
333                if (record.timestamp == erfts)
334                        break;
335        } while(min_off<max_off);
336
337        /* If we've passed it, seek backwards.  This loop shouldn't
338         * execute more than twice.
339         */
340        do {
341                wandio_seek(DATA(libtrace)->seek.index,
342                                (int64_t)(current*sizeof(record)),SEEK_SET);
343                wandio_read(DATA(libtrace)->seek.index,
344                                &record,sizeof(record));
345                current--;
346        } while(record.timestamp>erfts);
347
348        /* We've found our location in the trace, now use it. */
349        wandio_seek(libtrace->io,(int64_t) record.offset,SEEK_SET);
350
351        return 0; /* success */
352}
353
354/* There is no index.  Seek through the entire trace from the start, nice
355 * and slowly.
356 */
357static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts UNUSED)
358{
359        if (libtrace->io) {
360                wandio_destroy(libtrace->io);
361        }
362        libtrace->io = trace_open_file(libtrace);
363        if (!libtrace->io)
364                return -1;
365        return 0;
366}
367
368/* Seek within an ERF trace based on an ERF timestamp */
369static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
370{
371        libtrace_packet_t *packet;
372        off_t off = 0;
373
374        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
375                char buffer[PATH_MAX];
376                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
377                DATA(libtrace)->seek.index=wandio_create(buffer);
378                if (DATA(libtrace)->seek.index) {
379                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
380                }
381                else {
382                        DATA(libtrace)->seek.exists=INDEX_NONE;
383                }
384        }
385
386        /* If theres an index, use it to find the nearest packet that isn't
387         * after the time we're looking for.  If there is no index we need
388         * to seek slowly through the trace from the beginning.  Sigh.
389         */
390        switch(DATA(libtrace)->seek.exists) {
391                case INDEX_EXISTS:
392                        erf_fast_seek_start(libtrace,erfts);
393                        break;
394                case INDEX_NONE:
395                        erf_slow_seek_start(libtrace,erfts);
396                        break;
397                case INDEX_UNKNOWN:
398                        trace_set_err(libtrace, TRACE_ERR_SEEK_ERF, "Cannot seek to erf timestamp with unknown index in erf_seek_erf()");
399                        return -1;
400                        break;
401        }
402
403        /* Now seek forward looking for the correct timestamp */
404        packet=trace_create_packet();
405        do {
406                trace_read_packet(libtrace,packet);
407                if (trace_get_erf_timestamp(packet)==erfts)
408                        break;
409                off=wandio_tell(libtrace->io);
410        } while(trace_get_erf_timestamp(packet)<erfts);
411
412        wandio_seek(libtrace->io,off,SEEK_SET);
413
414        return 0;
415}
416
417static int erf_init_output(libtrace_out_t *libtrace) {
418        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
419
420        if (!libtrace->format_data) {
421                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED, "Unable to allocate memory for "
422                        "format data inside erf_init_output()");
423                return -1;
424        }
425
426        OUT_OPTIONS.level = 0;
427        OUT_OPTIONS.compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
428        OUT_OPTIONS.fileflag = O_CREAT | O_WRONLY;
429        OUTPUT->file = 0;
430
431        return 0;
432}
433
434static int erf_config_output(libtrace_out_t *libtrace, 
435                trace_option_output_t option, void *value) {
436
437        switch (option) {
438                case TRACE_OPTION_OUTPUT_COMPRESS:
439                        OUT_OPTIONS.level = *(int*)value;
440                        return 0;
441                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
442                        OUT_OPTIONS.compress_type = *(int*)value;
443                        return 0;
444                case TRACE_OPTION_OUTPUT_FILEFLAGS:
445                        OUT_OPTIONS.fileflag = *(int*)value;
446                        return 0;
447                default:
448                        /* Unknown option */
449                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
450                                        "Unknown option");
451                        return -1;
452        }
453}
454
455
456
457static int erf_fin_input(libtrace_t *libtrace) {
458        if (libtrace->io)
459                wandio_destroy(libtrace->io);
460        free(libtrace->format_data);
461        return 0;
462}
463
464static int erf_fin_output(libtrace_out_t *libtrace) {
465        if (OUTPUT->file)
466                wandio_wdestroy(OUTPUT->file);
467        free(libtrace->format_data);
468        return 0;
469}
470 
471static int erf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
472                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
473       
474        dag_record_t *erfptr;
475
476        if (packet->buffer != buffer && 
477                packet->buf_control == TRACE_CTRL_PACKET) {
478                free(packet->buffer);
479        }
480
481        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
482                packet->buf_control = TRACE_CTRL_PACKET;
483        } else
484                packet->buf_control = TRACE_CTRL_EXTERNAL;
485
486        packet->type = rt_type;
487        packet->buffer = buffer;
488        packet->header = buffer;
489        erfptr = (dag_record_t *)packet->buffer;
490        if (erfptr->flags.rxerror == 1) {
491                packet->payload = NULL;
492        } else {
493                packet->payload = ((char*)packet->buffer) + trace_get_framing_length(packet);
494        }
495
496        if (erfptr->rlen == 0) {
497                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "ERF packet has an invalid record "
498                        "length: zero, in erf_prepare_packet()\n");
499                return -1;
500        }
501
502        if (libtrace->format_data == NULL) {
503                /* Allocates the format_data structure */
504                if (erf_init_input(libtrace)) 
505                        return -1;
506        }
507
508        /* Check for loss */
509        if (erf_is_color_type(erfptr->type)) {
510                /* No idea how we get this yet */
511
512        } else if (erfptr->lctr) {
513                DATA(libtrace)->drops += ntohs(erfptr->lctr);
514        }
515
516        return 0;
517}
518
519static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
520        int numbytes;
521        unsigned int size;
522        void *buffer2 = packet->buffer;
523        unsigned int rlen;
524        uint32_t flags = 0;
525       
526       
527        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
528                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
529                if (!packet->buffer) {
530                        trace_set_err(libtrace, errno, 
531                                        "Cannot allocate memory");
532                        return -1;
533                }
534        }
535
536        flags |= TRACE_PREP_OWN_BUFFER; 
537       
538        if ((numbytes=wandio_read(libtrace->io,
539                                        packet->buffer,
540                                        (size_t)dag_record_size)) == -1) {
541                trace_set_err(libtrace,errno,"reading ERF file");
542                return -1;
543        }
544        /* EOF */
545        if (numbytes == 0) {
546                return 0;
547        }
548
549        if (numbytes < (int)dag_record_size) {
550                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF header");
551                return -1;
552        }
553
554        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
555        buffer2 = (char*)packet->buffer + dag_record_size;
556        size = rlen - dag_record_size;
557
558        if (size >= LIBTRACE_PACKET_BUFSIZE) {
559                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
560                                "Packet size %u larger than supported by libtrace - packet is probably corrupt", 
561                                size);
562                return -1;
563        }
564
565        /* Unknown/corrupt */
566        if ((((dag_record_t *)packet->buffer)->type & 0x7f) > ERF_TYPE_MAX) {
567                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
568                                "Corrupt or Unknown ERF type");
569                return -1;
570        }
571       
572        /* read in the rest of the packet */
573        if ((numbytes=wandio_read(libtrace->io,
574                                        buffer2,
575                                        (size_t)size)) != (int)size) {
576                if (numbytes==-1) {
577                        trace_set_err(libtrace,errno, "read(%s)", 
578                                        libtrace->uridata);
579                        return -1;
580                }
581                trace_set_err(libtrace,EIO,
582                                "Truncated packet (wanted %d, got %d)", 
583                                size, numbytes);
584                /* Failed to read the full packet?  must be EOF */
585                return -1;
586        }
587
588        if (numbytes < (int)size) {
589                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF record");
590                return -1;
591        }
592       
593        if (erf_prepare_packet(libtrace, packet, packet->buffer, 
594                                TRACE_RT_DATA_ERF, flags))
595                return -1;
596       
597        return rlen;
598}
599
600static int erf_dump_packet(libtrace_out_t *libtrace,
601                dag_record_t *erfptr, int framinglen, void *buffer,
602                int caplen) {
603        int numbytes = 0;
604
605        if (caplen + framinglen != ntohs(erfptr->rlen))
606                erfptr->rlen = htons(caplen + framinglen);
607
608        if ((numbytes = 
609                wandio_wwrite(OUTPUT->file, 
610                                erfptr,
611                                (size_t)(framinglen))) 
612                        != (int)(framinglen)) {
613                trace_set_err_out(libtrace,errno,
614                                "write(%s)",libtrace->uridata);
615                return -1;
616        }
617
618        numbytes=wandio_wwrite(OUTPUT->file, buffer, (size_t)caplen);
619        if (numbytes != caplen) {
620                trace_set_err_out(libtrace,errno,
621                                "write(%s)",libtrace->uridata);
622                return -1;
623        }
624        return numbytes + framinglen;
625}
626
627static int erf_flush_output(libtrace_out_t *libtrace) {
628        return wandio_wflush(OUTPUT->file);
629}
630
631static int erf_start_output(libtrace_out_t *libtrace)
632{
633        OUTPUT->file = trace_open_file_out(libtrace,
634                        OUT_OPTIONS.compress_type,
635                        OUT_OPTIONS.level,
636                        OUT_OPTIONS.fileflag);
637
638        if (!OUTPUT->file) {
639                return -1;
640        }
641        return 0;
642}
643
644static bool find_compatible_linktype(libtrace_out_t *libtrace,
645                                libtrace_packet_t *packet)
646{
647        /* Keep trying to simplify the packet until we can find
648         * something we can do with it */
649        do {
650                char type=libtrace_to_erf_type(trace_get_link_type(packet));
651
652                /* Success */
653                if (type != (char)-1)
654                        return true;
655
656                if (!demote_packet(packet)) {
657                        trace_set_err_out(libtrace,
658                                        TRACE_ERR_NO_CONVERSION,
659                                        "No erf type for packet (%i)",
660                                        trace_get_link_type(packet));
661                        return false;
662                }
663
664        } while(1);
665
666        return true;
667}
668               
669static int erf_write_packet(libtrace_out_t *libtrace, 
670                libtrace_packet_t *packet) 
671{
672        int numbytes = 0;
673        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
674        void *payload = packet->payload;
675
676        if (!OUTPUT->file) {
677                trace_set_err_out(libtrace, TRACE_ERR_BAD_IO, "Attempted to write ERF packets to a "
678                        "closed file, must call trace_create_output() before calling trace_write_output()");
679                return -1;
680        }
681
682        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
683                return 0;
684
685        if (!packet->header) {
686                return -1;
687        }
688       
689
690        /* If we've had an rxerror, we have no payload to write - fix
691         * rlen to be the correct length
692         */
693        /* I Think this is bogus, we should somehow figure out
694         * a way to write out the payload even if it is gibberish -- Perry */
695        if (payload == NULL) {
696                unsigned int pad = 0;
697                pad = erf_get_padding(packet);
698                dag_hdr->rlen = htons(dag_record_size + pad);
699               
700        } 
701       
702        if (packet->type == TRACE_RT_DATA_ERF) {
703                        numbytes = erf_dump_packet(libtrace,
704                                (dag_record_t *)packet->header,
705                                trace_get_framing_length(packet),
706                                payload,
707                                trace_get_capture_length(packet)
708                                );
709        } else {
710                dag_record_t erfhdr;
711                int rlen;
712                int framing;
713                /* convert format - build up a new erf header */
714                /* Timestamp */
715                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
716
717                /* Flags. Can't do this */
718                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
719                if (trace_get_direction(packet)!=TRACE_DIR_UNKNOWN)
720                        erfhdr.flags.iface = trace_get_direction(packet);
721
722                if (!find_compatible_linktype(libtrace,packet))
723                        return -1;
724
725                payload=packet->payload;
726
727                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
728
729                /* Packet length (rlen includes format overhead) */
730                if (trace_get_capture_length(packet) <= 0
731                        || trace_get_capture_length(packet) > 65536) {
732                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
733                                "Capture length is out of range in erf_write_packet()");
734                        return -1;
735                }
736                if (trace_get_framing_length(packet) > 65536) {
737                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
738                                "Framing length is to large in erf_write_packet()");
739                        return -1;
740                }
741
742                if (erfhdr.type == TYPE_ETH)
743                        framing = dag_record_size + 2;
744                else
745                        framing = dag_record_size;
746
747                rlen = trace_get_capture_length(packet) + framing;
748                if (rlen <= 0 || rlen > 65536) {
749                        trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
750                                "Capture + framing length is out of range in erf_write_packet()");
751                        return -1;
752                }
753                erfhdr.rlen = htons(rlen);
754                /* loss counter. Can't do this */
755                erfhdr.lctr = 0;
756                /* Wire length, does not include padding! */
757                erfhdr.wlen = htons(trace_get_wire_length(packet));
758
759                /* Write it out */
760                numbytes = erf_dump_packet(libtrace,
761                                &erfhdr,
762                                framing,
763                                payload,
764                                trace_get_capture_length(packet));
765        }
766        return numbytes;
767}
768
769libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
770        dag_record_t *erfptr = 0;
771        erfptr = (dag_record_t *)packet->header;
772        uint8_t type = (erfptr->type & 0x7f);
773        if (type != TYPE_LEGACY) {
774                /* The top-most bit is now used to indicate the presence of
775                 * extension headers :/ */
776                return erf_type_to_libtrace(type);
777        }
778        else {
779                /* Sigh, lets start wildly guessing */
780                if (((char*)packet->payload)[4]==0x45)
781                        return TRACE_TYPE_PPP;
782                return ~0;
783        }
784}
785
786libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
787        dag_record_t *erfptr = 0;
788        erfptr = (dag_record_t *)packet->header;
789        return erfptr->flags.iface;
790}
791
792libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
793        dag_record_t *erfptr = 0;
794        erfptr = (dag_record_t *)packet->header;
795        erfptr->flags.iface = direction;
796        return erfptr->flags.iface;
797}
798
799uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
800        dag_record_t *erfptr = 0;
801        erfptr = (dag_record_t *)packet->header;
802        return bswap_le_to_host64(erfptr->ts);
803}
804
805int erf_get_capture_length(const libtrace_packet_t *packet) {
806        dag_record_t *erfptr = 0;
807        int caplen;
808        size_t framinglen;
809        uint16_t wlen, rlen;
810
811        if (packet->payload == NULL)
812                return 0;
813
814        erfptr = (dag_record_t *)packet->header;
815        framinglen = trace_get_framing_length(packet);
816        rlen = ntohs(erfptr->rlen);
817        wlen = ntohs(erfptr->wlen);
818
819        caplen = rlen - framinglen;
820        if (wlen < caplen)
821                return wlen;
822
823        return caplen;
824}
825
826int erf_get_wire_length(const libtrace_packet_t *packet) {
827        dag_record_t *erfptr = 0;
828        erfptr = (dag_record_t *)packet->header;
829
830        if ((erfptr->type & 0x7f) == TYPE_META)
831                return 0;
832
833        return ntohs(erfptr->wlen);
834}
835
836size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
837        dag_record_t *erfptr = 0;
838        uint16_t wlen;
839
840        if (!packet) {
841                fprintf(stderr, "NULL packet passed to erf_set_capture_length()\n");
842                return ~0U;
843        }
844        erfptr = (dag_record_t *)packet->header;
845
846        if(size > trace_get_capture_length(packet) || (erfptr->type & 0x7f) == TYPE_META) {
847                /* Can't make a packet larger */
848                return trace_get_capture_length(packet);
849        }
850
851        /* Reset cached capture length - otherwise we will both return the
852         * wrong value here and subsequent get_capture_length() calls will
853         * return the wrong value. */
854        packet->capture_length = -1;
855        erfptr->rlen = htons(size + trace_get_framing_length(packet));
856        wlen = ntohs(erfptr->wlen);
857
858        if (wlen < size) {
859                return wlen;
860        }
861
862        return size;
863}
864
865static struct libtrace_eventobj_t erf_event(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
866        struct libtrace_eventobj_t event = {0,0,0.0,0};
867       
868        /* If we are being told to replay packets as fast as possible, then
869         * we just need to read and return the next packet in the trace */
870        if (IN_OPTIONS.real_time) {
871                event.size = trace_read_packet(libtrace, packet);
872                if (event.size < 1)
873                        event.type = TRACE_EVENT_TERMINATE;
874                else
875                        event.type = TRACE_EVENT_PACKET;
876                return event;
877               
878        } else {
879                /* Otherwise, use the generic event function */
880                return trace_event_trace(libtrace, packet);
881        }
882       
883}
884
885static void erf_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
886
887        if (trace->format_data) {
888                stat->dropped_valid = 1;
889                stat->dropped = DATA(trace)->drops;
890        }
891}
892
893static void erf_help(void) {
894        printf("erf format module: $Revision: 1752 $\n");
895        printf("Supported input URIs:\n");
896        printf("\terf:/path/to/file\t(uncompressed)\n");
897        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
898        printf("\terf:-\t(stdin, either compressed or not)\n");
899        printf("\terf:/path/to/socket\n");
900        printf("\n");
901        printf("\te.g.: erf:/tmp/trace\n");
902        printf("\n");
903        printf("Supported output URIs:\n");
904        printf("\terf:path/to/file\t(uncompressed)\n");
905        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
906        printf("\terf:-\t(stdout, either compressed or not)\n");
907        printf("\n");
908        printf("\te.g.: erf:/tmp/trace\n");
909        printf("\n");
910
911       
912}
913
914static struct libtrace_format_t erfformat = {
915        "erf",
916        "$Id$",
917        TRACE_FORMAT_ERF,
918        NULL,                           /* probe filename */
919        erf_probe_magic,                /* probe magic */
920        erf_init_input,                 /* init_input */       
921        erf_config_input,               /* config_input */
922        erf_start_input,                /* start_input */
923        NULL,                           /* pause_input */
924        erf_init_output,                /* init_output */
925        erf_config_output,              /* config_output */
926        erf_start_output,               /* start_output */
927        erf_fin_input,                  /* fin_input */
928        erf_fin_output,                 /* fin_output */
929        erf_read_packet,                /* read_packet */
930        erf_prepare_packet,             /* prepare_packet */
931        NULL,                           /* fin_packet */
932        erf_write_packet,               /* write_packet */
933        erf_flush_output,               /* flush_output */
934        erf_get_link_type,              /* get_link_type */
935        erf_get_direction,              /* get_direction */
936        erf_set_direction,              /* set_direction */
937        erf_get_erf_timestamp,          /* get_erf_timestamp */
938        NULL,                           /* get_timeval */
939        NULL,                           /* get_timespec */
940        NULL,                           /* get_seconds */
941        erf_seek_erf,                   /* seek_erf */
942        NULL,                           /* seek_timeval */
943        NULL,                           /* seek_seconds */
944        erf_get_capture_length,         /* get_capture_length */
945        erf_get_wire_length,            /* get_wire_length */
946        erf_get_framing_length,         /* get_framing_length */
947        erf_set_capture_length,         /* set_capture_length */
948        NULL,                           /* get_received_packets */
949        NULL,                           /* get_filtered_packets */
950        NULL,                           /* get_dropped_packets */
951        erf_get_statistics,             /* get_statistics */
952        NULL,                           /* get_fd */
953        erf_event,                      /* trace_event */
954        erf_help,                       /* help */
955        NULL,                           /* next pointer */
956        NON_PARALLEL(false)
957};
958
959static struct libtrace_format_t rawerfformat = {
960        "rawerf",
961        "$Id$",
962        TRACE_FORMAT_RAWERF,
963        NULL,                           /* probe filename */
964        NULL,           /* probe magic */
965        erf_init_input,                 /* init_input */       
966        erf_config_input,               /* config_input */
967        rawerf_start_input,             /* start_input */
968        NULL,                           /* pause_input */
969        erf_init_output,                /* init_output */
970        erf_config_output,              /* config_output */
971        erf_start_output,               /* start_output */
972        erf_fin_input,                  /* fin_input */
973        erf_fin_output,                 /* fin_output */
974        erf_read_packet,                /* read_packet */
975        erf_prepare_packet,             /* prepare_packet */
976        NULL,                           /* fin_packet */
977        erf_write_packet,               /* write_packet */
978        erf_flush_output,               /* flush_output */
979        erf_get_link_type,              /* get_link_type */
980        erf_get_direction,              /* get_direction */
981        erf_set_direction,              /* set_direction */
982        erf_get_erf_timestamp,          /* get_erf_timestamp */
983        NULL,                           /* get_timeval */
984        NULL,                           /* get_timespec */
985        NULL,                           /* get_seconds */
986        erf_seek_erf,                   /* seek_erf */
987        NULL,                           /* seek_timeval */
988        NULL,                           /* seek_seconds */
989        erf_get_capture_length,         /* get_capture_length */
990        erf_get_wire_length,            /* get_wire_length */
991        erf_get_framing_length,         /* get_framing_length */
992        erf_set_capture_length,         /* set_capture_length */
993        NULL,                           /* get_received_packets */
994        NULL,                           /* get_filtered_packets */
995        NULL,                           /* get_dropped_packets */
996        erf_get_statistics,             /* get_statistics */
997        NULL,                           /* get_fd */
998        erf_event,                      /* trace_event */
999        erf_help,                       /* help */
1000        NULL,                           /* next pointer */
1001        NON_PARALLEL(false)
1002};
1003
1004
1005
1006void erf_constructor(void) {
1007        register_format(&erfformat);
1008        register_format(&rawerfformat);
1009}
Note: See TracBrowser for help on using the repository browser.