source: lib/format_erf.c @ d439067

develop
Last change on this file since d439067 was d439067, checked in by Shane Alcock <salcock@…>, 23 months ago

Move packet cached fields into a distinct structure.

This will help tidy up the packet structure a little, as well as
simplify the cache clearing process (and maybe even speed it up
a little).

  • 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->cached.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.