1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 *
26 * sock_test.c.  Implementing a CLI for inetboot testing.
27 */
28#pragma ident	"%Z%%M%	%I%	%E% SMI"
29
30#include <sys/types.h>
31#include "socket_impl.h"
32#include "socket_inet.h"
33#include <sys/socket.h>
34#include <sys/sysmacros.h>
35#include <netinet/in_systm.h>
36#include <sys/promif.h>
37#include <sys/salib.h>
38#include <ctype.h>
39#include <errno.h>
40#include <netinet/in.h>
41#include "tcp_inet.h"
42#include "ipv4.h"
43#include <netinet/tcp.h>
44
45static int atoi(const char *);
46static int st_accept(void);
47static int st_bind(void);
48static int st_connect(void);
49static int st_echo(void);
50static int st_getsockname(void);
51static int st_getsockopt(void);
52static int st_get_addr_and_port(in_addr_t *, unsigned short *);
53static int st_get_buf_and_cnt(char **, int *);
54static int st_listen(void);
55static int st_match_option(char *, int *, int *);
56static int st_send(void);
57static int st_sendto(void);
58static int st_recv(void);
59static int st_recvfrom(void);
60static int st_set_addr(void);
61static int st_set_netmask(void);
62static int st_set_router(void);
63static int st_setsockopt(void);
64static int st_socket(void);
65static int st_sock_close(void);
66static int st_tcp_tw_report(void);
67static int st_toggle_promiscuous(void);
68static int st_use_obp(void);
69
70/* Wrapper for socket calls. */
71static int st_local_accept(int, struct sockaddr *, socklen_t *);
72static int st_local_bind(int, const struct sockaddr *, socklen_t);
73static int st_local_connect(int,  const  struct  sockaddr  *, socklen_t);
74static int st_local_getsockname(int, struct sockaddr *, socklen_t *);
75static int st_local_getsockopt(int, int, int, void *, socklen_t *);
76static int st_local_listen(int, int);
77static int st_local_recv(int, void *, size_t, int);
78static int st_local_recvfrom(int, void *, size_t, int, struct sockaddr *,
79	socklen_t *);
80static int st_local_send(int, const void *, size_t, int);
81static int st_local_sendto(int, const void *, size_t, int,
82	const struct sockaddr *, socklen_t);
83static int st_local_setsockopt(int, int, int, const void *, socklen_t);
84static int st_local_socket(int, int, int);
85static int st_local_socket_close(int);
86
87struct sock_test_cmd_s {
88	char *st_cmd;
89	int (*st_fn)(void);
90};
91
92static struct sock_test_cmd_s st_cmds[] = {
93	{ "set_addr", st_set_addr},
94	{ "set_netmask", st_set_netmask},
95	{ "set_router", st_set_router},
96	{ "socket", st_socket },
97	{ "bind", st_bind },
98	{ "accept", st_accept },
99	{ "connect", st_connect },
100	{ "listen", st_listen },
101	{ "send", st_send },
102	{ "sendto", st_sendto },
103	{ "recv", st_recv },
104	{ "recvfrom", st_recvfrom },
105	{ "setsockopt", st_setsockopt },
106	{ "getsockopt", st_getsockopt },
107	{ "getsockname", st_getsockname },
108	{ "close", st_sock_close },
109	{ "echo", st_echo },
110	{ "toggle_promiscous", st_toggle_promiscuous},
111	{ "use_obp", st_use_obp},
112	{ "tcp_tw_report", st_tcp_tw_report},
113	{ NULL, NULL }
114};
115
116struct so_option_string_s {
117	char *so_name;
118	int so_opt;
119	int so_opt_level;
120} so_option_array[] = {
121	{ "rcvtimeo", SO_RCVTIMEO, SOL_SOCKET },
122	{ "dontroute", SO_DONTROUTE, SOL_SOCKET },
123	{ "reuseaddr", SO_REUSEADDR, SOL_SOCKET },
124	{ "rcvbuf", SO_RCVBUF, SOL_SOCKET },
125	{ "sndbuf", SO_SNDBUF, SOL_SOCKET },
126	{ NULL, 0 }
127};
128
129#define	NO_OPENED_SOCKET	-1
130
131/* Right now, we only allow one socket at one time. */
132static int g_sock_fd = NO_OPENED_SOCKET;
133static int save_g_sock_fd = NO_OPENED_SOCKET;
134
135/* Boolean to decide if OBP network routines should be used. */
136static boolean_t use_obp = B_FALSE;
137
138
139/*
140 * The following routines are wrappers for the real socket routines.  The
141 * boolean use_obp is used to decide whether the real socket routines is
142 * called or the "equivalent" OBP provided routines should be called.
143 */
144static int
145st_local_socket(int domain, int type, int protocol)
146{
147	if (!use_obp) {
148		return (socket(domain, type, protocol));
149	} else {
150		return (0);
151	}
152}
153
154static int
155st_local_socket_close(int sd)
156{
157	if (!use_obp) {
158		return (socket_close(sd));
159	} else {
160		return (0);
161	}
162}
163
164static int
165st_local_accept(int sd, struct sockaddr *addr, socklen_t *addr_len)
166{
167	if (!use_obp) {
168		return (accept(sd, addr, addr_len));
169	} else {
170		return (0);
171	}
172}
173
174static int
175st_local_bind(int sd, const struct sockaddr *name, socklen_t namelen)
176{
177	if (!use_obp) {
178		return (bind(sd, name, namelen));
179	} else {
180		return (0);
181	}
182}
183
184static int
185st_local_connect(int sd,  const struct sockaddr *addr, socklen_t addr_len)
186{
187	if (!use_obp) {
188		return (connect(sd, addr, addr_len));
189	} else {
190		return (0);
191	}
192}
193
194static int
195st_local_listen(int sd,  int backlog)
196{
197	if (!use_obp) {
198		return (listen(sd, backlog));
199	} else {
200		return (0);
201	}
202}
203
204static int
205st_local_send(int sd, const void *msg, size_t len, int flags)
206{
207	if (!use_obp) {
208		return (send(sd, msg, len, flags));
209	} else {
210		return (0);
211	}
212}
213
214static int
215st_local_sendto(int sd, const void *msg, size_t len, int flags,
216    const struct sockaddr *to, socklen_t tolen)
217{
218	if (!use_obp) {
219		return (sendto(sd, msg, len, flags, to, tolen));
220	} else {
221		return (0);
222	}
223}
224
225static int
226st_local_recv(int sd, void *buf, size_t len, int flags)
227{
228	if (!use_obp) {
229		return (recv(sd, buf, len, flags));
230	} else {
231		return (0);
232	}
233}
234
235static int
236st_local_recvfrom(int sd, void *buf, size_t len, int flags,
237    struct sockaddr *from, socklen_t *fromlen)
238{
239	if (!use_obp) {
240		return (recvfrom(sd, buf, len, flags, from, fromlen));
241	} else {
242		return (0);
243	}
244}
245
246static int
247st_local_getsockname(int sd, struct sockaddr *name, socklen_t *namelen)
248{
249	if (!use_obp) {
250		return (getsockname(sd, name, namelen));
251	} else {
252		return (0);
253	}
254}
255
256
257static int
258st_local_getsockopt(int sd, int level, int option, void *optval,
259    socklen_t *optlen)
260{
261	if (!use_obp) {
262		return (getsockopt(sd, level, option, optval, optlen));
263	} else {
264		return (0);
265	}
266}
267
268static int
269st_local_setsockopt(int sd, int level, int option, const void *optval,
270    socklen_t optlen)
271{
272	if (!use_obp) {
273		return (setsockopt(sd, level, option, optval, optlen));
274	} else {
275		return (0);
276	}
277}
278
279static int
280atoi(const char *p)
281{
282	int n;
283	int c = *p++, neg = 0;
284
285	while (isspace(c)) {
286		c = *p++;
287	}
288	if (!isdigit(c)) {
289		switch (c) {
290		case '-':
291			neg++;
292			/* FALLTHROUGH */
293		case '+':
294			c = *p++;
295		}
296	}
297	for (n = 0; isdigit(c); c = *p++) {
298		n *= 10; /* two steps to avoid unnecessary overflow */
299		n += '0' - c; /* accum neg to avoid surprises at MAX */
300	}
301	return (neg ? n : -n);
302}
303
304int
305st_interpret(char *buf)
306{
307	char *cmd;
308	int i;
309
310	if ((cmd = strtok(buf, " ")) == NULL)
311		return (-1);
312
313	for (i = 0; st_cmds[i].st_cmd != NULL; i++) {
314		if (strcmp(cmd, st_cmds[i].st_cmd) == 0) {
315			return (st_cmds[i].st_fn());
316		}
317	}
318	printf("! Unknown command: %s\n", cmd);
319	return (-1);
320}
321
322
323static int
324st_socket(void)
325{
326	char *type;
327
328	if ((type = strtok(NULL, " ")) == NULL) {
329		printf("! usage: socket type\n");
330		return (-1);
331	}
332	if (g_sock_fd != NO_OPENED_SOCKET) {
333		printf("! Cannot open more than 1 socket\n");
334		return (-1);
335	}
336
337	if (strcmp(type, "stream") == 0) {
338		if ((g_sock_fd = st_local_socket(AF_INET, SOCK_STREAM,
339		    0)) < 0) {
340			printf("! Error in opening TCP socket: %d\n", errno);
341			return (-1);
342		} else {
343			printf("@ TCP socket opened\n");
344		}
345	} else if (strcmp(type, "dgram") == 0) {
346		if ((g_sock_fd = st_local_socket(AF_INET, SOCK_DGRAM,
347		    0)) < 0) {
348			printf("! Error in opening UDP socket: %d\n", errno);
349			return (-1);
350		} else {
351			printf("@ UDP socket opened\n");
352		}
353	} else if (strcmp(type, "raw") == 0) {
354		if ((g_sock_fd = st_local_socket(AF_INET, SOCK_RAW, 0)) < 0) {
355			printf("! Error in opening RAW socket: %d\n", errno);
356			return (-1);
357		} else {
358			printf("@ RAW socket opened\n");
359		}
360	} else {
361		printf("! Unknown socket type: %s\n", type);
362		return (-1);
363	}
364
365	return (0);
366}
367
368static int
369st_set_addr(void)
370{
371	char *tmp;
372	struct in_addr addr;
373
374	tmp = strtok(NULL, " ");
375	if (tmp == NULL) {
376		printf("! No address given\n");
377		return (-1);
378	}
379	if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
380		printf("! Malformed address\n");
381		return (-1);
382	}
383
384	ipv4_setipaddr(&addr);
385	printf("@ IP address %s set\n", inet_ntoa(addr));
386
387	return (0);
388}
389
390static int
391st_set_netmask(void)
392{
393	char *tmp;
394	struct in_addr addr;
395
396	tmp = strtok(NULL, " ");
397	if (tmp == NULL) {
398		printf("! No netmask given\n");
399		return (-1);
400	}
401	if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
402		printf("! Malformed netmask\n");
403		return (-1);
404	}
405
406	ipv4_setnetmask(&addr);
407	printf("@ Netmask %s set\n", inet_ntoa(addr));
408
409	return (0);
410}
411
412static int
413st_set_router(void)
414{
415	char *tmp;
416	struct in_addr addr;
417
418	tmp = strtok(NULL, " ");
419	if (tmp == NULL) {
420		printf("! No router address given\n");
421		return (-1);
422	}
423	if ((addr.s_addr = inet_addr(tmp)) == (uint32_t)-1) {
424		printf("! Malformed router address\n");
425		return (-1);
426	}
427
428	ipv4_setdefaultrouter(&addr);
429	if (ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, &addr) < 0) {
430		printf("! Cannot add default route\n");
431	} else {
432		printf("@ Default router %s set\n", inet_ntoa(addr));
433	}
434
435	return (0);
436}
437
438static int
439st_get_addr_and_port(in_addr_t *addr, unsigned short *port)
440{
441	char *tmp;
442
443	if (g_sock_fd == NO_OPENED_SOCKET) {
444		printf("! No socket opened\n");
445		return (-1);
446	}
447
448	tmp = strtok(NULL, "/");
449	if (tmp == NULL) {
450		printf("! No address given\n");
451		return (-1);
452	}
453	if ((*addr = inet_addr(tmp)) == (uint32_t)-1) {
454		printf("! Malformed address\n");
455		return (-1);
456	}
457
458	tmp = strtok(NULL, " ");
459	if (tmp == NULL) {
460		printf("! No port given\n");
461		return (-1);
462	}
463	*port = htons(atoi(tmp));
464
465	return (0);
466}
467
468static int
469st_bind(void)
470{
471	struct sockaddr_in local_addr;
472
473	if (st_get_addr_and_port(&(local_addr.sin_addr.s_addr),
474	    &(local_addr.sin_port)) < 0) {
475		return (-1);
476	}
477
478	local_addr.sin_family = AF_INET;
479	if (st_local_bind(g_sock_fd, (struct sockaddr *)&local_addr,
480	    sizeof (local_addr)) < 0) {
481		printf("! Bind failed: %d\n", errno);
482		return (-1);
483	}
484	printf("@ Socket bound to %s/%d\n", inet_ntoa(local_addr.sin_addr),
485	    ntohs(local_addr.sin_port));
486	return (0);
487}
488
489static int
490st_listen(void)
491{
492	char *tmp;
493
494	if (g_sock_fd == NO_OPENED_SOCKET) {
495		printf("! No socket opened\n");
496		return (-1);
497	}
498	if ((tmp = strtok(NULL, " ")) == NULL) {
499		printf("! No backlog given\n");
500		return (-1);
501	}
502	if (st_local_listen(g_sock_fd, atoi(tmp)) < 0) {
503		printf("! Listen failed: %d\n", errno);
504		return (-1);
505	}
506	printf("@ Listen succeeded\n");
507	return (0);
508}
509
510static int
511st_accept(void)
512{
513	struct sockaddr_in addr;
514	socklen_t addr_len;
515	int sd;
516
517	if (g_sock_fd == NO_OPENED_SOCKET) {
518		printf("! No socket opened\n");
519		return (-1);
520	}
521	addr_len = sizeof (struct sockaddr_in);
522	if ((sd = st_local_accept(g_sock_fd, (struct sockaddr *)&addr,
523	    &addr_len)) < 0) {
524		printf("! Accept failed: %d\n", errno);
525		return (-1);
526	}
527	printf("@ Accept succeeded from %s:%d.  Socket descriptor saved\n",
528	    inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
529	save_g_sock_fd = g_sock_fd;
530	g_sock_fd = sd;
531	return (0);
532}
533
534static int
535st_connect(void)
536{
537	struct sockaddr_in peer_addr;
538
539	if (st_get_addr_and_port(&(peer_addr.sin_addr.s_addr),
540	    &(peer_addr.sin_port)) < 0) {
541		return (-1);
542	}
543
544	peer_addr.sin_family = AF_INET;
545	if (st_local_connect(g_sock_fd, (struct sockaddr *)&peer_addr,
546	    sizeof (peer_addr)) < 0) {
547		printf("! Connect failed: %d\n", errno);
548		return (-1);
549	}
550	printf("@ Socket connected to %s/%d\n", inet_ntoa(peer_addr.sin_addr),
551	    ntohs(peer_addr.sin_port));
552
553	return (0);
554}
555
556static int
557st_get_buf_and_cnt(char **buf, int *send_cnt)
558{
559	char *cnt;
560
561	if ((*buf = strtok(NULL, " ")) == NULL) {
562		printf("! No send buffer\n");
563		return (-1);
564	}
565	if ((cnt = strtok(NULL, " ")) == NULL) {
566		printf("! Missing send length\n");
567		return (-1);
568	}
569
570	if ((*send_cnt = atoi(cnt)) < 0) {
571		printf("! Invalid send count\n");
572		return (-1);
573	}
574	return (0);
575}
576
577static int
578st_send(void)
579{
580	char *buf;
581	int send_cnt;
582
583	if (g_sock_fd == NO_OPENED_SOCKET) {
584		printf("! No socket opened\n");
585		return (-1);
586	}
587
588	if (st_get_buf_and_cnt(&buf, &send_cnt) < 0)
589		return (-1);
590
591	if ((send_cnt = st_local_send(g_sock_fd, buf, send_cnt, 0)) < 0) {
592		printf("! Send failed: %d\n", errno);
593		return (-1);
594	}
595	printf("@ Send %d bytes\n", send_cnt);
596
597	return (0);
598}
599
600static int
601st_sendto(void)
602{
603	struct sockaddr_in peer_addr;
604	char *buf;
605	int send_cnt;
606
607	if (st_get_addr_and_port(&(peer_addr.sin_addr.s_addr),
608	    &(peer_addr.sin_port)) < 0) {
609		return (-1);
610	}
611	peer_addr.sin_family = AF_INET;
612
613	if (st_get_buf_and_cnt(&buf, &send_cnt) < 0)
614		return (-1);
615
616	if ((send_cnt = st_local_sendto(g_sock_fd, buf, send_cnt, 0,
617	    (struct sockaddr *)&peer_addr, sizeof (peer_addr))) < 0) {
618		printf("! Sendto failed: %d\n", errno);
619		return (-1);
620	}
621	printf("@ Send %d bytes\n", send_cnt);
622
623	return (0);
624}
625
626static int
627st_recv(void)
628{
629	char *tmp;
630	char *buf;
631	int buf_len, ret;
632
633	if (g_sock_fd == NO_OPENED_SOCKET) {
634		printf("! No socket opened\n");
635		return (-1);
636	}
637
638	if ((tmp = strtok(NULL, " ")) == NULL) {
639		printf("! No buffer len given\n");
640		return (-1);
641	}
642	buf_len = atoi(tmp);
643
644	if ((buf = bkmem_zalloc(buf_len)) == NULL) {
645		printf("! Cannot allocate buffer: %d\n", errno);
646		return (-1);
647	}
648	if ((ret = st_local_recv(g_sock_fd, buf, buf_len, 0)) <= 0) {
649		if (ret == 0) {
650			printf("@ EOF received: %d\n", errno);
651			return (0);
652		}
653		printf("! Cannot recv: %d\n", errno);
654		return (-1);
655	}
656	printf("@ Bytes received: %d\n", ret);
657	hexdump(buf, ret);
658	bkmem_free(buf, buf_len);
659	return (0);
660}
661
662static int
663st_recvfrom(void)
664{
665	char *tmp;
666	char *buf;
667	int buf_len, ret;
668	struct sockaddr_in from;
669	socklen_t fromlen;
670
671	if (g_sock_fd == NO_OPENED_SOCKET) {
672		printf("! No socket opened\n");
673		return (-1);
674	}
675
676	if ((tmp = strtok(NULL, " ")) == NULL) {
677		printf("! No buffer len given\n");
678		return (-1);
679	}
680	buf_len = atoi(tmp);
681
682	if ((buf = bkmem_zalloc(buf_len)) == NULL) {
683		printf("! Cannot allocate buffer: %d\n", errno);
684		return (-1);
685	}
686	fromlen = sizeof (from);
687	if ((ret = st_local_recvfrom(g_sock_fd, buf, buf_len, 0,
688	    (struct sockaddr *)&from, &fromlen)) <= 0) {
689		if (ret == 0) {
690			printf("@ EOF received: %d\n", errno);
691			return (0);
692		}
693		printf("! Cannot recv: %d\n", errno);
694		return (-1);
695	}
696	printf("@ Bytes received from %s/%d: %d\n",
697	    inet_ntoa(from.sin_addr), ntohs(from.sin_port), ret);
698	hexdump(buf, ret);
699	bkmem_free(buf, buf_len);
700	return (0);
701}
702
703/*
704 * To act as an echo server.  Note that it assumes the address and
705 * netmask have been set.
706 */
707static int
708st_echo(void)
709{
710	char *tmp;
711	int listen_fd, newfd;
712	int echo_port;
713	struct sockaddr_in addr;
714	socklen_t addr_size;
715	int backlog = 20;
716	char *buf;
717	int buf_len, ret, snd_cnt;
718
719	tmp = strtok(NULL, " ");
720	if (tmp == NULL) {
721		printf("! No echo port given\n");
722		return (-1);
723	}
724	echo_port = atoi(tmp);
725	tmp = strtok(NULL, " ");
726	if (tmp == NULL) {
727		printf("! No buffer size given\n");
728		return (-1);
729	}
730	buf_len = atoi(tmp);
731
732	/* Create local socket for echo server */
733	if ((listen_fd = st_local_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
734		printf("! Error in opening TCP socket: %d\n", errno);
735		return (-1);
736	} else {
737		printf("@ Local TCP socket opened\n");
738	}
739
740	/* Bind local socket */
741	addr.sin_family = AF_INET;
742	addr.sin_port = htons(echo_port);
743	addr.sin_addr.s_addr = INADDR_ANY;
744
745	if (st_local_bind(listen_fd, (struct sockaddr *)&addr,
746	    sizeof (addr)) < 0) {
747		printf("! Bind failed: %d\n", errno);
748		return (-1);
749	}
750	if (st_local_listen(listen_fd, backlog) < 0) {
751		printf("! Listen failed: %d\n", errno);
752		return (-1);
753	}
754
755	addr_size = sizeof (addr);
756	if ((newfd = st_local_accept(listen_fd, (struct sockaddr *)&addr,
757	    &addr_size)) < 0) {
758		printf("! Accept failed: %d\n", errno);
759		(void) st_local_socket_close(listen_fd);
760		return (-1);
761	}
762	printf("@ Accepted connection: %s/%d\n", inet_ntoa(addr.sin_addr),
763		ntohs(addr.sin_port));
764	(void) st_local_socket_close(listen_fd);
765
766	if ((buf = bkmem_zalloc(buf_len)) == NULL) {
767		printf("! Cannot allocate buffer: %d\n", errno);
768		(void) st_local_socket_close(newfd);
769		return (-1);
770	}
771	while ((ret = st_local_recv(newfd, buf, buf_len, 0)) > 0) {
772		printf("@ Bytes received: %d\n", ret);
773		hexdump(buf, ret);
774		if ((snd_cnt = st_local_send(newfd, buf, ret, 0)) < ret) {
775			printf("! Send failed: %d\n", errno);
776			bkmem_free(buf, buf_len);
777			return (-1);
778		}
779		printf("@ Sent %d bytes\n", snd_cnt);
780	}
781	(void) st_local_socket_close(newfd);
782	if (ret < 0) {
783		printf("! Cannot recv: %d\n", errno);
784		bkmem_free(buf, buf_len);
785		return (-1);
786	} else {
787		return (0);
788	}
789}
790
791static int
792st_match_option(char *opt_s, int *opt, int *opt_level)
793{
794	int i;
795
796	for (i = 0; so_option_array[i].so_name != NULL; i++) {
797		if (strcmp(so_option_array[i].so_name, opt_s) == 0) {
798			*opt = so_option_array[i].so_opt;
799			*opt_level = so_option_array[i].so_opt_level;
800			return (0);
801		}
802	}
803	printf("! Unknown option\n");
804	return (-1);
805}
806
807static int
808st_setsockopt(void)
809{
810	char *tmp;
811	int opt, opt_level, opt_val;
812
813	if (g_sock_fd == NO_OPENED_SOCKET) {
814		printf("! No socket opened\n");
815		return (-1);
816	}
817
818	if ((tmp = strtok(NULL, " ")) == NULL) {
819		printf("! No option given\n");
820		return (-1);
821	}
822	if (st_match_option(tmp, &opt, &opt_level) < 0) {
823		return (-1);
824	}
825
826	/* We only support integer option for the moment. */
827	if ((tmp = strtok(NULL, " ")) == NULL) {
828		printf("! No option value given\n");
829		return (-1);
830	}
831	opt_val = atoi(tmp);
832
833	if (st_local_setsockopt(g_sock_fd, opt_level, opt, &opt_val,
834	    sizeof (int)) < 0) {
835		printf("! Cannot set option: %d\n", errno);
836		return (-1);
837	}
838	printf("@ Option set successfully\n");
839	return (0);
840}
841
842static int
843st_getsockname(void)
844{
845	struct sockaddr_in addr;
846	socklen_t len;
847
848	if (g_sock_fd == NO_OPENED_SOCKET) {
849		printf("! No socket opened\n");
850		return (-1);
851	}
852
853	len = sizeof (addr);
854	if (st_local_getsockname(g_sock_fd, (struct sockaddr *)&addr,
855	    &len) < 0) {
856		printf("! getsockname failed: %d\n", errno);
857		return (-1);
858	}
859	printf("@ Local socket name: %s/%d\n", inet_ntoa(addr.sin_addr),
860	    ntohs(addr.sin_port));
861	return (0);
862}
863
864static int
865st_getsockopt(void)
866{
867	char *tmp;
868	int opt, opt_level, opt_val;
869	socklen_t opt_len;
870
871	if (g_sock_fd == NO_OPENED_SOCKET) {
872		printf("! No socket opened\n");
873		return (-1);
874	}
875
876	if ((tmp = strtok(NULL, " ")) == NULL) {
877		printf("! No option given\n");
878		return (-1);
879	}
880	if (st_match_option(tmp, &opt, &opt_level) < 0) {
881		return (-1);
882	}
883
884	opt_len = sizeof (opt_val);
885	if (st_local_getsockopt(g_sock_fd, opt_level, opt, &opt_val,
886	    &opt_len) < 0) {
887		printf("! Cannot get option: %d\n", errno);
888		return (-1);
889	}
890	printf("@ Option value is %d\n", opt_val);
891	return (-1);
892}
893
894static int
895st_sock_close(void)
896{
897	if (g_sock_fd == NO_OPENED_SOCKET) {
898		printf("! No socket opened\n");
899		return (-1);
900	}
901	if (st_local_socket_close(g_sock_fd) < 0) {
902		printf("! Error in closing socket: %d\n", errno);
903		return (-1);
904	}
905	printf("@ Socket closed");
906	if (save_g_sock_fd != NO_OPENED_SOCKET) {
907		g_sock_fd = save_g_sock_fd;
908		save_g_sock_fd = NO_OPENED_SOCKET;
909		printf(", switching to saved socket descriptor\n");
910	} else {
911		g_sock_fd = NO_OPENED_SOCKET;
912		printf("\n");
913	}
914	return (0);
915}
916
917static int
918st_toggle_promiscuous(void)
919{
920	/* We always start with non-promiscuous mode. */
921	static boolean_t promiscuous = B_FALSE;
922
923	promiscuous = !promiscuous;
924	(void) ipv4_setpromiscuous(promiscuous);
925	printf("@ Setting promiscuous to %d\n", promiscuous);
926	return (0);
927}
928
929static int
930st_use_obp(void)
931{
932	if ((use_obp = !use_obp) == B_TRUE) {
933		printf("@ Now using OBP routines\n");
934	} else {
935		printf("@ Now using socket routines\n");
936	}
937	return (0);
938}
939
940static int
941st_tcp_tw_report(void)
942{
943	printf("@ TCP Time Wait report\n");
944	tcp_time_wait_report();
945	return (0);
946}
947