xref: /illumos-gate/usr/src/stand/lib/sock/sock_test.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
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 
45 static int atoi(const char *);
46 static int st_accept(void);
47 static int st_bind(void);
48 static int st_connect(void);
49 static int st_echo(void);
50 static int st_getsockname(void);
51 static int st_getsockopt(void);
52 static int st_get_addr_and_port(in_addr_t *, unsigned short *);
53 static int st_get_buf_and_cnt(char **, int *);
54 static int st_listen(void);
55 static int st_match_option(char *, int *, int *);
56 static int st_send(void);
57 static int st_sendto(void);
58 static int st_recv(void);
59 static int st_recvfrom(void);
60 static int st_set_addr(void);
61 static int st_set_netmask(void);
62 static int st_set_router(void);
63 static int st_setsockopt(void);
64 static int st_socket(void);
65 static int st_sock_close(void);
66 static int st_tcp_tw_report(void);
67 static int st_toggle_promiscuous(void);
68 static int st_use_obp(void);
69 
70 /* Wrapper for socket calls. */
71 static int st_local_accept(int, struct sockaddr *, socklen_t *);
72 static int st_local_bind(int, const struct sockaddr *, socklen_t);
73 static int st_local_connect(int,  const  struct  sockaddr  *, socklen_t);
74 static int st_local_getsockname(int, struct sockaddr *, socklen_t *);
75 static int st_local_getsockopt(int, int, int, void *, socklen_t *);
76 static int st_local_listen(int, int);
77 static int st_local_recv(int, void *, size_t, int);
78 static int st_local_recvfrom(int, void *, size_t, int, struct sockaddr *,
79 	socklen_t *);
80 static int st_local_send(int, const void *, size_t, int);
81 static int st_local_sendto(int, const void *, size_t, int,
82 	const struct sockaddr *, socklen_t);
83 static int st_local_setsockopt(int, int, int, const void *, socklen_t);
84 static int st_local_socket(int, int, int);
85 static int st_local_socket_close(int);
86 
87 struct sock_test_cmd_s {
88 	char *st_cmd;
89 	int (*st_fn)(void);
90 };
91 
92 static 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 
116 struct 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. */
132 static int g_sock_fd = NO_OPENED_SOCKET;
133 static int save_g_sock_fd = NO_OPENED_SOCKET;
134 
135 /* Boolean to decide if OBP network routines should be used. */
136 static 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  */
144 static int
145 st_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 
154 static int
155 st_local_socket_close(int sd)
156 {
157 	if (!use_obp) {
158 		return (socket_close(sd));
159 	} else {
160 		return (0);
161 	}
162 }
163 
164 static int
165 st_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 
174 static int
175 st_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 
184 static int
185 st_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 
194 static int
195 st_local_listen(int sd,  int backlog)
196 {
197 	if (!use_obp) {
198 		return (listen(sd, backlog));
199 	} else {
200 		return (0);
201 	}
202 }
203 
204 static int
205 st_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 
214 static int
215 st_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 
225 static int
226 st_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 
235 static int
236 st_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 
246 static int
247 st_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 
257 static int
258 st_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 
268 static int
269 st_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 
279 static int
280 atoi(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 
304 int
305 st_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 
323 static int
324 st_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 
368 static int
369 st_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 
390 static int
391 st_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 
412 static int
413 st_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 
438 static int
439 st_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 
468 static int
469 st_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 
489 static int
490 st_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 
510 static int
511 st_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 
534 static int
535 st_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 
556 static int
557 st_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 
577 static int
578 st_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 
600 static int
601 st_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 
626 static int
627 st_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 
662 static int
663 st_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  */
707 static int
708 st_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 
791 static int
792 st_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 
807 static int
808 st_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 
842 static int
843 st_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 
864 static int
865 st_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 
894 static int
895 st_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 
917 static int
918 st_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 
929 static int
930 st_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 
940 static int
941 st_tcp_tw_report(void)
942 {
943 	printf("@ TCP Time Wait report\n");
944 	tcp_time_wait_report();
945 	return (0);
946 }
947