source: lib/format_dag24.c

develop
Last change on this file was 254c926, checked in by Jacob Van Walraven <jcv9@…>, 3 years ago

Cleanup some duplicate code, Added datatype/option_name for libtrace_meta_t structure

  • Property mode set to 100644
File size: 18.8 KB
RevLine 
[5e85c23]1/*
2 *
[ee6e802]3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
[5e85c23]4 * All rights reserved.
5 *
[ee6e802]6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
[5e85c23]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
[ee6e802]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
[5e85c23]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
[ee6e802]19 * GNU Lesser General Public License for more details.
[5e85c23]20 *
[ee6e802]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/>.
[5e85c23]23 *
24 *
25 */
26#define _GNU_SOURCE
27
28#include "config.h"
29#include "common.h"
30#include "libtrace.h"
31#include "libtrace_int.h"
32#include "format_helper.h"
33#include "format_erf.h"
34
35#include <errno.h>
36#include <fcntl.h>
37#include <stdio.h>
38#include <string.h>
39#include <stdlib.h>
[44028d4]40#include <sys/stat.h>
[5e85c23]41
42#include <sys/mman.h>
43#ifdef WIN32
44#  include <io.h>
45#  include <share.h>
46#  define PATH_MAX _MAX_PATH
47#  define snprintf sprintf_s
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
[5952ff0]56/* This format deals with DAG cards that are using drivers from the 2.4.X
57 * versions.
58 *
59 * DAG is a LIVE capture format.
60 *
61 * We do not support writing using this format, as transmit support was not
62 * added until a subsequent version of the DAG software (see format_dag25.c).
63 * Instead, you should write the packets read using this format as ERF traces.
64 */
[5e85c23]65
66static struct libtrace_format_t dag;
67
68#define DATA(x) ((struct dag_format_data_t *)x->format_data)
69#define DUCK DATA(libtrace)->duck
70#define FORMAT_DATA DATA(libtrace)
71
[5952ff0]72/* "Global" data that is stored for each DAG input trace */
[5e85c23]73struct dag_format_data_t {
[5952ff0]74
75        /* Data required for regular DUCK reporting */
[5e85c23]76        struct {
[5952ff0]77                /* Timestamp of the last DUCK report */
[5e85c23]78                uint32_t last_duck;
[5952ff0]79                /* The number of seconds between each DUCK report */
[5e85c23]80                uint32_t duck_freq;
[5952ff0]81                /* Timestamp of the last packet read from the DAG card */
[5e85c23]82                uint32_t last_pkt;
[5952ff0]83                /* Dummy trace to ensure DUCK packets are dealt with using
84                 * the DUCK format functions */
[5e85c23]85                libtrace_t *dummy_duck;
86        } duck; 
87       
[5952ff0]88        /* File descriptor for the DAG card */
[5e85c23]89        int fd;
[5952ff0]90        /* Pointer to DAG memory hole */
[5e85c23]91        void *buf;
[5952ff0]92        /* Difference between the top and bottom pointers in the DAG memory
93         * hole, i.e. the amount of available data to read */
[5e85c23]94        uint32_t diff;
[5952ff0]95        /* The amount of data read thus far from the start of the bottom
96         * pointer */
[5e85c23]97        uint32_t offset;
[5952ff0]98        /* The offset for the first unread byte in the DAG memory hole */
[5e85c23]99        uint32_t bottom;
[5952ff0]100        /* The offset for the last unread byte in the DAG memory hole */
[5e85c23]101        uint32_t top;
[5952ff0]102        /* The number of packets that have been dropped */
[50bbce8]103        uint64_t drops;
[5e85c23]104};
105
[5952ff0]106/* Determines if a given filename refers to a DAG device */
[91b72d3]107static void dag_probe_filename(const char *filename) 
108{
109        struct stat statbuf;
110        /* Can we stat the file? */
111        if (stat(filename, &statbuf) != 0) {
112                return 0;
113        }
114        /* Is it a character device? */
115        if (!S_ISCHR(statbuf.st_mode)) {
116                return 0;
117        }
118        /* Yeah, it's probably us. */
119        return 1;
120}
121
[5952ff0]122/* Initialises the DAG "global" variables */
[f0fb38f]123static void dag_init_format_data(libtrace_t *libtrace) {
124        libtrace->format_data = (struct dag_format_data_t *)
125                malloc(sizeof(struct dag_format_data_t));
126
127        DUCK.last_duck = 0;
128        DUCK.duck_freq = 0;
129        DUCK.last_pkt = 0;
130        DUCK.dummy_duck = NULL;
131        FORMAT_DATA->drops = 0;
132        FORMAT_DATA->top = 0;
133        FORMAT_DATA->bottom = 0;
134        FORMAT_DATA->buf = NULL;
135        FORMAT_DATA->fd = -1;
136        FORMAT_DATA->offset = 0;
137        FORMAT_DATA->diff = 0;
138}
139
[5952ff0]140/* Determines how much data is available for reading on the DAG card and
141 * updates the various offsets accordingly */
[5e85c23]142static int dag_available(libtrace_t *libtrace) {
143
144        if (FORMAT_DATA->diff > 0)
145                return FORMAT_DATA->diff;
146
147        FORMAT_DATA->bottom = FORMAT_DATA->top;
148        FORMAT_DATA->top = dag_offset(
149                        FORMAT_DATA->fd,
150                        &(FORMAT_DATA->bottom),
151                        DAGF_NONBLOCK);
152        FORMAT_DATA->diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
153        FORMAT_DATA->offset = 0;
154        return FORMAT_DATA->diff;
155}
156
[5952ff0]157/* Initialises a DAG input trace */
[5e85c23]158static int dag_init_input(libtrace_t *libtrace) {
159        struct stat buf;
[121b7e2]160        char *dag_dev_name = NULL;
161        char *scan = NULL;
162
163        /* Since DAG 2.5 has been changed to support a slightly different URI
164         * format, it's probably a good idea to deal with URIs specified in
165         * such a fashion even if we just end up ignoring the stream number */
166        if ((scan = strchr(libtrace->uridata,',')) == NULL) {
167                dag_dev_name = strdup(libtrace->uridata);
168        } else {
169                dag_dev_name = (char *)strndup(libtrace->uridata,
170                                (size_t)(scan - libtrace->uridata));
171        }
172
[5952ff0]173
174        /* Make sure a DAG device with the right name exists */ 
[121b7e2]175        if (stat(dag_dev_name, &buf) == -1) {
176                trace_set_err(libtrace,errno,"stat(%s)",dag_dev_name);
177                free(dag_dev_name);
[5e85c23]178                return -1;
179        }
[2725318]180
[f0fb38f]181        dag_init_format_data(libtrace);
[5e85c23]182        if (S_ISCHR(buf.st_mode)) {
183                /* DEVICE */
[121b7e2]184                if((FORMAT_DATA->fd = dag_open(dag_dev_name)) < 0) {
[5e85c23]185                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
[121b7e2]186                                        dag_dev_name);
187                        free(dag_dev_name);
[5e85c23]188                        return -1;
189                }
[5952ff0]190
191                /* Memory-map ourselves a pointer to the DAG memory hole */
[5e85c23]192                if((FORMAT_DATA->buf = (void *)dag_mmap(FORMAT_DATA->fd)) == MAP_FAILED) {
193                        trace_set_err(libtrace,errno,"Cannot mmap DAG %s",
[121b7e2]194                                        dag_dev_name);
195                        free(dag_dev_name);
[5e85c23]196                        return -1;
197                }
198        } else {
199                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
[121b7e2]200                                dag_dev_name);
201                free(dag_dev_name);
[5e85c23]202                return -1;
203        }
204
[121b7e2]205        free(dag_dev_name);
[5e85c23]206
207        return 0;
208}
209
[5952ff0]210/* Configures a DAG input trace */
[5e85c23]211static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
212                                void *data) {
213        switch(option) {
[646aca1]214                case TRACE_OPTION_META_FREQ:
[5952ff0]215                        /* We use this option to specify the frequency of
216                         * DUCK updates */
[5e85c23]217                        DUCK.duck_freq = *(int *)data;
218                        return 0;
219                case TRACE_OPTION_SNAPLEN:
220                        /* Surely we can set this?? Fall through for now*/
221                        return -1;
222                case TRACE_OPTION_PROMISC:
223                        /* DAG already operates in a promisc fashion */
224                        return -1;
225                case TRACE_OPTION_FILTER:
[5952ff0]226                        /* Cards that use the older drivers don't do
227                         * filtering */
[5e85c23]228                        return -1;
[708f9ae]229                case TRACE_OPTION_EVENT_REALTIME:
[5952ff0]230                        /* Live capture is always going to be realtime */
[708f9ae]231                        return -1;
[418c78d]232                case TRACE_OPTION_CONSTANT_ERF_FRAMING:
233                        return -1;
[5e85c23]234        }
[708f9ae]235        return -1;
[5e85c23]236}
237
[5952ff0]238/* Starts a DAG input trace */
[5e85c23]239static int dag_start_input(libtrace_t *libtrace) {     
240        if(dag_start(FORMAT_DATA->fd) < 0) {
241                trace_set_err(libtrace,errno,"Cannot start DAG %s",
242                                libtrace->uridata);
243                return -1;
244        }
245
246        /* Flush the memory hole */
247        while(dag_available(libtrace) != 0)
248                FORMAT_DATA->diff = 0;
[50bbce8]249        FORMAT_DATA->drops = 0;
[5e85c23]250        return 0;
251}
252
[5952ff0]253/* Pauses a DAG input trace */
[5e85c23]254static int dag_pause_input(libtrace_t *libtrace) {
255        dag_stop(FORMAT_DATA->fd);
256        return 0;
257}
258
[5952ff0]259/* Destroys a DAG input trace */
[5e85c23]260static int dag_fin_input(libtrace_t *libtrace) {
261        dag_close(FORMAT_DATA->fd);
262        if (DUCK.dummy_duck)
263                trace_destroy_dead(DUCK.dummy_duck);
264        free(libtrace->format_data);
265        return 0; /* success */
266}
267
[5952ff0]268/* Extracts DUCK information from the DAG card and produces a DUCK packet */
[5e85c23]269static int dag_get_duckinfo(libtrace_t *libtrace,
270                                libtrace_packet_t *packet) {
271        dag_inf lt_dag_inf;
272
[5952ff0]273        /* Allocate memory for the DUCK data */
[5e85c23]274        if (packet->buf_control == TRACE_CTRL_EXTERNAL ||
275                        !packet->buffer) {
276                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
277                packet->buf_control = TRACE_CTRL_PACKET;
278                if (!packet->buffer) {
279                        trace_set_err(libtrace, errno,
280                                        "Cannot allocate packet buffer");
281                        return -1;
282                }
283        }
284
[5952ff0]285        /* DUCK doesn't actually have a format header, as such */
[5e85c23]286        packet->header = 0;
287        packet->payload = packet->buffer;
288
[5952ff0]289        /* Check that the DAG card supports DUCK */
[5e85c23]290        if ((ioctl(FORMAT_DATA->fd, DAG_IOINF, &lt_dag_inf) < 0)) {
291                trace_set_err(libtrace, errno,
292                                "Error using DAG_IOINF");
293                return -1;
294        }
295        if (!IsDUCK(&lt_dag_inf)) {
296                printf("WARNING: %s does not have modern clock support - No DUCK information will be gathered\n", libtrace->uridata);
297                return 0;
298        }
299
[5952ff0]300        /* Get the DUCK information from the card */
[5e85c23]301        if ((ioctl(FORMAT_DATA->fd, DAG_IOGETDUCK, (duck_inf *)packet->payload)
302                                < 0)) {
303                trace_set_err(libtrace, errno, "Error using DAG_IOGETDUCK");
304                return -1;
305        }
306
[5952ff0]307        /* Set the type */
[5e85c23]308        packet->type = TRACE_RT_DUCK_2_4;
[5952ff0]309
310        /* Set the packet's trace to point at a DUCK trace, so that the
311         * DUCK format functions will be called on the packet rather than the
312         * DAG ones */
[5e85c23]313        if (!DUCK.dummy_duck)
314                DUCK.dummy_duck = trace_create_dead("duck:dummy");
315        packet->trace = DUCK.dummy_duck;
316        return sizeof(duck_inf);
317}
318
[5952ff0]319/* Reads the next ERF record from the DAG memory hole */
[5798dc6]320static dag_record_t *dag_get_record(libtrace_t *libtrace) {
[5e85c23]321        dag_record_t *erfptr = NULL;
322        uint16_t size;
323        erfptr = (dag_record_t *) ((char *)FORMAT_DATA->buf + 
324                        (FORMAT_DATA->bottom + FORMAT_DATA->offset));
325
326        if (!erfptr)
327                return NULL;
328        size = ntohs(erfptr->rlen);
[f6f3ae5]329        if (size < dag_record_size) {
[2193905]330                fprintf(stderr, "DAG2.4 rlen is invalid (rlen = %u, must be at least %u)\n",
331                        size, dag_record_size);
[f6f3ae5]332                return NULL;
333        }
[5e85c23]334        FORMAT_DATA->offset += size;
335        FORMAT_DATA->diff -= size;
336        return erfptr;
337}
338
[5952ff0]339/* Converts a buffer containing a recently read DAG packet record into a
340 * libtrace packet */
[f0fb38f]341static int dag_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
342                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
343
344        dag_record_t *erfptr;
[5952ff0]345        /* If the packet previously owned a buffer that is not the buffer
346         * that contains the new packet data, we're going to need to free the
347         * old one to avoid memory leaks */
[f0fb38f]348        if (packet->buffer != buffer &&
349                        packet->buf_control == TRACE_CTRL_PACKET) {
350                free(packet->buffer);
351        }
352
[5952ff0]353        /* Set the buffer owner appropriately */
[f0fb38f]354        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
355                packet->buf_control = TRACE_CTRL_PACKET;
356        } else 
357                packet->buf_control = TRACE_CTRL_EXTERNAL;
358       
[5952ff0]359        /* Update packet pointers and type appropriately */
[f52bcdd]360        erfptr = (dag_record_t *)buffer;
[5e85c23]361        packet->buffer = erfptr;
362        packet->header = erfptr;
[f0fb38f]363        packet->type = rt_type;
364
[5e85c23]365        if (erfptr->flags.rxerror == 1) {
[5952ff0]366                /* rxerror means the payload is corrupt - drop the payload
[5e85c23]367                 * by tweaking rlen */
368                packet->payload = NULL;
369                erfptr->rlen = htons(erf_get_framing_length(packet));
370        } else {
371                packet->payload = (char*)packet->buffer
372                        + erf_get_framing_length(packet);
373        }
374
[f0fb38f]375        if (libtrace->format_data == NULL) {
376                dag_init_format_data(libtrace);
377        }
378
[5952ff0]379        /* Update the dropped packets counter, using the value of the ERF
380         * loss counter */
[f0fb38f]381        DATA(libtrace)->drops += ntohs(erfptr->lctr);
382
383        return 0;
384
[5e85c23]385}
386
[5952ff0]387/* Reads the next available packet from a DAG card, in a BLOCKING fashion
388 *
389 * If DUCK reporting is enabled, the packet returned may be a DUCK update */
[5e85c23]390static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
391        int numbytes;
392        int size = 0;
[f0fb38f]393        uint32_t flags = 0;
394        struct timeval tv;
[5e85c23]395        dag_record_t *erfptr = NULL;
396
[5952ff0]397        /* Check if we're due for a DUCK report */
[5e85c23]398        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq &&
399                        DUCK.duck_freq != 0) {
400                size = dag_get_duckinfo(libtrace, packet);
401                DUCK.last_duck = DUCK.last_pkt;
402                if (size != 0) {
403                        return size;
404                }
405                /* No DUCK support, so don't waste our time anymore */
406                DUCK.duck_freq = 0;
407        }
408
[5952ff0]409        /* Don't let anyone try to free our DAG memory hole */
[c0dba7a]410        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
411       
[5952ff0]412        /* If the packet buffer is currently owned by libtrace, free it so
413         * that we can set the packet to point into the DAG memory hole */
414        if (packet->buf_control == TRACE_CTRL_PACKET) {
[5e85c23]415                packet->buf_control = TRACE_CTRL_EXTERNAL;
416                free(packet->buffer);
417                packet->buffer = 0;
418        }
419
[5952ff0]420        /* Grab a full ERF record */
[5e85c23]421        do {
422                numbytes = dag_available(libtrace);
423                if (numbytes < 0)
424                        return numbytes;
425                if (numbytes == 0)
426                        continue;
427                erfptr = dag_get_record(libtrace);
428        } while (erfptr == NULL);
[f0fb38f]429       
[5952ff0]430        /* Prepare the libtrace packet */
[f0fb38f]431        if (dag_prepare_packet(libtrace, packet, erfptr, TRACE_RT_DATA_ERF, 
432                                flags))
433                return -1;
[5952ff0]434       
435        /* Update the DUCK timer */
[f0fb38f]436        tv = trace_get_timeval(packet);
[5e85c23]437        DUCK.last_pkt = tv.tv_sec;
438        return packet->payload ? htons(erfptr->rlen) : erf_get_framing_length(packet);
439}
440
[5952ff0]441/* Attempts to read a packet from a DAG card in a NON-BLOCKING fashion. If
442 * a packet is available, we will return a packet event. Otherwise we will
443 * return a SLEEP event (as we cannot select on the DAG file descriptor).
444 */
[5e85c23]445static libtrace_eventobj_t trace_event_dag(libtrace_t *trace,
446                                        libtrace_packet_t *packet) {
447        libtrace_eventobj_t event = {0,0,0.0,0};
448        int data;
449
[5778738]450        do {
451                data = dag_available(trace);
452
[5952ff0]453                /* If no data is available, drop out and return a sleep event */
[5778738]454                if (data <= 0)
455                        break;
456
[5952ff0]457                /* Data is available, so we can call the blocking read because
458                 * we know that we will get a packet straight away */
[5e85c23]459                event.size = dag_read_packet(trace,packet);
460                //DATA(trace)->dag.diff -= event.size;
[5952ff0]461               
462                /* XXX trace_read_packet() normally applies the following
463                 * config options for us, but this function is called via
464                 * trace_event() so we have to do it ourselves */
465
466                /* Check that the packet matches any pre-existing filter */
[5e85c23]467                if (trace->filter) {
468                        if (trace_apply_filter(trace->filter, packet)) {
469                                event.type = TRACE_EVENT_PACKET;
470                        } else {
[5778738]471                                /* Do not sleep - try to read another packet */
[c70f59f]472                                trace->filtered_packets ++;
[5778738]473                                continue;
[5e85c23]474                        }
475                } else {
476                        event.type = TRACE_EVENT_PACKET;
477                }
[5952ff0]478
479                /* If the user has specified a snap length, apply that too */
[5e85c23]480                if (trace->snaplen > 0) {
481                        trace_set_capture_length(packet, trace->snaplen);
482                }
[c70f59f]483                trace->accepted_packets ++;
[5e85c23]484                return event;
[5778738]485        } while (1);
486
[5e85c23]487        event.type = TRACE_EVENT_SLEEP;
488        event.seconds = 0.0001;
[5778738]489        event.size = 0;
490        return event;
[5e85c23]491}
492
[5952ff0]493/* Gets the number of dropped packets */
[2b7750a]494static uint64_t dag_get_dropped_packets(libtrace_t *trace)
[50bbce8]495{
[f0fb38f]496        if (!trace->format_data)
497                return (uint64_t)-1;
[50bbce8]498        return DATA(trace)->drops;
499}
500
[5952ff0]501/* Prints some semi-useful help text about the DAG format module */
[5e85c23]502static void dag_help(void) {
[c909fad]503        printf("dag format module: $Revision: 1715 $\n");
[5e85c23]504        printf("Supported input URIs:\n");
505        printf("\tdag:/dev/dagn\n");
506        printf("\n");
507        printf("\te.g.: dag:/dev/dag0\n");
508        printf("\n");
509        printf("Supported output URIs:\n");
510        printf("\tnone\n");
511        printf("\n");
512}
513
514static struct libtrace_format_t dag = {
515        "dag",
[293999b]516        "$Id$",
[5e85c23]517        TRACE_FORMAT_ERF,
[91b72d3]518        dag_probe_filename,             /* probe filename */
519        NULL,                           /* probe magic */
[5e85c23]520        dag_init_input,                 /* init_input */
521        dag_config_input,               /* config_input */
522        dag_start_input,                /* start_input */
523        dag_pause_input,                /* pause_input */
524        NULL,                           /* init_output */
525        NULL,                           /* config_output */
526        NULL,                           /* start_output */
527        dag_fin_input,                  /* fin_input */
528        NULL,                           /* fin_output */
529        dag_read_packet,                /* read_packet */
[f0fb38f]530        dag_prepare_packet,             /* prepare_packet */
531        NULL,                           /* fin_packet */
[5e85c23]532        NULL,                           /* write_packet */
[32ee9b2]533        NULL,                           /* flush_output */
[5e85c23]534        erf_get_link_type,              /* get_link_type */
535        erf_get_direction,              /* get_direction */
536        erf_set_direction,              /* set_direction */
537        erf_get_erf_timestamp,          /* get_erf_timestamp */
538        NULL,                           /* get_timeval */
[1aa4bf7]539        NULL,                           /* get_timespec */
[5e85c23]540        NULL,                           /* get_seconds */
541        NULL,                           /* seek_erf */
542        NULL,                           /* seek_timeval */
543        NULL,                           /* seek_seconds */
[ef5ba20]544        NULL,                           /* get_meta_section */
[5e85c23]545        erf_get_capture_length,         /* get_capture_length */
546        erf_get_wire_length,            /* get_wire_length */
547        erf_get_framing_length,         /* get_framing_length */
548        erf_set_capture_length,         /* set_capture_length */
[f2fae49]549        NULL,                           /* get_received_packets */
550        NULL,                           /* get_filtered_packets */
[2b7750a]551        dag_get_dropped_packets,        /* get_dropped_packets */
[5ab626a]552        NULL,                           /* get_statistics */
[5e85c23]553        NULL,                           /* get_fd */
554        trace_event_dag,                /* trace_event */
555        dag_help,                       /* help */
[b13b939]556        NULL,                            /* next pointer */
557    NON_PARALLEL(true)
[5e85c23]558};
559
560void dag_constructor(void) {
561        register_format(&dag);
562}
Note: See TracBrowser for help on using the repository browser.