source: lib/format_erf.c @ 9a6bdbc

develop
Last change on this file since 9a6bdbc was 9a6bdbc, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Added can_write functions to each output format, Fixed pcapng_get_header_type incorrectly flipping type bytes

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