root/usr/src/stand/lib/sock/sock_test.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * sock_test.c.  Implementing a CLI for inetboot testing.
 */
#pragma ident   "%Z%%M% %I%     %E% SMI"

#include <sys/types.h>
#include "socket_impl.h"
#include "socket_inet.h"
#include <sys/socket.h>
#include <sys/sysmacros.h>
#include <netinet/in_systm.h>
#include <sys/promif.h>
#include <sys/salib.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include "tcp_inet.h"
#include "ipv4.h"
#include <netinet/tcp.h>

static int atoi(const char *);
static int st_accept(void);
static int st_bind(void);
static int st_connect(void);
static int st_echo(void);
static int st_getsockname(void);
static int st_getsockopt(void);
static int st_get_addr_and_port(in_addr_t *, unsigned short *);
static int st_get_buf_and_cnt(char **, int *);
static int st_listen(void);
static int st_match_option(char *, int *, int *);
static int st_send(void);
static int st_sendto(void);
static int st_recv(void);
static int st_recvfrom(void);
static int st_set_addr(void);
static int st_set_netmask(void);
static int st_set_router(void);
static int st_setsockopt(void);
static int st_socket(void);
static int st_sock_close(void);
static int st_tcp_tw_report(void);
static int st_toggle_promiscuous(void);
static int st_use_obp(void);

/* Wrapper for socket calls. */
static int st_local_accept(int, struct sockaddr *, socklen_t *);
static int st_local_bind(int, const struct sockaddr *, socklen_t);
static int st_local_connect(int,  const  struct  sockaddr  *, socklen_t);
static int st_local_getsockname(int, struct sockaddr *, socklen_t *);
static int st_local_getsockopt(int, int, int, void *, socklen_t *);
static int st_local_listen(int, int);
static int st_local_recv(int, void *, size_t, int);
static int st_local_recvfrom(int, void *, size_t, int, struct sockaddr *,
        socklen_t *);
static int st_local_send(int, const void *, size_t, int);
static int st_local_sendto(int, const void *, size_t, int,
        const struct sockaddr *, socklen_t);
static int st_local_setsockopt(int, int, int, const void *, socklen_t);
static int st_local_socket(int, int, int);
static int st_local_socket_close(int);

struct sock_test_cmd_s {
        char *st_cmd;
        int (*st_fn)(void);
};

static struct sock_test_cmd_s st_cmds[] = {
        { "set_addr", st_set_addr},
        { "set_netmask", st_set_netmask},
        { "set_router", st_set_router},
        { "socket", st_socket },
        { "bind", st_bind },
        { "accept", st_accept },
        { "connect", st_connect },
        { "listen", st_listen },
        { "send", st_send },
        { "sendto", st_sendto },
        { "recv", st_recv },
        { "recvfrom", st_recvfrom },
        { "setsockopt", st_setsockopt },
        { "getsockopt", st_getsockopt },
        { "getsockname", st_getsockname },
        { "close", st_sock_close },
        { "echo", st_echo },
        { "toggle_promiscous", st_toggle_promiscuous},
        { "use_obp", st_use_obp},
        { "tcp_tw_report", st_tcp_tw_report},
        { NULL, NULL }
};

struct so_option_string_s {
        char *so_name;
        int so_opt;
        int so_opt_level;
} so_option_array[] = {
        { "rcvtimeo", SO_RCVTIMEO, SOL_SOCKET },
        { "dontroute", SO_DONTROUTE, SOL_SOCKET },
        { "reuseaddr", SO_REUSEADDR, SOL_SOCKET },
        { "rcvbuf", SO_RCVBUF, SOL_SOCKET },
        { "sndbuf", SO_SNDBUF, SOL_SOCKET },
        { NULL, 0 }
};

#define NO_OPENED_SOCKET        -1

/* Right now, we only allow one socket at one time. */
static int g_sock_fd = NO_OPENED_SOCKET;
static int save_g_sock_fd = NO_OPENED_SOCKET;

/* Boolean to decide if OBP network routines should be used. */
static boolean_t use_obp = B_FALSE;


/*
 * The following routines are wrappers for the real socket routines.  The
 * boolean use_obp is used to decide whether the real socket routines is
 * called or the "equivalent" OBP provided routines should be called.
 */
static int
st_local_socket(int domain, int type, int protocol)
{
        if (!use_obp) {
                return (socket(domain, type, protocol));
        } else {
                return (0);
        }
}

static int
st_local_socket_close(int sd)
{
        if (!use_obp) {
                return (socket_close(sd));
        } else {
                return (0);
        }
}

static int
st_local_accept(int sd, struct sockaddr *addr, socklen_t *addr_len)
{
        if (!use_obp) {
                return (accept(sd, addr, addr_len));
        } else {
                return (0);
        }
}

static int
st_local_bind(int sd, const struct sockaddr *name, socklen_t namelen)
{
        if (!use_obp) {
                return (bind(sd, name, namelen));
        } else {
                return (0);
        }
}

static int
st_local_connect(int sd,  const struct sockaddr *addr, socklen_t addr_len)
{
        if (!use_obp) {
                return (connect(sd, addr, addr_len));
        } else {
                return (0);
        }
}

static int
st_local_listen(int sd,  int backlog)
{
        if (!use_obp) {
                return (listen(sd, backlog));
        } else {
                return (0);
        }
}

static int
st_local_send(int sd, const void *msg, size_t len, int flags)
{
        if (!use_obp) {
                return (send(sd, msg, len, flags));
        } else {
                return (0);
        }
}

static int
st_local_sendto(int sd, const void *msg, size_t len, int flags,
    const struct sockaddr *to, socklen_t tolen)
{
        if (!use_obp) {
                return (sendto(sd, msg, len, flags, to, tolen));
        } else {
                return (0);
        }
}

static int
st_local_recv(int sd, void *buf, size_t len, int flags)
{
        if (!use_obp) {
                return (recv(sd, buf, len, flags));
        } else {
                return (0);
        }
}

static int
st_local_recvfrom(int sd, void *buf, size_t len, int flags,
    struct sockaddr *from, socklen_t *fromlen)
{
        if (!use_obp) {
                return (recvfrom(sd, buf, len, flags, from, fromlen));
        } else {
                return (0);
        }
}

static int
st_local_getsockname(int sd, struct sockaddr *name, socklen_t *namelen)
{
        if (!use_obp) {
                return (getsockname(sd, name, namelen));
        } else {
                return (0);
        }
}


static int
st_local_getsockopt(int sd, int level, int option, void *optval,
    socklen_t *optlen)
{
        if (!use_obp) {
                return (getsockopt(sd, level, option, optval, optlen));
        } else {
                return (0);
        }
}

static int
st_local_setsockopt(int sd, int level, int option, const void *optval,
    socklen_t optlen)
{
        if (!use_obp) {
                return (setsockopt(sd, level, option, optval, optlen));
        } else {
                return (0);
        }
}

static int
atoi(const char *p)
{
        int n;
        int c = *p++, neg = 0;

        while (isspace(c)) {
                c = *p++;
        }
        if (!isdigit(c)) {
                switch (c) {
                case '-':
                        neg++;
                        /* FALLTHROUGH */
                case '+':
                        c = *p++;
                }
        }
        for (n = 0; isdigit(c); c = *p++) {
                n *= 10; /* two steps to avoid unnecessary overflow */
                n += '0' - c; /* accum neg to avoid surprises at MAX */
        }
        return (neg ? n : -n);
}

int
st_interpret(char *buf)
{
        char *cmd;
        int i;

        if ((cmd = strtok(buf, " ")) == NULL)
                return (-1);

        for (i = 0; st_cmds[i].st_cmd != NULL; i++) {
                if (strcmp(cmd, st_cmds[i].st_cmd) == 0) {
                        return (st_cmds[i].st_fn());
                }
        }
        printf("! Unknown command: %s\n", cmd);
        return (-1);
}


static int
st_socket(void)
{
        char *type;

        if ((type = strtok(NULL, " ")) == NULL) {
                printf("! usage: socket type\n");
                return (-1);
        }
        if (g_sock_fd != NO_OPENED_SOCKET) {
                printf("! Cannot open more than 1 socket\n");
                return (-1);
        }

        if (strcmp(type, "stream") == 0) {
                if ((g_sock_fd = st_local_socket(AF_INET, SOCK_STREAM,
                    0)) < 0) {
                        printf("! Error in opening TCP socket: %d\n", errno);
                        return (-1);
                } else {
                        printf("@ TCP socket opened\n");
                }
        } else if (strcmp(type, "dgram") == 0) {
                if ((g_sock_fd = st_local_socket(AF_INET, SOCK_DGRAM,
                    0)) < 0) {
                        printf("! Error in opening UDP socket: %d\n", errno);
                        return (-1);
                } else {
                        printf("@ UDP socket opened\n");
                }
        } else if (strcmp(type, "raw") == 0) {
                if ((g_sock_fd = st_local_socket(AF_INET, SOCK_RAW, 0)) < 0) {
                        printf("! Error in opening RAW socket: %d\n", errno);
                        return (-1);
                } else {
                        printf("@ RAW socket opened\n");
                }
        } else {
                printf("! Unknown socket type: %s\n", type);
                return (-1);
        }

        return (0);
}

static int
st_set_addr(void)
{
        char *tmp;
        struct in_addr addr;

        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No address given\n");
                return (-1);
        }
        if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
                printf("! Malformed address\n");
                return (-1);
        }

        ipv4_setipaddr(&addr);
        printf("@ IP address %s set\n", inet_ntoa(addr));

        return (0);
}

static int
st_set_netmask(void)
{
        char *tmp;
        struct in_addr addr;

        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No netmask given\n");
                return (-1);
        }
        if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
                printf("! Malformed netmask\n");
                return (-1);
        }

        ipv4_setnetmask(&addr);
        printf("@ Netmask %s set\n", inet_ntoa(addr));

        return (0);
}

static int
st_set_router(void)
{
        char *tmp;
        struct in_addr addr;

        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No router address given\n");
                return (-1);
        }
        if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
                printf("! Malformed router address\n");
                return (-1);
        }

        ipv4_setdefaultrouter(&addr);
        if (ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, &addr) < 0) {
                printf("! Cannot add default route\n");
        } else {
                printf("@ Default router %s set\n", inet_ntoa(addr));
        }

        return (0);
}

static int
st_get_addr_and_port(in_addr_t *addr, unsigned short *port)
{
        char *tmp;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        tmp = strtok(NULL, "/");
        if (tmp == NULL) {
                printf("! No address given\n");
                return (-1);
        }
        if ((*addr = inet_addr(tmp)) == (uint32_t)-1) {
                printf("! Malformed address\n");
                return (-1);
        }

        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No port given\n");
                return (-1);
        }
        *port = htons(atoi(tmp));

        return (0);
}

static int
st_bind(void)
{
        struct sockaddr_in local_addr;

        if (st_get_addr_and_port(&(local_addr.sin_addr.s_addr),
            &(local_addr.sin_port)) < 0) {
                return (-1);
        }

        local_addr.sin_family = AF_INET;
        if (st_local_bind(g_sock_fd, (struct sockaddr *)&local_addr,
            sizeof (local_addr)) < 0) {
                printf("! Bind failed: %d\n", errno);
                return (-1);
        }
        printf("@ Socket bound to %s/%d\n", inet_ntoa(local_addr.sin_addr),
            ntohs(local_addr.sin_port));
        return (0);
}

static int
st_listen(void)
{
        char *tmp;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }
        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No backlog given\n");
                return (-1);
        }
        if (st_local_listen(g_sock_fd, atoi(tmp)) < 0) {
                printf("! Listen failed: %d\n", errno);
                return (-1);
        }
        printf("@ Listen succeeded\n");
        return (0);
}

static int
st_accept(void)
{
        struct sockaddr_in addr;
        socklen_t addr_len;
        int sd;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }
        addr_len = sizeof (struct sockaddr_in);
        if ((sd = st_local_accept(g_sock_fd, (struct sockaddr *)&addr,
            &addr_len)) < 0) {
                printf("! Accept failed: %d\n", errno);
                return (-1);
        }
        printf("@ Accept succeeded from %s:%d.  Socket descriptor saved\n",
            inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        save_g_sock_fd = g_sock_fd;
        g_sock_fd = sd;
        return (0);
}

static int
st_connect(void)
{
        struct sockaddr_in peer_addr;

        if (st_get_addr_and_port(&(peer_addr.sin_addr.s_addr),
            &(peer_addr.sin_port)) < 0) {
                return (-1);
        }

        peer_addr.sin_family = AF_INET;
        if (st_local_connect(g_sock_fd, (struct sockaddr *)&peer_addr,
            sizeof (peer_addr)) < 0) {
                printf("! Connect failed: %d\n", errno);
                return (-1);
        }
        printf("@ Socket connected to %s/%d\n", inet_ntoa(peer_addr.sin_addr),
            ntohs(peer_addr.sin_port));

        return (0);
}

static int
st_get_buf_and_cnt(char **buf, int *send_cnt)
{
        char *cnt;

        if ((*buf = strtok(NULL, " ")) == NULL) {
                printf("! No send buffer\n");
                return (-1);
        }
        if ((cnt = strtok(NULL, " ")) == NULL) {
                printf("! Missing send length\n");
                return (-1);
        }

        if ((*send_cnt = atoi(cnt)) < 0) {
                printf("! Invalid send count\n");
                return (-1);
        }
        return (0);
}

static int
st_send(void)
{
        char *buf;
        int send_cnt;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        if (st_get_buf_and_cnt(&buf, &send_cnt) < 0)
                return (-1);

        if ((send_cnt = st_local_send(g_sock_fd, buf, send_cnt, 0)) < 0) {
                printf("! Send failed: %d\n", errno);
                return (-1);
        }
        printf("@ Send %d bytes\n", send_cnt);

        return (0);
}

static int
st_sendto(void)
{
        struct sockaddr_in peer_addr;
        char *buf;
        int send_cnt;

        if (st_get_addr_and_port(&(peer_addr.sin_addr.s_addr),
            &(peer_addr.sin_port)) < 0) {
                return (-1);
        }
        peer_addr.sin_family = AF_INET;

        if (st_get_buf_and_cnt(&buf, &send_cnt) < 0)
                return (-1);

        if ((send_cnt = st_local_sendto(g_sock_fd, buf, send_cnt, 0,
            (struct sockaddr *)&peer_addr, sizeof (peer_addr))) < 0) {
                printf("! Sendto failed: %d\n", errno);
                return (-1);
        }
        printf("@ Send %d bytes\n", send_cnt);

        return (0);
}

static int
st_recv(void)
{
        char *tmp;
        char *buf;
        int buf_len, ret;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No buffer len given\n");
                return (-1);
        }
        buf_len = atoi(tmp);

        if ((buf = bkmem_zalloc(buf_len)) == NULL) {
                printf("! Cannot allocate buffer: %d\n", errno);
                return (-1);
        }
        if ((ret = st_local_recv(g_sock_fd, buf, buf_len, 0)) <= 0) {
                if (ret == 0) {
                        printf("@ EOF received: %d\n", errno);
                        return (0);
                }
                printf("! Cannot recv: %d\n", errno);
                return (-1);
        }
        printf("@ Bytes received: %d\n", ret);
        hexdump(buf, ret);
        bkmem_free(buf, buf_len);
        return (0);
}

static int
st_recvfrom(void)
{
        char *tmp;
        char *buf;
        int buf_len, ret;
        struct sockaddr_in from;
        socklen_t fromlen;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No buffer len given\n");
                return (-1);
        }
        buf_len = atoi(tmp);

        if ((buf = bkmem_zalloc(buf_len)) == NULL) {
                printf("! Cannot allocate buffer: %d\n", errno);
                return (-1);
        }
        fromlen = sizeof (from);
        if ((ret = st_local_recvfrom(g_sock_fd, buf, buf_len, 0,
            (struct sockaddr *)&from, &fromlen)) <= 0) {
                if (ret == 0) {
                        printf("@ EOF received: %d\n", errno);
                        return (0);
                }
                printf("! Cannot recv: %d\n", errno);
                return (-1);
        }
        printf("@ Bytes received from %s/%d: %d\n",
            inet_ntoa(from.sin_addr), ntohs(from.sin_port), ret);
        hexdump(buf, ret);
        bkmem_free(buf, buf_len);
        return (0);
}

/*
 * To act as an echo server.  Note that it assumes the address and
 * netmask have been set.
 */
static int
st_echo(void)
{
        char *tmp;
        int listen_fd, newfd;
        int echo_port;
        struct sockaddr_in addr;
        socklen_t addr_size;
        int backlog = 20;
        char *buf;
        int buf_len, ret, snd_cnt;

        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No echo port given\n");
                return (-1);
        }
        echo_port = atoi(tmp);
        tmp = strtok(NULL, " ");
        if (tmp == NULL) {
                printf("! No buffer size given\n");
                return (-1);
        }
        buf_len = atoi(tmp);

        /* Create local socket for echo server */
        if ((listen_fd = st_local_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                printf("! Error in opening TCP socket: %d\n", errno);
                return (-1);
        } else {
                printf("@ Local TCP socket opened\n");
        }

        /* Bind local socket */
        addr.sin_family = AF_INET;
        addr.sin_port = htons(echo_port);
        addr.sin_addr.s_addr = INADDR_ANY;

        if (st_local_bind(listen_fd, (struct sockaddr *)&addr,
            sizeof (addr)) < 0) {
                printf("! Bind failed: %d\n", errno);
                return (-1);
        }
        if (st_local_listen(listen_fd, backlog) < 0) {
                printf("! Listen failed: %d\n", errno);
                return (-1);
        }

        addr_size = sizeof (addr);
        if ((newfd = st_local_accept(listen_fd, (struct sockaddr *)&addr,
            &addr_size)) < 0) {
                printf("! Accept failed: %d\n", errno);
                (void) st_local_socket_close(listen_fd);
                return (-1);
        }
        printf("@ Accepted connection: %s/%d\n", inet_ntoa(addr.sin_addr),
                ntohs(addr.sin_port));
        (void) st_local_socket_close(listen_fd);

        if ((buf = bkmem_zalloc(buf_len)) == NULL) {
                printf("! Cannot allocate buffer: %d\n", errno);
                (void) st_local_socket_close(newfd);
                return (-1);
        }
        while ((ret = st_local_recv(newfd, buf, buf_len, 0)) > 0) {
                printf("@ Bytes received: %d\n", ret);
                hexdump(buf, ret);
                if ((snd_cnt = st_local_send(newfd, buf, ret, 0)) < ret) {
                        printf("! Send failed: %d\n", errno);
                        bkmem_free(buf, buf_len);
                        return (-1);
                }
                printf("@ Sent %d bytes\n", snd_cnt);
        }
        (void) st_local_socket_close(newfd);
        if (ret < 0) {
                printf("! Cannot recv: %d\n", errno);
                bkmem_free(buf, buf_len);
                return (-1);
        } else {
                return (0);
        }
}

static int
st_match_option(char *opt_s, int *opt, int *opt_level)
{
        int i;

        for (i = 0; so_option_array[i].so_name != NULL; i++) {
                if (strcmp(so_option_array[i].so_name, opt_s) == 0) {
                        *opt = so_option_array[i].so_opt;
                        *opt_level = so_option_array[i].so_opt_level;
                        return (0);
                }
        }
        printf("! Unknown option\n");
        return (-1);
}

static int
st_setsockopt(void)
{
        char *tmp;
        int opt, opt_level, opt_val;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No option given\n");
                return (-1);
        }
        if (st_match_option(tmp, &opt, &opt_level) < 0) {
                return (-1);
        }

        /* We only support integer option for the moment. */
        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No option value given\n");
                return (-1);
        }
        opt_val = atoi(tmp);

        if (st_local_setsockopt(g_sock_fd, opt_level, opt, &opt_val,
            sizeof (int)) < 0) {
                printf("! Cannot set option: %d\n", errno);
                return (-1);
        }
        printf("@ Option set successfully\n");
        return (0);
}

static int
st_getsockname(void)
{
        struct sockaddr_in addr;
        socklen_t len;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        len = sizeof (addr);
        if (st_local_getsockname(g_sock_fd, (struct sockaddr *)&addr,
            &len) < 0) {
                printf("! getsockname failed: %d\n", errno);
                return (-1);
        }
        printf("@ Local socket name: %s/%d\n", inet_ntoa(addr.sin_addr),
            ntohs(addr.sin_port));
        return (0);
}

static int
st_getsockopt(void)
{
        char *tmp;
        int opt, opt_level, opt_val;
        socklen_t opt_len;

        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }

        if ((tmp = strtok(NULL, " ")) == NULL) {
                printf("! No option given\n");
                return (-1);
        }
        if (st_match_option(tmp, &opt, &opt_level) < 0) {
                return (-1);
        }

        opt_len = sizeof (opt_val);
        if (st_local_getsockopt(g_sock_fd, opt_level, opt, &opt_val,
            &opt_len) < 0) {
                printf("! Cannot get option: %d\n", errno);
                return (-1);
        }
        printf("@ Option value is %d\n", opt_val);
        return (-1);
}

static int
st_sock_close(void)
{
        if (g_sock_fd == NO_OPENED_SOCKET) {
                printf("! No socket opened\n");
                return (-1);
        }
        if (st_local_socket_close(g_sock_fd) < 0) {
                printf("! Error in closing socket: %d\n", errno);
                return (-1);
        }
        printf("@ Socket closed");
        if (save_g_sock_fd != NO_OPENED_SOCKET) {
                g_sock_fd = save_g_sock_fd;
                save_g_sock_fd = NO_OPENED_SOCKET;
                printf(", switching to saved socket descriptor\n");
        } else {
                g_sock_fd = NO_OPENED_SOCKET;
                printf("\n");
        }
        return (0);
}

static int
st_toggle_promiscuous(void)
{
        /* We always start with non-promiscuous mode. */
        static boolean_t promiscuous = B_FALSE;

        promiscuous = !promiscuous;
        (void) ipv4_setpromiscuous(promiscuous);
        printf("@ Setting promiscuous to %d\n", promiscuous);
        return (0);
}

static int
st_use_obp(void)
{
        if ((use_obp = !use_obp) == B_TRUE) {
                printf("@ Now using OBP routines\n");
        } else {
                printf("@ Now using socket routines\n");
        }
        return (0);
}

static int
st_tcp_tw_report(void)
{
        printf("@ TCP Time Wait report\n");
        tcp_time_wait_report();
        return (0);
}