source: lib/format_erf.c @ 2193905

develop
Last change on this file since 2193905 was 2193905, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Apply changes required for pull request #81

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