Beispiel #1
0
/**
 * \brief Specifies an interface to use for sending.
 *
 * You may call this up to two (2) times with different interfaces
 * when using a tcpprep cache file or dualfile mode.  Note, both interfaces
 * must use the same DLT type
 */
int
tcpreplay_set_interface(tcpreplay_t *ctx, tcpreplay_intf intf, char *value)
{
    static int int1dlt = -1, int2dlt = -1;
    char *intname;
    char ebuf[SENDPACKET_ERRBUF_SIZE];

    assert(ctx);
    assert(value);

    if (intf == intf1) {
        if ((intname = get_interface(ctx->intlist, value)) == NULL) {
            tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", value);
            return -1;
        }

        ctx->options->intf1_name = safe_strdup(intname);

        /* open interfaces for writing */
        if ((ctx->intf1 = sendpacket_open(ctx->options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) {
            tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf1_name, ebuf);
            return -1;
        }

        int1dlt = sendpacket_get_dlt(ctx->intf1);
    } else if (intf == intf2) {
        if ((intname = get_interface(ctx->intlist, value)) == NULL) {
            tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", ctx->options->intf2_name);
            return -1;
        }

        ctx->options->intf2_name = safe_strdup(intname);

        /* open interface for writing */
        if ((ctx->intf2 = sendpacket_open(ctx->options->intf2_name, ebuf, TCPR_DIR_S2C)) == NULL) {
            tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf2_name, ebuf);
            return -1;
        }
        int2dlt = sendpacket_get_dlt(ctx->intf2);
    }

    /*
     * If both interfaces are selected, then make sure both interfaces use
     * the same DLT type
     */
    if (int1dlt != -1 && int2dlt != -1) {
        if (int1dlt != int2dlt) {
            tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", 
                ctx->options->intf1_name, pcap_datalink_val_to_name(int1dlt), 
                ctx->options->intf2_name, pcap_datalink_val_to_name(int2dlt));
            return -1;
        }
    }

    return 0;
}
Beispiel #2
0
/**
 * \brief Add a pcap file to be sent via tcpreplay
 *
 * One or more pcap files can be added.  Each file will be replayed
 * in order
 */
int
tcpreplay_add_pcapfile(tcpreplay_t *ctx, char *pcap_file)
{
    assert(ctx);
    assert(pcap_file);

    if (ctx->options->source_cnt < MAX_FILES) {
        ctx->options->sources[ctx->options->source_cnt].filename = safe_strdup(pcap_file);
        ctx->options->sources[ctx->options->source_cnt].type = source_filename;

        /*
         * prepare the cache info data struct.  This doesn't actually enable
         * file caching for this pcap (that is controlled globally via
         * tcpreplay_set_file_cache())
         */
        ctx->options->file_cache[ctx->options->source_cnt].index = ctx->options->source_cnt;
        ctx->options->file_cache[ctx->options->source_cnt].cached = false;
        ctx->options->file_cache[ctx->options->source_cnt].packet_cache = NULL;

        ctx->options->source_cnt += 1;


    } else {
        tcpreplay_seterr(ctx, "Unable to add more then %u files", MAX_FILES);
        return -1;
    }
    return 0;
}
Beispiel #3
0
/**
 * \brief sends the traffic out the interfaces
 *
 * Designed to be called in a separate thread if you need to.  Blocks until
 * the replay is complete or you call tcpreplay_abort() in another thread.
 * Pass the index of the pcap you want to replay, or -1 for all pcaps.
 *
 * In dualfile mode, we will process idx and idx+1
 */
int
tcpreplay_replay(tcpreplay_t *ctx, int idx)
{
    int rcode;

    assert(ctx);

    if (idx < 0 || idx > ctx->options->source_cnt) {
        tcpreplay_seterr(ctx, "invalid source index value: %d", idx);
        return -1;
    }

    if (ctx->options->dualfile && ((idx + 1) > ctx->options->source_cnt)) {
        tcpreplay_seterr(ctx, "invalid dualfile source index value: %d", (idx + 1));
        return -1;
    }


    if (gettimeofday(&ctx->stats.start_time, NULL) < 0) {
        tcpreplay_seterr(ctx, "gettimeofday() failed: %s",  strerror(errno));
        return -1;
    }

    ctx->running = true;

    /* main loop, when not looping forever */
    if (ctx->options->loop > 0) {
        while (ctx->options->loop--) {  /* limited loop */
            if ((rcode = tcpr_replay_index(ctx, idx)) < 0)
                return rcode;
        }
    } else {
        while (1) { /* loop forever */
            if ((rcode = tcpr_replay_index(ctx, idx)) < 0)
                return rcode;
        }
    }

    ctx->running = false;
    return 0;
}
Beispiel #4
0
/**
 * Enable verbose mode
 */
int
tcpreplay_set_verbose(tcpreplay_t *ctx, bool value)
{
    assert(ctx);
#ifdef ENABLE_VERBOSE
    ctx->options->verbose = value;
    return 0;
#else
    tcpreplay_seterr(ctx, "verbose mode not supported");
    return -1;
#endif
}
Beispiel #5
0
/**
 * \brief Set the arguments to be passed to tcpdump
 *
 * Specify the additional argument to be passed to tcpdump when enabling
 * verbose mode.  See TCPDUMP_ARGS in tcpdump.h for the default options
 */
int
tcpreplay_set_tcpdump_args(tcpreplay_t *ctx, char *value)
{
    assert(ctx);
#ifdef ENABLE_VERBOSE
    assert(value);
    ctx->options->tcpdump_args = safe_strdup(value);
    return 0;
#else
    tcpreplay_seterr(ctx, "verbose mode not supported");
    return -1;
#endif
}
Beispiel #6
0
/**
 * \brief Set the path to the tcpdump binary
 *
 * In order to support the verbose feature, tcpreplay needs to know where
 * tcpdump lives
 */
int
tcpreplay_set_tcpdump(tcpreplay_t *ctx, tcpdump_t *value)
{
    assert(ctx);
#ifdef ENABLE_VERBOSE
    assert(value);
    ctx->options->verbose = true;
    ctx->options->tcpdump = value;
    return 0;
#else
    tcpreplay_seterr(ctx, "verbose mode not supported");
    return -1;
#endif
}
Beispiel #7
0
/**
 * \brief Set the callback function for handing manual iteration
 *
 * Obviously for this to work, you need to first set speed_mode = speed_oneatatime
 * returns 0 on success, < 0 on error
 */
int
tcpreplay_set_manual_callback(tcpreplay_t *ctx, tcpreplay_manual_callback callback)
{
    assert(ctx);
    assert(callback);

    if (ctx->options->speed.mode != speed_oneatatime) {
        tcpreplay_seterr(ctx, "%s", 
                "Unable to set manual callback because speed mode is not 'speed_oneatatime'");
        return -1;
    }

    ctx->options->speed.manual_callback = callback;
    return 0;
}
Beispiel #8
0
/**
 * \brief Specify the tcpprep cache file to use for replaying with two NICs
 *
 * Note: this only works if you have a single pcap file
 * returns -1 on error
 */
int
tcpreplay_set_tcpprep_cache(tcpreplay_t *ctx, char *file)
{
    assert(ctx);
    char *tcpprep_file;

    if (ctx->options->source_cnt > 1) {
        tcpreplay_seterr(ctx, "%s", "Unable to use tcpprep cache file with a single pcap file");
        return -1;
    }

    tcpprep_file = safe_strdup(file);
    ctx->options->cache_packets = read_cache(&ctx->options->cachedata, 
        tcpprep_file, &ctx->options->comment);

    free(tcpprep_file);

    return 0;
}
Beispiel #9
0
/**
 * \brief Internal tcpreplay method to replay a given index
 *
 * This is used by tcpreplay_replay() to actually send the packets
 */
int 
tcpr_replay_index(tcpreplay_t *ctx)
{
    int rcode = 0;
    int idx;
    assert(ctx);

    /* only process a single file */
    if (! ctx->options->dualfile) {
        /* process each pcap file in order */
        for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx++) {
            /* reset cache markers for each iteration */
            ctx->cache_byte = 0;
            ctx->cache_bit = 0;
            switch(ctx->options->sources[idx].type) {
                case source_filename:
                    rcode = replay_file(ctx, idx);
                    break;
                case source_fd:
                    rcode = replay_fd(ctx, idx);
                    break;
                case source_cache:
                    rcode = replay_cache(ctx, idx);
                    break;
                default:
                    tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type);
                    rcode = -1;
            }
        }
    }

    /* dual file mode: two files, two interfaces */
    else {
        /* process each pcap file in order */
        for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx += 2) {
            if (ctx->options->sources[idx].type != ctx->options->sources[(idx+1)].type) {
                tcpreplay_seterr(ctx, "Both source indexes (%d, %d) must be of the same type", idx, (idx+1));
                return -1;
            }
            switch(ctx->options->sources[idx].type) {
                case source_filename:
                    rcode = replay_two_files(ctx, idx, (idx+1));
                    break;
                case source_fd:
                    rcode = replay_two_fds(ctx, idx, (idx+1));
                    break;
                case source_cache:
                    rcode = replay_two_caches(ctx, idx, (idx+1));
                    break;
                default:
                    tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type);
                    rcode = -1;
            }

        }

    }
    if (rcode < 0) {
        ctx->running = false;
        return -1;
    }

    return rcode;
}
Beispiel #10
0
/**
 * \brief replay two pcap files out two interfaces
 *
 * Internal to tcpreplay, does the heavy lifting for --dualfile
 */
static int
replay_two_files(tcpreplay_t *ctx, int idx1, int idx2)
{
    char *path1, *path2;
    pcap_t *pcap1  = NULL, *pcap2 = NULL;
    char ebuf[PCAP_ERRBUF_SIZE];
    int rcode = 0;

    assert(ctx);
    assert(ctx->options->sources[idx1].type = source_filename);
    assert(ctx->options->sources[idx2].type = source_filename);

    path1 = ctx->options->sources[idx1].filename;
    path2 = ctx->options->sources[idx2].filename;


    /* can't use stdin in dualfile mode */
    if ((strncmp(path1, "-", strlen(path1)) == 0) || 
        (strncmp(path2, "-", strlen(path2)) == 0)) {
        tcpreplay_seterr(ctx, "%s", "Invalid use of STDIN '-' in dual file mode");
        return -1;
    }

    /* read from first pcap file if we haven't cached things yet */
    if (!ctx->options->preload_pcap) {
        if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
            tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
            return -1;
        }
        ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
        if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
            tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
            return -1;
        }
        ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2);
    } else {
        if (!ctx->options->file_cache[idx1].cached) {
            if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
                tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                return -1;
            }
            ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
        }
        if (!ctx->options->file_cache[idx2].cached) {
            if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
                tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                return -1;
            }
            ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2);
        }
    }

    if (pcap1 != NULL) {
#ifdef HAVE_PCAP_SNAPSHOT
        if (pcap_snapshot(pcap1) < 65535) {
            tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes.  This may mean you have truncated packets.",
                    path1, pcap_snapshot(pcap1));
            rcode = -2;
        }

        if (pcap_snapshot(pcap2) < 65535) {
            tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes.  This may mean you have truncated packets.",
                    path2, pcap_snapshot(pcap2));
            rcode = -2;
        }
#endif
        if (ctx->intf1dlt == -1)
            ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);
        if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap1))) {
            tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)", 
                path1, pcap_datalink_val_to_name(pcap_datalink(pcap1)), 
                ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
            rcode = -2;
        }

        if (ctx->intf2dlt == -1)
            ctx->intf2dlt = sendpacket_get_dlt(ctx->intf2);
        if ((ctx->intf2dlt >= 0) && (ctx->intf2dlt != pcap_datalink(pcap2))) {
            tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)", 
                path2, pcap_datalink_val_to_name(pcap_datalink(pcap2)), 
                ctx->intf2->device, pcap_datalink_val_to_name(ctx->intf2dlt));
            rcode = -2;
        }

        if (ctx->intf1dlt != ctx->intf2dlt) {
            tcpreplay_seterr(ctx, "DLT mismatch for %s (%d) and %s (%d)",
                    path1, ctx->intf1dlt, path2, ctx->intf2dlt);
            return -1;
        }
    }

#ifdef ENABLE_VERBOSE
    if (ctx->options->verbose) {

        /* in cache mode, we may not have opened the file */
        if (pcap1 == NULL) {
            if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
                tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                return -1;
            }
            ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
        }
        /* init tcpdump */
        tcpdump_open(ctx->options->tcpdump, pcap1);
    }
#endif


    send_dual_packets(ctx, pcap1, idx1, pcap2, idx2);

    if (pcap1 != NULL)
        pcap_close(pcap1);

    if (pcap2 != NULL)
        pcap_close(pcap2);

#ifdef ENABLE_VERBOSE
    tcpdump_close(ctx->options->tcpdump);
#endif

    return rcode;
}
Beispiel #11
0
/**
 * \brief replay a pcap file out interface(s)
 *
 * Internal to tcpreplay.  Does the heavy lifting.
 */
static int
replay_file(tcpreplay_t *ctx, int idx)
{
    char *path;
    pcap_t *pcap = NULL;
    char ebuf[PCAP_ERRBUF_SIZE];

    assert(ctx);
    assert(ctx->options->sources[idx].type = source_filename);

    path = ctx->options->sources[idx].filename;

    /* close stdin if reading from it (needed for some OS's) */
    if (strncmp(path, "-", 1) == 0)
        close(1);

    /* read from pcap file if we haven't cached things yet */
    if (!ctx->options->preload_pcap) {
        if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
            tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
            return -1;
        }

        ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);

#ifdef HAVE_PCAP_SNAPSHOT
        if (pcap_snapshot(pcap) < 65535)
            warnx("%s was captured using a snaplen of %d bytes.  This may mean you have truncated packets.",
                    path, pcap_snapshot(pcap));
#endif

    } else {
        if (!ctx->options->file_cache[idx].cached) {
            if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
                tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                return -1;
            }
            ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
        }
    }

#if 0
/*
 * this API is broken right now.  This needs to be handled via a pipe or 
 * something else so we can pass the output up to the calling programm 
 */
#ifdef ENABLE_VERBOSE
    if (ctx->options->verbose) {
        /* in cache mode, we may not have opened the file */
        if (pcap == NULL)
            if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
               tcpreplay_seterr("Error opening pcap file: %s", ebuf);
               return -1;
            }

        ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
        /* init tcpdump */
        tcpdump_open(ctx->options->tcpdump, pcap);
    }
#endif
#endif

    if (pcap != NULL) {
        if (ctx->intf1dlt == -1)
            ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);
#if 0
        if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap)))
            warnx("%s DLT (%s) does not match that of the outbound interface: %s (%s)",
                    path, pcap_datalink_val_to_name(pcap_datalink(pcap)),
                    ctx->options->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
#endif
        if (ctx->intf1dlt != ctx->options->file_cache[idx].dlt)
            tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)",
                path, pcap_datalink_val_to_name(pcap_datalink(pcap)),
                ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
    }

    ctx->stats.active_pcap = ctx->options->sources[idx].filename;
    send_packets(ctx, pcap, idx);

    if (pcap != NULL)
        pcap_close(pcap);

#if 0
#ifdef ENABLE_VERBOSE
    tcpdump_close(ctx->options->tcpdump);
#endif
#endif
    return 0;
}
Beispiel #12
0
/**
 * \brief Does all the prep work before calling tcpreplay_replay()
 *
 * Technically this validates our config options, preloads the tcpprep
 * cache file, loads the packet cache and anything else which might
 * cause a delay for starting to send packets with tcpreplay_replay()
 */
int 
tcpreplay_prepare(tcpreplay_t *ctx)
{
    char *intname, ebuf[SENDPACKET_ERRBUF_SIZE];
    int int1dlt, int2dlt, i;

    assert(ctx);

    /*
     * First, process the validations, basically the same we do in 
     * tcpreplay_post_args() and AutoOpts
     */
    if (ctx->options->intf1_name == NULL) {
        tcpreplay_seterr(ctx, "%s", "You must specify at least one network interface");
        return -1;
    }

    if (ctx->options->source_cnt == 0) {
        tcpreplay_seterr(ctx, "%s", "You must specify at least one source pcap");
        return -1;
    }

    if (ctx->options->dualfile) {
        if (! ctx->options->source_cnt >= 2) {
            tcpreplay_seterr(ctx, "%s", "Dual file mode requires 2 or more pcap files");
            return -1;
        }

        if (ctx->options->source_cnt % 2 != 0) {
            tcpreplay_seterr(ctx, "%s", "Dual file mode requires an even number of pcap files");
            return -1;
        }
    }

    if (ctx->options->dualfile && ctx->options->cachedata != NULL) {
        tcpreplay_seterr(ctx, "%s", "Can't use dual file mode and tcpprep cache file together");
        return -1;
    }

    if ((ctx->options->dualfile || ctx->options->cachedata != NULL) && 
           ctx->options->intf2_name == NULL) {
        tcpreplay_seterr(ctx, "%s", "dual file mode and tcpprep cache files require two interfaces");
    }


#ifndef HAVE_SELECT
    if (ctx->options->accurate == accurate_select) {
        tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with select support");
        return -1;
    }
#endif
#ifndef HAVE_RDTSC
    if (ctx->options->accurate == accurate_rdtsc) {
        tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with rdtsc support");
        return -1;
    }
#else
    if (ctx->options->rdtsc_clicks > 0)
        rdtsc_calibrate(ctx->options->rdtsc_clicks);
#endif
#ifndef HAVE_IOPERM
    if (ctx->options->accurate == accurate_ioport) {
        tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with IO Port 0x80 support");
        return -1;
    }
#else
    if (ctx->options->accurate == accurate_ioport) {
        ioport_sleep_init();
    }
#endif
#ifndef HAVE_ABSOLUTE_TIME
    if (ctx->options->accurate == accurate_abs_time) {
        tcpreplay_seterr(ctx, "%s", "tcpreplay_api only supports absolute time on Apple OS X");
        return -1;
    }
#endif

    if ((intname = get_interface(ctx->intlist, ctx->options->intf1_name)) == NULL) {
        tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1));
        return -1;
    }

    /* open interfaces for writing */
    if ((ctx->intf1 = sendpacket_open(ctx->options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) {
        tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf1_name, ebuf);
        return -1;
    }

    int1dlt = sendpacket_get_dlt(ctx->intf1);

    if (ctx->options->intf2_name != NULL) {
        if ((intname = get_interface(ctx->intlist, ctx->options->intf2_name)) == NULL) {
            tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2));
            return -1;
        }

        /* open interfaces for writing */
        if ((ctx->intf2 = sendpacket_open(ctx->options->intf2_name, ebuf, TCPR_DIR_C2S)) == NULL) {
            tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf2_name, ebuf);
            return -1;
        }

        int2dlt = sendpacket_get_dlt(ctx->intf2);
        if (int2dlt != int1dlt) {
            tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", 
                ctx->options->intf1_name, pcap_datalink_val_to_name(int1dlt), 
                ctx->options->intf2_name, pcap_datalink_val_to_name(int2dlt));
            return -1;
        }
    }

    /*
     * Setup up the file cache, if required
     */
    if (ctx->options->enable_file_cache && ctx->options->file_cache == NULL) {
        /* Initialise each of the file cache structures */
        for (i = 0; i < ctx->options->source_cnt; i++) {
            ctx->options->file_cache[i].index = i;
            ctx->options->file_cache[i].cached = FALSE;
            ctx->options->file_cache[i].packet_cache = NULL;
        }
    }

    return 0;
}
Beispiel #13
0
/**
 * \brief Parses the GNU AutoOpts options for tcpreplay
 *
 * If you're using AutoOpts with tcpreplay_api, then just call this after
 * optionProcess() and it will parse all the options for you.  As always,
 * returns 0 on success, and -1 on error & -2 on warning.
 */
int
tcpreplay_post_args(tcpreplay_t *ctx, int argc)
{
    char *temp, *intname;
    char ebuf[SENDPACKET_ERRBUF_SIZE];
    int int1dlt, int2dlt;
    tcpreplay_opt_t *options;
    int warn = 0;

#ifdef USE_AUTOOPTS
    options = ctx->options;

#ifdef DEBUG
    if (HAVE_OPT(DBUG))
        debug = OPT_VALUE_DBUG;
#else
    if (HAVE_OPT(DBUG)) {
        warn ++;
        tcpreplay_setwarn(ctx, "%s", "not configured with --enable-debug.  Debugging disabled.");
    }
#endif

    options->loop = OPT_VALUE_LOOP;
    options->sleep_accel = OPT_VALUE_SLEEP_ACCEL;

    if (HAVE_OPT(LIMIT))
        options->limit_send = OPT_VALUE_LIMIT;

    if (HAVE_OPT(TOPSPEED)) {
        options->speed.mode = speed_topspeed;
        options->speed.speed = 0.0;
    } else if (HAVE_OPT(PPS)) {
        options->speed.mode = speed_packetrate;
        options->speed.speed = (float)OPT_VALUE_PPS;
        options->speed.pps_multi = OPT_VALUE_PPS_MULTI;
    } else if (HAVE_OPT(ONEATATIME)) {
        options->speed.mode = speed_oneatatime;
        options->speed.speed = 0.0;
    } else if (HAVE_OPT(MBPS)) {
        options->speed.mode = speed_mbpsrate;
        options->speed.speed = atof(OPT_ARG(MBPS));
    } else if (HAVE_OPT(MULTIPLIER)) {
        options->speed.mode = speed_multiplier;
        options->speed.speed = atof(OPT_ARG(MULTIPLIER));
    }

#ifdef ENABLE_VERBOSE
    if (HAVE_OPT(VERBOSE))
        options->verbose = 1;

    if (HAVE_OPT(DECODE))
        options->tcpdump->args = safe_strdup(OPT_ARG(DECODE));
#endif

    if (HAVE_OPT(STATS))
        options->stats = OPT_VALUE_STATS;

    /*
     * Check if the file cache should be enabled - if we're looping more than
     * once and the command line option has been spec'd
     */
    if (HAVE_OPT(ENABLE_FILE_CACHE) && (options->loop != 1)) {
        options->enable_file_cache = true;
    }

    /*
     * If we're preloading the pcap before the first run, then
     * we're forcing the file cache to be true
     */

    if (HAVE_OPT(PRELOAD_PCAP)) {
        options->preload_pcap = true;
        options->enable_file_cache = true;
    }

    /* Dual file mode */
    if (HAVE_OPT(DUALFILE)) {
        options->dualfile = true;
        if (argc < 2) {
            tcpreplay_seterr(ctx, "%s", "--dualfile mode requires at least two pcap files");
            return -1;
        }
        if (argc % 2 != 0) {
            tcpreplay_seterr(ctx, "%s", "--dualfile mode requires an even number of pcap files");
            return -1;
        }
    }


    if (HAVE_OPT(TIMER)) {
        if (strcmp(OPT_ARG(TIMER), "select") == 0) {
#ifdef HAVE_SELECT
            options->accurate = accurate_select;
#else
            tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with select support");
            return -1;
#endif
        } else if (strcmp(OPT_ARG(TIMER), "rdtsc") == 0) {
#ifdef HAVE_RDTSC
            options->accurate = accurate_rdtsc;
#else
            tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with rdtsc support");
            return -1;
#endif
        } else if (strcmp(OPT_ARG(TIMER), "ioport") == 0) {
#if defined HAVE_IOPERM && defined(__i386__)
            options->accurate = accurate_ioport;
            ioport_sleep_init();
#else
            tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with IO Port 0x80 support");
            return -1;
#endif
        } else if (strcmp(OPT_ARG(TIMER), "gtod") == 0) {
            options->accurate = accurate_gtod;
        } else if (strcmp(OPT_ARG(TIMER), "nano") == 0) {
            options->accurate = accurate_nanosleep;
        } else if (strcmp(OPT_ARG(TIMER), "abstime") == 0) {
#ifdef HAVE_ABSOLUTE_TIME
            options->accurate = accurate_abs_time;
            if  (!MPLibraryIsLoaded()) {
                tcpreplay_seterr(ctx, "%s", "The MP library did not load.\n");
                return -1;
            }
#else
            tcpreplay_seterr(ctx, "%s", "tcpreplay_api only supports absolute time on Apple OS X");
            return -1;
#endif
        } else {
            tcpreplay_seterr(ctx, "Unsupported timer mode: %s", OPT_ARG(TIMER));
            return -1;
        }
    }

#ifdef HAVE_RDTSC
    if (HAVE_OPT(RDTSC_CLICKS)) {
        rdtsc_calibrate(OPT_VALUE_RDTSC_CLICKS);
    }
#endif

    if (HAVE_OPT(PKTLEN)) {
        options->use_pkthdr_len = true;
        warn ++;
        tcpreplay_setwarn(ctx, "%s", "--pktlen may cause problems.  Use with caution.");
    }

    if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF1))) == NULL) {
        tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1));
        return -1;
    }

    options->intf1_name = safe_strdup(intname);

    /* open interfaces for writing */
    if ((ctx->intf1 = sendpacket_open(options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) {
        tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf1_name, ebuf);
        return -1;
    }

    int1dlt = sendpacket_get_dlt(ctx->intf1);

    if (HAVE_OPT(INTF2)) {
        if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF2))) == NULL) {
            tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2));
            return -1;
        }

        options->intf2_name = safe_strdup(intname);

        /* open interface for writing */
        if ((ctx->intf2 = sendpacket_open(options->intf2_name, ebuf, TCPR_DIR_S2C)) == NULL) {
            tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf2_name, ebuf);
        }

        int2dlt = sendpacket_get_dlt(ctx->intf2);
        if (int2dlt != int1dlt) {
            tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", 
                options->intf1_name, pcap_datalink_val_to_name(int1dlt), 
                options->intf2_name, pcap_datalink_val_to_name(int2dlt));
            return -1;
        }
    }

    if (HAVE_OPT(CACHEFILE)) {
        temp = safe_strdup(OPT_ARG(CACHEFILE));
        options->cache_packets = read_cache(&options->cachedata, temp,
            &options->comment);
        safe_free(temp);
    }

    /* return -2 on warnings */
    if (warn > 0)
        return -2;

    return 0;

#else
    tcpreplay_seterr(ctx, "autopts support not compiled in.  tcpreplay_post_args() not supported");
    return -1;
#endif /* USE_AUTOOPTS */

}