xref: /titanic_50/usr/src/stand/lib/sock/socket.c (revision 4a634bb80136cc001d14ab96addd9915105e5223)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4a634bb8Sga159272  * Common Development and Distribution License (the "License").
6*4a634bb8Sga159272  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*4a634bb8Sga159272  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * socket.c, Code implementing a simple socket interface.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include "socket_impl.h"
327c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
357c478bd9Sstevel@tonic-gate #include <sys/socket.h>
367c478bd9Sstevel@tonic-gate #include <netinet/in.h>
377c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
387c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
397c478bd9Sstevel@tonic-gate #include <sys/uio.h>
407c478bd9Sstevel@tonic-gate #include <sys/salib.h>
417c478bd9Sstevel@tonic-gate #include "socket_inet.h"
427c478bd9Sstevel@tonic-gate #include "ipv4.h"
437c478bd9Sstevel@tonic-gate #include "ipv4_impl.h"
447c478bd9Sstevel@tonic-gate #include "udp_inet.h"
457c478bd9Sstevel@tonic-gate #include "tcp_inet.h"
467c478bd9Sstevel@tonic-gate #include "mac.h"
477c478bd9Sstevel@tonic-gate #include "mac_impl.h"
487c478bd9Sstevel@tonic-gate #include <sys/promif.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate struct inetboot_socket	sockets[MAXSOCKET] = { 0 };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /* Default send and receive socket buffer size */
537c478bd9Sstevel@tonic-gate #define	SO_DEF_SNDBUF	48*1024
547c478bd9Sstevel@tonic-gate #define	SO_DEF_RCVBUF	48*1024
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Default max socket buffer size */
577c478bd9Sstevel@tonic-gate #define	SO_MAX_BUF	4*1024*1024
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static ssize_t dgram_sendto(int, const void *, size_t, int,
607c478bd9Sstevel@tonic-gate     const struct sockaddr *, int);
617c478bd9Sstevel@tonic-gate static ssize_t stream_sendto(int, const void *, size_t, int);
627c478bd9Sstevel@tonic-gate static int bind_check(int, const struct sockaddr *);
637c478bd9Sstevel@tonic-gate static int quickbind(int);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* Check the validity of a fd and return the socket index of that fd. */
667c478bd9Sstevel@tonic-gate int
so_check_fd(int fd,int * errno)677c478bd9Sstevel@tonic-gate so_check_fd(int fd, int *errno)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	int i;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	i = FD_TO_SOCKET(fd);
727c478bd9Sstevel@tonic-gate 	if (i < 0 || i >= MAXSOCKET) {
737c478bd9Sstevel@tonic-gate 		*errno = ENOTSOCK;
747c478bd9Sstevel@tonic-gate 		return (-1);
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_UNUSED) {
777c478bd9Sstevel@tonic-gate 		*errno = ENOTSOCK;
787c478bd9Sstevel@tonic-gate 		return (-1);
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 	return (i);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Create an endpoint for network communication. Returns a descriptor.
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  * Notes:
877c478bd9Sstevel@tonic-gate  *	Only PF_INET communication domains are supported. Within
887c478bd9Sstevel@tonic-gate  * 	this domain, only SOCK_RAW, SOCK_DGRAM and SOCK_STREAM types are
897c478bd9Sstevel@tonic-gate  *	supported.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate int
socket(int domain,int type,int protocol)927c478bd9Sstevel@tonic-gate socket(int domain, int type, int protocol)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	static int sock_initialized;
957c478bd9Sstevel@tonic-gate 	int i;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	errno = 0;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	if (!sock_initialized) {
1007c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAXSOCKET; i++)
1017c478bd9Sstevel@tonic-gate 			sockets[i].type = INETBOOT_UNUSED;
1027c478bd9Sstevel@tonic-gate 		sock_initialized = B_TRUE;
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	if (domain != AF_INET) {
1057c478bd9Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
1067c478bd9Sstevel@tonic-gate 		return (-1);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	/* Find available socket */
1107c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXSOCKET; i++) {
1117c478bd9Sstevel@tonic-gate 		if (sockets[i].type == INETBOOT_UNUSED)
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 	if (i >= MAXSOCKET) {
1157c478bd9Sstevel@tonic-gate 		errno = EMFILE;	/* No slots left. */
1167c478bd9Sstevel@tonic-gate 		return (-1);
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/* Some socket initialization... */
1207c478bd9Sstevel@tonic-gate 	sockets[i].so_rcvbuf = SO_DEF_RCVBUF;
1217c478bd9Sstevel@tonic-gate 	sockets[i].so_sndbuf = SO_DEF_SNDBUF;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Note that we ignore the protocol field for SOCK_DGRAM and
1257c478bd9Sstevel@tonic-gate 	 * SOCK_STREAM.  When we support different protocols in future,
1267c478bd9Sstevel@tonic-gate 	 * this needs to be changed.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate 	switch (type) {
1297c478bd9Sstevel@tonic-gate 	case SOCK_RAW:
1307c478bd9Sstevel@tonic-gate 		ipv4_raw_socket(&sockets[i], (uint8_t)protocol);
1317c478bd9Sstevel@tonic-gate 		break;
1327c478bd9Sstevel@tonic-gate 	case SOCK_DGRAM:
1337c478bd9Sstevel@tonic-gate 		udp_socket_init(&sockets[i]);
1347c478bd9Sstevel@tonic-gate 		break;
1357c478bd9Sstevel@tonic-gate 	case SOCK_STREAM:
1367c478bd9Sstevel@tonic-gate 		tcp_socket_init(&sockets[i]);
1377c478bd9Sstevel@tonic-gate 		break;
1387c478bd9Sstevel@tonic-gate 	default:
1397c478bd9Sstevel@tonic-gate 		errno = EPROTOTYPE;
1407c478bd9Sstevel@tonic-gate 		break;
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if (errno != 0)
1447c478bd9Sstevel@tonic-gate 		return (-1);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	/* IPv4 generic initialization. */
1477c478bd9Sstevel@tonic-gate 	ipv4_socket_init(&sockets[i]);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* MAC generic initialization. */
1507c478bd9Sstevel@tonic-gate 	mac_socket_init(&sockets[i]);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	return (i + SOCKETTYPE);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate int
getsockname(int s,struct sockaddr * name,socklen_t * namelen)1567c478bd9Sstevel@tonic-gate getsockname(int s, struct sockaddr *name,  socklen_t *namelen)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	int i;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	errno = 0;
1617c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
1627c478bd9Sstevel@tonic-gate 		return (-1);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (*namelen < sizeof (struct sockaddr_in)) {
1657c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1667c478bd9Sstevel@tonic-gate 		return (-1);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	/* Structure assignment... */
1707c478bd9Sstevel@tonic-gate 	*((struct sockaddr_in *)name) = sockets[i].bind;
1717c478bd9Sstevel@tonic-gate 	*namelen = sizeof (struct sockaddr_in);
1727c478bd9Sstevel@tonic-gate 	return (0);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * The socket options we support are:
1777c478bd9Sstevel@tonic-gate  * SO_RCVTIMEO	-	Value is in msecs, and is of uint32_t.
1787c478bd9Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is an int, and is a boolean (nonzero if set).
1797c478bd9Sstevel@tonic-gate  * SO_REUSEADDR -	Value is an int boolean.
1807c478bd9Sstevel@tonic-gate  * SO_RCVBUF -		Value is an int.
1817c478bd9Sstevel@tonic-gate  * SO_SNDBUF -		Value is an int.
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate int
getsockopt(int s,int level,int option,void * optval,socklen_t * optlen)1847c478bd9Sstevel@tonic-gate getsockopt(int s, int level, int option, void *optval, socklen_t *optlen)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	int i;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	errno = 0;
1897c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
1907c478bd9Sstevel@tonic-gate 		return (-1);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	switch (level) {
1937c478bd9Sstevel@tonic-gate 	case SOL_SOCKET: {
1947c478bd9Sstevel@tonic-gate 		switch (option) {
1957c478bd9Sstevel@tonic-gate 		case SO_RCVTIMEO:
1967c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (uint32_t)) {
1977c478bd9Sstevel@tonic-gate 				*(uint32_t *)optval = sockets[i].in_timeout;
1987c478bd9Sstevel@tonic-gate 			} else {
1997c478bd9Sstevel@tonic-gate 				*optlen = 0;
2007c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2017c478bd9Sstevel@tonic-gate 			}
2027c478bd9Sstevel@tonic-gate 			break;
2037c478bd9Sstevel@tonic-gate 		case SO_DONTROUTE:
2047c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2057c478bd9Sstevel@tonic-gate 				*(int *)optval =
2067c478bd9Sstevel@tonic-gate 				    (sockets[i].out_flags & SO_DONTROUTE);
2077c478bd9Sstevel@tonic-gate 			} else {
2087c478bd9Sstevel@tonic-gate 				*optlen = 0;
2097c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2107c478bd9Sstevel@tonic-gate 			}
2117c478bd9Sstevel@tonic-gate 			break;
2127c478bd9Sstevel@tonic-gate 		case SO_REUSEADDR:
2137c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2147c478bd9Sstevel@tonic-gate 				*(int *)optval =
2157c478bd9Sstevel@tonic-gate 				    (sockets[i].so_opt & SO_REUSEADDR);
2167c478bd9Sstevel@tonic-gate 			} else {
2177c478bd9Sstevel@tonic-gate 				*optlen = 0;
2187c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2197c478bd9Sstevel@tonic-gate 			}
2207c478bd9Sstevel@tonic-gate 			break;
2217c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
2227c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2237c478bd9Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_rcvbuf;
2247c478bd9Sstevel@tonic-gate 			} else {
2257c478bd9Sstevel@tonic-gate 				*optlen = 0;
2267c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2277c478bd9Sstevel@tonic-gate 			}
2287c478bd9Sstevel@tonic-gate 			break;
2297c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
2307c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2317c478bd9Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_sndbuf;
2327c478bd9Sstevel@tonic-gate 			} else {
2337c478bd9Sstevel@tonic-gate 				*optlen = 0;
2347c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2357c478bd9Sstevel@tonic-gate 			}
2367c478bd9Sstevel@tonic-gate 			break;
2377c478bd9Sstevel@tonic-gate 		case SO_LINGER:
2387c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (struct linger)) {
2397c478bd9Sstevel@tonic-gate 				/* struct copy */
2407c478bd9Sstevel@tonic-gate 				*(struct linger *)optval = sockets[i].so_linger;
2417c478bd9Sstevel@tonic-gate 			} else {
2427c478bd9Sstevel@tonic-gate 				*optlen = 0;
2437c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2447c478bd9Sstevel@tonic-gate 			}
2457c478bd9Sstevel@tonic-gate 		default:
2467c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
2477c478bd9Sstevel@tonic-gate 			break;
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		break;
2507c478bd9Sstevel@tonic-gate 	} /* case SOL_SOCKET */
2517c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
2527c478bd9Sstevel@tonic-gate 	case IPPROTO_IP: {
2537c478bd9Sstevel@tonic-gate 		switch (option) {
2547c478bd9Sstevel@tonic-gate 		default:
2557c478bd9Sstevel@tonic-gate 			*optlen = 0;
2567c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
2577c478bd9Sstevel@tonic-gate 			break;
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		break;
2607c478bd9Sstevel@tonic-gate 	} /* case IPPROTO_IP or IPPROTO_TCP */
2617c478bd9Sstevel@tonic-gate 	default:
2627c478bd9Sstevel@tonic-gate 		errno = ENOPROTOOPT;
2637c478bd9Sstevel@tonic-gate 		break;
2647c478bd9Sstevel@tonic-gate 	} /* switch (level) */
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (errno != 0)
2677c478bd9Sstevel@tonic-gate 		return (-1);
2687c478bd9Sstevel@tonic-gate 	else
2697c478bd9Sstevel@tonic-gate 		return (0);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate  * Generate a network-order source port from the privileged range if
2747c478bd9Sstevel@tonic-gate  * "reserved" is true, dynamic/private range otherwise. We consider the
2757c478bd9Sstevel@tonic-gate  * range of 512-1023 privileged ports as ports we can use. This mirrors
2767c478bd9Sstevel@tonic-gate  * historical rpc client practice for privileged port selection.
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate in_port_t
get_source_port(boolean_t reserved)2797c478bd9Sstevel@tonic-gate get_source_port(boolean_t reserved)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	static in_port_t	dynamic = IPPORT_DYNAMIC_START - 1,
2827c478bd9Sstevel@tonic-gate 	    rsvdport = (IPPORT_RESERVED / 2) - 1;
2837c478bd9Sstevel@tonic-gate 	in_port_t		p;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if (reserved) {
2867c478bd9Sstevel@tonic-gate 		if (++rsvdport >= IPPORT_RESERVED)
2877c478bd9Sstevel@tonic-gate 			p = rsvdport = IPPORT_RESERVED / 2;
2887c478bd9Sstevel@tonic-gate 		else
2897c478bd9Sstevel@tonic-gate 			p = rsvdport;
2907c478bd9Sstevel@tonic-gate 	} else
2917c478bd9Sstevel@tonic-gate 		p = ++dynamic;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	return (htons(p));
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * The socket options we support are:
2987c478bd9Sstevel@tonic-gate  * SO_RECVTIMEO	-	Value is uint32_t msecs.
2997c478bd9Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is int boolean (nonzero == TRUE, zero == FALSE).
3007c478bd9Sstevel@tonic-gate  * SO_REUSEADDR -	value is int boolean.
3017c478bd9Sstevel@tonic-gate  * SO_RCVBUF -		Value is int.
3027c478bd9Sstevel@tonic-gate  * SO_SNDBUF -		Value is int.
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate int
setsockopt(int s,int level,int option,const void * optval,socklen_t optlen)3057c478bd9Sstevel@tonic-gate setsockopt(int s, int level, int option, const void *optval, socklen_t optlen)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	int i;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	errno = 0;
3107c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
3117c478bd9Sstevel@tonic-gate 		return (-1);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	switch (level) {
3147c478bd9Sstevel@tonic-gate 	case SOL_SOCKET: {
3157c478bd9Sstevel@tonic-gate 		switch (option) {
3167c478bd9Sstevel@tonic-gate 		case SO_RCVTIMEO:
3177c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (uint32_t))
3187c478bd9Sstevel@tonic-gate 				sockets[i].in_timeout = *(uint32_t *)optval;
3197c478bd9Sstevel@tonic-gate 			else {
3207c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 			break;
3237c478bd9Sstevel@tonic-gate 		case SO_DONTROUTE:
3247c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3257c478bd9Sstevel@tonic-gate 				if (*(int *)optval)
3267c478bd9Sstevel@tonic-gate 					sockets[i].out_flags |= SO_DONTROUTE;
3277c478bd9Sstevel@tonic-gate 				else
3287c478bd9Sstevel@tonic-gate 					sockets[i].out_flags &= ~SO_DONTROUTE;
3297c478bd9Sstevel@tonic-gate 			} else {
3307c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 			break;
3337c478bd9Sstevel@tonic-gate 		case SO_REUSEADDR:
3347c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3357c478bd9Sstevel@tonic-gate 				if (*(int *)optval)
3367c478bd9Sstevel@tonic-gate 					sockets[i].so_opt |= SO_REUSEADDR;
3377c478bd9Sstevel@tonic-gate 				else
3387c478bd9Sstevel@tonic-gate 					sockets[i].so_opt &= ~SO_REUSEADDR;
3397c478bd9Sstevel@tonic-gate 			} else {
3407c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3417c478bd9Sstevel@tonic-gate 			}
3427c478bd9Sstevel@tonic-gate 			break;
3437c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
3447c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3457c478bd9Sstevel@tonic-gate 				sockets[i].so_rcvbuf = *(int *)optval;
3467c478bd9Sstevel@tonic-gate 				if (sockets[i].so_rcvbuf > SO_MAX_BUF)
3477c478bd9Sstevel@tonic-gate 					sockets[i].so_rcvbuf = SO_MAX_BUF;
3487c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3497c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
3507c478bd9Sstevel@tonic-gate 			} else {
3517c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 			break;
3547c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
3557c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3567c478bd9Sstevel@tonic-gate 				sockets[i].so_sndbuf = *(int *)optval;
3577c478bd9Sstevel@tonic-gate 				if (sockets[i].so_sndbuf > SO_MAX_BUF)
3587c478bd9Sstevel@tonic-gate 					sockets[i].so_sndbuf = SO_MAX_BUF;
3597c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3607c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
3617c478bd9Sstevel@tonic-gate 			} else {
3627c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3637c478bd9Sstevel@tonic-gate 			}
3647c478bd9Sstevel@tonic-gate 			break;
3657c478bd9Sstevel@tonic-gate 		case SO_LINGER:
3667c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (struct linger)) {
3677c478bd9Sstevel@tonic-gate 				/* struct copy */
3687c478bd9Sstevel@tonic-gate 				sockets[i].so_linger = *(struct linger *)optval;
3697c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3707c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
3717c478bd9Sstevel@tonic-gate 			} else {
3727c478bd9Sstevel@tonic-gate 				errno = EINVAL;
3737c478bd9Sstevel@tonic-gate 			}
3747c478bd9Sstevel@tonic-gate 			break;
3757c478bd9Sstevel@tonic-gate 		default:
3767c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
3777c478bd9Sstevel@tonic-gate 			break;
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 		break;
3807c478bd9Sstevel@tonic-gate 	} /* case SOL_SOCKET */
3817c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
3827c478bd9Sstevel@tonic-gate 	case IPPROTO_IP: {
3837c478bd9Sstevel@tonic-gate 		switch (option) {
3847c478bd9Sstevel@tonic-gate 		default:
3857c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
3867c478bd9Sstevel@tonic-gate 			break;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 		break;
3897c478bd9Sstevel@tonic-gate 	} /* case IPPROTO_IP  or IPPROTO_TCP */
3907c478bd9Sstevel@tonic-gate 	default:
3917c478bd9Sstevel@tonic-gate 		errno = ENOPROTOOPT;
3927c478bd9Sstevel@tonic-gate 		break;
3937c478bd9Sstevel@tonic-gate 	} /* switch (level) */
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if (errno != 0)
3967c478bd9Sstevel@tonic-gate 		return (-1);
3977c478bd9Sstevel@tonic-gate 	else
3987c478bd9Sstevel@tonic-gate 		return (0);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * Shut down part of a full-duplex connection.
4037c478bd9Sstevel@tonic-gate  *
4047c478bd9Sstevel@tonic-gate  * Only supported for TCP sockets
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate int
shutdown(int s,int how)4077c478bd9Sstevel@tonic-gate shutdown(int s, int how)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	int sock_id;
4107c478bd9Sstevel@tonic-gate 	int i;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	errno = 0;
4137c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
4147c478bd9Sstevel@tonic-gate 		return (-1);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/* shutdown only supported for TCP sockets */
4177c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
4187c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
4197c478bd9Sstevel@tonic-gate 		return (-1);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	if (!(sockets[sock_id].so_state & SS_ISCONNECTED)) {
4237c478bd9Sstevel@tonic-gate 		errno = ENOTCONN;
4247c478bd9Sstevel@tonic-gate 		return (-1);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	switch (how) {
4287c478bd9Sstevel@tonic-gate 	case 0:
4297c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTRCVMORE;
4307c478bd9Sstevel@tonic-gate 		break;
4317c478bd9Sstevel@tonic-gate 	case 1:
4327c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTSENDMORE;
4337c478bd9Sstevel@tonic-gate 		break;
4347c478bd9Sstevel@tonic-gate 	case 2:
4357c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE);
4367c478bd9Sstevel@tonic-gate 		break;
4377c478bd9Sstevel@tonic-gate 	default:
4387c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4397c478bd9Sstevel@tonic-gate 		return (-1);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	switch (sockets[sock_id].so_state &
4437c478bd9Sstevel@tonic-gate 	    (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
4447c478bd9Sstevel@tonic-gate 	case (SS_CANTRCVMORE | SS_CANTSENDMORE):
4457c478bd9Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
4467c478bd9Sstevel@tonic-gate 		for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4477c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].close[i] != NULL) {
4487c478bd9Sstevel@tonic-gate 				(void) sockets[sock_id].close[i](sock_id);
4497c478bd9Sstevel@tonic-gate 			}
4507c478bd9Sstevel@tonic-gate 		}
4517c478bd9Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
4527c478bd9Sstevel@tonic-gate 		break;
4537c478bd9Sstevel@tonic-gate 	case SS_CANTRCVMORE:
4547c478bd9Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
4557c478bd9Sstevel@tonic-gate 		break;
4567c478bd9Sstevel@tonic-gate 	case SS_CANTSENDMORE:
4577c478bd9Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
4587c478bd9Sstevel@tonic-gate 		if (tcp_shutdown(sock_id) < 0)
4597c478bd9Sstevel@tonic-gate 			return (-1);
4607c478bd9Sstevel@tonic-gate 		break;
4617c478bd9Sstevel@tonic-gate 	default:
4627c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4637c478bd9Sstevel@tonic-gate 		return (-1);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	return (0);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * "close" a socket.
4717c478bd9Sstevel@tonic-gate  */
4727c478bd9Sstevel@tonic-gate int
socket_close(int s)4737c478bd9Sstevel@tonic-gate socket_close(int s)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	int sock_id, i;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	errno = 0;
4787c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
4797c478bd9Sstevel@tonic-gate 		return (-1);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/* Call lower level protocol close routine. */
4827c478bd9Sstevel@tonic-gate 	for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4837c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].close[i] != NULL) {
4847c478bd9Sstevel@tonic-gate 			/*
4857c478bd9Sstevel@tonic-gate 			 * Note that the close() routine of other
4867c478bd9Sstevel@tonic-gate 			 * layers can return an error.  But right
4877c478bd9Sstevel@tonic-gate 			 * now, the only mechanism to report that
4887c478bd9Sstevel@tonic-gate 			 * back is for the close() routine to set
4897c478bd9Sstevel@tonic-gate 			 * the errno and socket_close() will return
4907c478bd9Sstevel@tonic-gate 			 * an error.  But the close operation will
4917c478bd9Sstevel@tonic-gate 			 * not be stopped.
4927c478bd9Sstevel@tonic-gate 			 */
4937c478bd9Sstevel@tonic-gate 			(void) sockets[sock_id].close[i](sock_id);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * Clear the input queue.  This has to be done
4997c478bd9Sstevel@tonic-gate 	 * after the lower level protocol close routines have been
5007c478bd9Sstevel@tonic-gate 	 * called as they may want to do something about the queue.
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 	nuke_grams(&sockets[sock_id].inq);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&sockets[sock_id], sizeof (struct inetboot_socket));
5057c478bd9Sstevel@tonic-gate 	sockets[sock_id].type = INETBOOT_UNUSED;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	return (0);
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate  * Read up to `nbyte' of data from socket `s' into `buf'; if non-zero,
5127c478bd9Sstevel@tonic-gate  * then give up after `read_timeout' seconds.  Returns the number of
5137c478bd9Sstevel@tonic-gate  * bytes read, or -1 on failure.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate int
socket_read(int s,void * buf,size_t nbyte,int read_timeout)5167c478bd9Sstevel@tonic-gate socket_read(int s, void *buf, size_t nbyte, int read_timeout)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	ssize_t	n;
5197c478bd9Sstevel@tonic-gate 	uint_t	start, diff;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * keep calling non-blocking recvfrom until something received
5237c478bd9Sstevel@tonic-gate 	 * or an error occurs
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	start = prom_gettime();
52666ac517eSjk115741 	for (;;) {
52766ac517eSjk115741 		n = recvfrom(s, buf, nbyte, MSG_DONTWAIT, NULL, NULL);
52866ac517eSjk115741 		if (n == -1 && errno == EWOULDBLOCK) {
5297c478bd9Sstevel@tonic-gate 			diff = (uint_t)((prom_gettime() - start) + 500) / 1000;
5307c478bd9Sstevel@tonic-gate 			if (read_timeout != 0 && diff > read_timeout) {
5317c478bd9Sstevel@tonic-gate 				errno = EINTR;
5327c478bd9Sstevel@tonic-gate 				return (-1);
5337c478bd9Sstevel@tonic-gate 			}
53466ac517eSjk115741 		} else {
5357c478bd9Sstevel@tonic-gate 			return (n);
5367c478bd9Sstevel@tonic-gate 		}
53766ac517eSjk115741 	}
53866ac517eSjk115741 }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * Write up to `nbyte' bytes of data from `buf' to the address pointed to
5427c478bd9Sstevel@tonic-gate  * `addr' using socket `s'.  Returns the number of bytes writte on success,
5437c478bd9Sstevel@tonic-gate  * or -1 on failure.
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate int
socket_write(int s,const void * buf,size_t nbyte,struct sockaddr_in * addr)5467c478bd9Sstevel@tonic-gate socket_write(int s, const void *buf, size_t nbyte, struct sockaddr_in *addr)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	return (sendto(s, buf, nbyte, 0, (struct sockaddr *)addr,
5497c478bd9Sstevel@tonic-gate 	    sizeof (*addr)));
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate static int
bind_check(int sock_id,const struct sockaddr * addr)5537c478bd9Sstevel@tonic-gate bind_check(int sock_id, const struct sockaddr *addr)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	int k;
5567c478bd9Sstevel@tonic-gate 	struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	/* Do not check for duplicate bind() if SO_REUSEADDR option is set. */
5597c478bd9Sstevel@tonic-gate 	if (! (sockets[sock_id].so_opt & SO_REUSEADDR)) {
5607c478bd9Sstevel@tonic-gate 		for (k = 0; k < MAXSOCKET; k++) {
5617c478bd9Sstevel@tonic-gate 			if (sockets[k].type != INETBOOT_UNUSED &&
5627c478bd9Sstevel@tonic-gate 			    sockets[k].proto == sockets[sock_id].proto &&
5637c478bd9Sstevel@tonic-gate 			    sockets[k].bound) {
5647c478bd9Sstevel@tonic-gate 				if ((sockets[k].bind.sin_addr.s_addr ==
5657c478bd9Sstevel@tonic-gate 				    in_addr->sin_addr.s_addr) &&
5667c478bd9Sstevel@tonic-gate 				    (sockets[k].bind.sin_port ==
5677c478bd9Sstevel@tonic-gate 				    in_addr->sin_port)) {
5687c478bd9Sstevel@tonic-gate 					errno = EADDRINUSE;
5697c478bd9Sstevel@tonic-gate 					return (-1);
5707c478bd9Sstevel@tonic-gate 				}
5717c478bd9Sstevel@tonic-gate 			}
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 	return (0);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /* Assign a name to an unnamed socket. */
5787c478bd9Sstevel@tonic-gate int
bind(int s,const struct sockaddr * name,socklen_t namelen)5797c478bd9Sstevel@tonic-gate bind(int s, const struct sockaddr *name, socklen_t namelen)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	int i;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	errno = 0;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
5867c478bd9Sstevel@tonic-gate 		return (-1);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	if (name == NULL) {
5897c478bd9Sstevel@tonic-gate 		/* unbind */
5907c478bd9Sstevel@tonic-gate 		if (sockets[i].bound) {
5917c478bd9Sstevel@tonic-gate 			bzero((caddr_t)&sockets[i].bind,
5927c478bd9Sstevel@tonic-gate 			    sizeof (struct sockaddr_in));
5937c478bd9Sstevel@tonic-gate 			sockets[i].bound = B_FALSE;
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate 		return (0);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	if (namelen != sizeof (struct sockaddr_in) || name == NULL) {
5987c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5997c478bd9Sstevel@tonic-gate 		return (-1);
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 	if (name->sa_family != AF_INET) {
6027c478bd9Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
6037c478bd9Sstevel@tonic-gate 		return (-1);
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 	if (sockets[i].bound) {
6067c478bd9Sstevel@tonic-gate 		if (bcmp((caddr_t)&sockets[i].bind, (caddr_t)name,
6077c478bd9Sstevel@tonic-gate 		    namelen) == 0) {
6087c478bd9Sstevel@tonic-gate 			/* attempt to bind to same address ok... */
6097c478bd9Sstevel@tonic-gate 			return (0);
6107c478bd9Sstevel@tonic-gate 		}
6117c478bd9Sstevel@tonic-gate 		errno = EINVAL;	/* already bound */
6127c478bd9Sstevel@tonic-gate 		return (-1);
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (errno != 0) {
6167c478bd9Sstevel@tonic-gate 		return (-1);
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/* Check for duplicate bind(). */
6207c478bd9Sstevel@tonic-gate 	if (bind_check(i, name) < 0)
6217c478bd9Sstevel@tonic-gate 		return (-1);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)name, (caddr_t)&sockets[i].bind, namelen);
6247c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_STREAM) {
6257c478bd9Sstevel@tonic-gate 		if (tcp_bind(i) < 0) {
6267c478bd9Sstevel@tonic-gate 			return (-1);
6277c478bd9Sstevel@tonic-gate 		}
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 	sockets[i].bound = B_TRUE;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	return (0);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate static int
quickbind(int sock_id)6357c478bd9Sstevel@tonic-gate quickbind(int sock_id)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	int i;
6387c478bd9Sstevel@tonic-gate 	struct sockaddr_in addr;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/*
6417c478bd9Sstevel@tonic-gate 	 * XXX This needs more work.  Right now, if ipv4_setipaddr()
6427c478bd9Sstevel@tonic-gate 	 * have not been called, this will be wrong.  But we need
6437c478bd9Sstevel@tonic-gate 	 * something better.  Need to be revisited.
6447c478bd9Sstevel@tonic-gate 	 */
6457c478bd9Sstevel@tonic-gate 	ipv4_getipaddr(&addr.sin_addr);
6467c478bd9Sstevel@tonic-gate 	addr.sin_family = AF_INET;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	for (i = SMALLEST_ANON_PORT; i <= LARGEST_ANON_PORT; i++) {
6497c478bd9Sstevel@tonic-gate 		addr.sin_port = htons(i);
6507c478bd9Sstevel@tonic-gate 		if (bind_check(sock_id, (struct sockaddr *)&addr) == 0)
6517c478bd9Sstevel@tonic-gate 			break;
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 	/* Need to clear errno as it is probably set by bind_check(). */
6547c478bd9Sstevel@tonic-gate 	errno = 0;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (i <= LARGEST_ANON_PORT) {
6577c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&addr, (caddr_t)&sockets[sock_id].bind,
6587c478bd9Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
6597c478bd9Sstevel@tonic-gate 		sockets[sock_id].bound = B_TRUE;
6607c478bd9Sstevel@tonic-gate #ifdef DEBUG
6617c478bd9Sstevel@tonic-gate 		printf("quick bind done addr %s port %d\n",
6627c478bd9Sstevel@tonic-gate 		    inet_ntoa(sockets[sock_id].bind.sin_addr),
6637c478bd9Sstevel@tonic-gate 		    ntohs(sockets[sock_id].bind.sin_port));
6647c478bd9Sstevel@tonic-gate #endif
6657c478bd9Sstevel@tonic-gate 		return (0);
6667c478bd9Sstevel@tonic-gate 	} else {
6677c478bd9Sstevel@tonic-gate 		return (-1);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate int
listen(int fd,int backlog)6727c478bd9Sstevel@tonic-gate listen(int fd, int backlog)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate 	int sock_id;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	errno = 0;
6777c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
6787c478bd9Sstevel@tonic-gate 		return (-1);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
6817c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
6827c478bd9Sstevel@tonic-gate 		return (-1);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
6857c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
6867c478bd9Sstevel@tonic-gate 		return (-1);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 	return (tcp_listen(sock_id, backlog));
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate int
accept(int fd,struct sockaddr * addr,socklen_t * addr_len)6927c478bd9Sstevel@tonic-gate accept(int fd, struct sockaddr *addr,  socklen_t *addr_len)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate 	int sock_id;
6957c478bd9Sstevel@tonic-gate 	int new_sd;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	errno = 0;
6987c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
6997c478bd9Sstevel@tonic-gate 		return (-1);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
7027c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
7037c478bd9Sstevel@tonic-gate 		return (-1);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
7067c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
7077c478bd9Sstevel@tonic-gate 		return (-1);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	if ((new_sd = tcp_accept(sock_id, addr, addr_len)) == -1)
7107c478bd9Sstevel@tonic-gate 		return (-1);
7117c478bd9Sstevel@tonic-gate 	sock_id = so_check_fd(new_sd, &errno);
7127c478bd9Sstevel@tonic-gate 	sockets[sock_id].so_state |= SS_ISCONNECTED;
7137c478bd9Sstevel@tonic-gate 	return (new_sd);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate int
connect(int fd,const struct sockaddr * addr,socklen_t addr_len)7177c478bd9Sstevel@tonic-gate connect(int fd, const  struct sockaddr *addr, socklen_t addr_len)
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate 	int sock_id;
7207c478bd9Sstevel@tonic-gate 	int so_type;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	errno = 0;
7237c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
7247c478bd9Sstevel@tonic-gate 		return (-1);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (addr == NULL || addr_len == 0) {
7297c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7307c478bd9Sstevel@tonic-gate 		return (-1);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 	/* Don't allow connect for raw socket. */
7337c478bd9Sstevel@tonic-gate 	if (so_type == INETBOOT_RAW) {
7347c478bd9Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
7357c478bd9Sstevel@tonic-gate 		return (-1);
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_state & SS_ISCONNECTED) {
7397c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7407c478bd9Sstevel@tonic-gate 		return (-1);
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
7447c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
7457c478bd9Sstevel@tonic-gate 		return (-1);
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	/* If the socket is not bound, we need to do a quick bind. */
7497c478bd9Sstevel@tonic-gate 	if (!sockets[sock_id].bound) {
7507c478bd9Sstevel@tonic-gate 		/* For TCP socket, just call tcp_bind(). */
7517c478bd9Sstevel@tonic-gate 		if (so_type == INETBOOT_STREAM) {
7527c478bd9Sstevel@tonic-gate 			if (tcp_bind(sock_id) < 0)
7537c478bd9Sstevel@tonic-gate 				return (-1);
7547c478bd9Sstevel@tonic-gate 		} else {
7557c478bd9Sstevel@tonic-gate 			if (quickbind(sock_id) < 0) {
7567c478bd9Sstevel@tonic-gate 				errno = EADDRNOTAVAIL;
7577c478bd9Sstevel@tonic-gate 				return (-1);
7587c478bd9Sstevel@tonic-gate 			}
7597c478bd9Sstevel@tonic-gate 		}
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	/* Should do some sanity check for addr .... */
7627c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)addr, &sockets[sock_id].remote,
7637c478bd9Sstevel@tonic-gate 	    sizeof (struct sockaddr_in));
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM) {
7667c478bd9Sstevel@tonic-gate 		/* Call TCP connect routine. */
7677c478bd9Sstevel@tonic-gate 		if (tcp_connect(sock_id) == 0)
7687c478bd9Sstevel@tonic-gate 			sockets[sock_id].so_state |= SS_ISCONNECTED;
7697c478bd9Sstevel@tonic-gate 		else {
7707c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0)
7717c478bd9Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
7727c478bd9Sstevel@tonic-gate 			return (-1);
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 	} else {
7757c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_ISCONNECTED;
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 	return (0);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate /* Just a wrapper around recvfrom(). */
7817c478bd9Sstevel@tonic-gate ssize_t
recv(int s,void * buf,size_t len,int flags)7827c478bd9Sstevel@tonic-gate recv(int s, void *buf, size_t len, int flags)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	return (recvfrom(s, buf, len, flags, NULL, NULL));
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate  * Receive messages from a connectionless socket. Legal flags are 0 and
7897c478bd9Sstevel@tonic-gate  * MSG_DONTWAIT. MSG_WAITALL is not currently supported.
7907c478bd9Sstevel@tonic-gate  *
7917c478bd9Sstevel@tonic-gate  * Returns length of message for success, -1 if error occurred.
7927c478bd9Sstevel@tonic-gate  */
7937c478bd9Sstevel@tonic-gate ssize_t
recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)7947c478bd9Sstevel@tonic-gate recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
7957c478bd9Sstevel@tonic-gate     socklen_t *fromlen)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	int			sock_id, i;
7987c478bd9Sstevel@tonic-gate 	ssize_t			datalen, bytes = 0;
7997c478bd9Sstevel@tonic-gate 	struct inetgram		*icp;
8007c478bd9Sstevel@tonic-gate 	enum SockType		so_type;
8017c478bd9Sstevel@tonic-gate 	char			*tmp_buf;
8027c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	errno = 0;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
8077c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8087c478bd9Sstevel@tonic-gate 		return (-1);
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM &&
8127c478bd9Sstevel@tonic-gate 	    !(sockets[sock_id].so_state & SS_ISCONNECTED)) {
8137c478bd9Sstevel@tonic-gate 		errno = ENOTCONN;
8147c478bd9Sstevel@tonic-gate 		return (-1);
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	if (buf == NULL || len == 0) {
8187c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8197c478bd9Sstevel@tonic-gate 		return (-1);
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 	/* Yup - MSG_WAITALL not implemented */
8227c478bd9Sstevel@tonic-gate 	if ((flags & ~MSG_DONTWAIT) != 0) {
8237c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8247c478bd9Sstevel@tonic-gate 		return (-1);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate retry:
8287c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].inq == NULL) {
8297c478bd9Sstevel@tonic-gate 		/* Go out and check the wire */
8307c478bd9Sstevel@tonic-gate 		for (i = MEDIA_LVL; i < APP_LVL; i++) {
8317c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].input[i] != NULL) {
8327c478bd9Sstevel@tonic-gate 				if (sockets[sock_id].input[i](sock_id) < 0) {
8337c478bd9Sstevel@tonic-gate 					if (sockets[sock_id].so_error != 0) {
8347c478bd9Sstevel@tonic-gate 						errno =
8357c478bd9Sstevel@tonic-gate 						    sockets[sock_id].so_error;
8367c478bd9Sstevel@tonic-gate 					}
8377c478bd9Sstevel@tonic-gate 					return (-1);
8387c478bd9Sstevel@tonic-gate 				}
8397c478bd9Sstevel@tonic-gate 			}
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	/* Remove unknown inetgrams from the head of inq.  Can this happen? */
8467c478bd9Sstevel@tonic-gate 	while ((icp = sockets[sock_id].inq) != NULL) {
8477c478bd9Sstevel@tonic-gate 		if ((so_type == INETBOOT_DGRAM ||
8487c478bd9Sstevel@tonic-gate 		    so_type == INETBOOT_STREAM) &&
8497c478bd9Sstevel@tonic-gate 		    icp->igm_level != APP_LVL) {
8507c478bd9Sstevel@tonic-gate #ifdef	DEBUG
8517c478bd9Sstevel@tonic-gate 			printf("recvfrom: unexpected level %d frame found\n",
8527c478bd9Sstevel@tonic-gate 			    icp->igm_level);
8537c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
8547c478bd9Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
8557c478bd9Sstevel@tonic-gate 			continue;
8567c478bd9Sstevel@tonic-gate 		} else {
8577c478bd9Sstevel@tonic-gate 			break;
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (icp == NULL) {
8637c478bd9Sstevel@tonic-gate 		/*
8647c478bd9Sstevel@tonic-gate 		 * Checking for error should be done everytime a lower layer
8657c478bd9Sstevel@tonic-gate 		 * input routing is called.  For example, if TCP gets a RST,
8667c478bd9Sstevel@tonic-gate 		 * this should be reported asap.
8677c478bd9Sstevel@tonic-gate 		 */
8687c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTRCVMORE) {
8697c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0) {
8707c478bd9Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
8717c478bd9Sstevel@tonic-gate 				return (-1);
8727c478bd9Sstevel@tonic-gate 			} else {
8737c478bd9Sstevel@tonic-gate 				return (0);
8747c478bd9Sstevel@tonic-gate 			}
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 		if ((flags & MSG_DONTWAIT) == 0)
8787c478bd9Sstevel@tonic-gate 			goto retry;	/* wait forever */
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		/* no data */
8817c478bd9Sstevel@tonic-gate 		errno = EWOULDBLOCK;
8827c478bd9Sstevel@tonic-gate 		return (-1);
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	if (from != NULL && fromlen != NULL) {
8867c478bd9Sstevel@tonic-gate 		switch (so_type) {
8877c478bd9Sstevel@tonic-gate 		case INETBOOT_STREAM:
8887c478bd9Sstevel@tonic-gate 			/* Need to copy from the socket's remote address. */
8897c478bd9Sstevel@tonic-gate 			bcopy(&(sockets[sock_id].remote), from, MIN(*fromlen,
8907c478bd9Sstevel@tonic-gate 			    sizeof (struct sockaddr_in)));
8917c478bd9Sstevel@tonic-gate 			break;
8927c478bd9Sstevel@tonic-gate 		case INETBOOT_RAW:
8937c478bd9Sstevel@tonic-gate 		case INETBOOT_DGRAM:
8947c478bd9Sstevel@tonic-gate 		default:
8957c478bd9Sstevel@tonic-gate 			if (*fromlen > sizeof (icp->igm_saddr))
8967c478bd9Sstevel@tonic-gate 				*fromlen = sizeof (icp->igm_saddr);
8977c478bd9Sstevel@tonic-gate 			bcopy((caddr_t)&(icp->igm_saddr), (caddr_t)from,
8987c478bd9Sstevel@tonic-gate 			    MIN(*fromlen, sizeof (struct sockaddr_in)));
8997c478bd9Sstevel@tonic-gate 			break;
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	mp = icp->igm_mp;
9047c478bd9Sstevel@tonic-gate 	switch (so_type) {
9057c478bd9Sstevel@tonic-gate 	case INETBOOT_STREAM:
9067c478bd9Sstevel@tonic-gate 		/*
9077c478bd9Sstevel@tonic-gate 		 * If the message has igm_id == TCP_CALLB_MAGIC_ID, we need
9087c478bd9Sstevel@tonic-gate 		 * to drain the data held by tcp and try again.
9097c478bd9Sstevel@tonic-gate 		 */
9107c478bd9Sstevel@tonic-gate 		if (icp->igm_id == TCP_CALLB_MAGIC_ID) {
9117c478bd9Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9127c478bd9Sstevel@tonic-gate 			tcp_rcv_drain_sock(sock_id);
9137c478bd9Sstevel@tonic-gate 			goto retry;
9147c478bd9Sstevel@tonic-gate 		}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		/* TCP should put only user data in the inetgram. */
9177c478bd9Sstevel@tonic-gate 		tmp_buf = (char *)buf;
9187c478bd9Sstevel@tonic-gate 		while (len > 0 && icp != NULL) {
9197c478bd9Sstevel@tonic-gate 			datalen = mp->b_wptr - mp->b_rptr;
9207c478bd9Sstevel@tonic-gate 			if (len < datalen) {
9217c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, len);
9227c478bd9Sstevel@tonic-gate 				bytes += len;
9237c478bd9Sstevel@tonic-gate 				mp->b_rptr += len;
9247c478bd9Sstevel@tonic-gate 				break;
9257c478bd9Sstevel@tonic-gate 			} else {
9267c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, datalen);
9277c478bd9Sstevel@tonic-gate 				len -= datalen;
9287c478bd9Sstevel@tonic-gate 				bytes += datalen;
9297c478bd9Sstevel@tonic-gate 				tmp_buf += datalen;
9307c478bd9Sstevel@tonic-gate 				del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 				/*
9337c478bd9Sstevel@tonic-gate 				 * If we have any embedded magic messages just
9347c478bd9Sstevel@tonic-gate 				 * drop them.
9357c478bd9Sstevel@tonic-gate 				 */
9367c478bd9Sstevel@tonic-gate 				while ((icp = sockets[sock_id].inq) != NULL) {
9377c478bd9Sstevel@tonic-gate 					if (icp->igm_id != TCP_CALLB_MAGIC_ID)
9387c478bd9Sstevel@tonic-gate 						break;
9397c478bd9Sstevel@tonic-gate 					del_gram(&sockets[sock_id].inq, icp,
9407c478bd9Sstevel@tonic-gate 					    B_TRUE);
9417c478bd9Sstevel@tonic-gate 				}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 				if (icp == NULL)
9447c478bd9Sstevel@tonic-gate 					break;
9457c478bd9Sstevel@tonic-gate 				mp = icp->igm_mp;
9467c478bd9Sstevel@tonic-gate 			}
9477c478bd9Sstevel@tonic-gate 		}
9487c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_rcvbuf += (int32_t)bytes;
9497c478bd9Sstevel@tonic-gate 		break;
9507c478bd9Sstevel@tonic-gate 	case INETBOOT_DGRAM:
9517c478bd9Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
9527c478bd9Sstevel@tonic-gate 		if (len < datalen)
9537c478bd9Sstevel@tonic-gate 			bytes = len;
9547c478bd9Sstevel@tonic-gate 		else
9557c478bd9Sstevel@tonic-gate 			bytes = datalen;
9567c478bd9Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
9577c478bd9Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9587c478bd9Sstevel@tonic-gate 		break;
9597c478bd9Sstevel@tonic-gate 	case INETBOOT_RAW:
9607c478bd9Sstevel@tonic-gate 	default:
9617c478bd9Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
9627c478bd9Sstevel@tonic-gate 		if (len < datalen)
9637c478bd9Sstevel@tonic-gate 			bytes = len;
9647c478bd9Sstevel@tonic-gate 		else
9657c478bd9Sstevel@tonic-gate 			bytes = datalen;
9667c478bd9Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
9677c478bd9Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9687c478bd9Sstevel@tonic-gate 		break;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate #ifdef	DEBUG
9727c478bd9Sstevel@tonic-gate 	printf("recvfrom(%d): data: (0x%x,%d)\n", sock_id,
9737c478bd9Sstevel@tonic-gate 	    (icp != NULL) ? icp->igm_mp : 0, bytes);
9747c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
9757c478bd9Sstevel@tonic-gate 	return (bytes);
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate /* Just a wrapper around sendto(). */
9807c478bd9Sstevel@tonic-gate ssize_t
send(int s,const void * msg,size_t len,int flags)9817c478bd9Sstevel@tonic-gate send(int s, const void *msg, size_t len, int flags)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	return (sendto(s, msg, len, flags, NULL, 0));
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate /*
9877c478bd9Sstevel@tonic-gate  * Transmit a message through a socket.
9887c478bd9Sstevel@tonic-gate  *
9897c478bd9Sstevel@tonic-gate  * Supported flags: MSG_DONTROUTE or 0.
9907c478bd9Sstevel@tonic-gate  */
9917c478bd9Sstevel@tonic-gate ssize_t
sendto(int s,const void * msg,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)9927c478bd9Sstevel@tonic-gate sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to,
9937c478bd9Sstevel@tonic-gate     socklen_t tolen)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	enum SockType so_type;
9967c478bd9Sstevel@tonic-gate 	int sock_id;
9977c478bd9Sstevel@tonic-gate 	ssize_t bytes;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	errno = 0;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
10027c478bd9Sstevel@tonic-gate 		return (-1);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 	if (msg == NULL) {
10057c478bd9Sstevel@tonic-gate 		errno = EINVAL;
10067c478bd9Sstevel@tonic-gate 		return (-1);
10077c478bd9Sstevel@tonic-gate 	}
10087c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
10097c478bd9Sstevel@tonic-gate 	if ((flags & ~MSG_DONTROUTE) != 0) {
10107c478bd9Sstevel@tonic-gate 		errno = EINVAL;
10117c478bd9Sstevel@tonic-gate 		return (-1);
10127c478bd9Sstevel@tonic-gate 	}
10137c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
10147c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
10157c478bd9Sstevel@tonic-gate 		return (-1);
10167c478bd9Sstevel@tonic-gate 	}
10177c478bd9Sstevel@tonic-gate 	if (to != NULL && to->sa_family != AF_INET) {
10187c478bd9Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
10197c478bd9Sstevel@tonic-gate 		return (-1);
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	switch (so_type) {
10237c478bd9Sstevel@tonic-gate 	case INETBOOT_RAW:
10247c478bd9Sstevel@tonic-gate 	case INETBOOT_DGRAM:
10257c478bd9Sstevel@tonic-gate 		if (!(sockets[sock_id].so_state & SS_ISCONNECTED) &&
10267c478bd9Sstevel@tonic-gate 		    (to == NULL || tolen != sizeof (struct sockaddr_in))) {
10277c478bd9Sstevel@tonic-gate 			errno = EINVAL;
10287c478bd9Sstevel@tonic-gate 			return (-1);
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 		bytes = dgram_sendto(sock_id, msg, len, flags, to, tolen);
10317c478bd9Sstevel@tonic-gate 		break;
10327c478bd9Sstevel@tonic-gate 	case INETBOOT_STREAM:
10337c478bd9Sstevel@tonic-gate 		if (!((sockets[sock_id].so_state & SS_ISCONNECTED) ||
10347c478bd9Sstevel@tonic-gate 		    (sockets[sock_id].so_state & SS_ISCONNECTING))) {
10357c478bd9Sstevel@tonic-gate 			errno = EINVAL;
10367c478bd9Sstevel@tonic-gate 			return (-1);
10377c478bd9Sstevel@tonic-gate 		}
10387c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTSENDMORE) {
10397c478bd9Sstevel@tonic-gate 			errno = EPIPE;
10407c478bd9Sstevel@tonic-gate 			return (-1);
10417c478bd9Sstevel@tonic-gate 		}
10427c478bd9Sstevel@tonic-gate 		bytes = stream_sendto(sock_id, msg, len, flags);
10437c478bd9Sstevel@tonic-gate 		break;
10447c478bd9Sstevel@tonic-gate 	default:
10457c478bd9Sstevel@tonic-gate 		/* Should not happen... */
10467c478bd9Sstevel@tonic-gate 		errno = EPROTOTYPE;
10477c478bd9Sstevel@tonic-gate 		return (-1);
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 	return (bytes);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate static ssize_t
dgram_sendto(int i,const void * msg,size_t len,int flags,const struct sockaddr * to,int tolen)10537c478bd9Sstevel@tonic-gate dgram_sendto(int i, const void *msg, size_t len, int flags,
10547c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen)
10557c478bd9Sstevel@tonic-gate {
10567c478bd9Sstevel@tonic-gate 	struct inetgram		oc;
10577c478bd9Sstevel@tonic-gate 	int			l, offset;
10587c478bd9Sstevel@tonic-gate 	size_t			tlen;
10597c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate #ifdef	DEBUG
10627c478bd9Sstevel@tonic-gate 	{
10637c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin = (struct sockaddr_in *)to;
10647c478bd9Sstevel@tonic-gate 	printf("sendto(%d): msg of length: %d sent to port %d and host: %s\n",
10657c478bd9Sstevel@tonic-gate 	    i, len, ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	nuke_grams(&sockets[i].inq); /* flush the input queue */
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	/* calculate offset for data */
10727c478bd9Sstevel@tonic-gate 	offset = sockets[i].headerlen[MEDIA_LVL](NULL) +
10737c478bd9Sstevel@tonic-gate 	    (sockets[i].headerlen[NETWORK_LVL])(NULL);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&oc, sizeof (oc));
10767c478bd9Sstevel@tonic-gate 	if (sockets[i].type != INETBOOT_RAW) {
10777c478bd9Sstevel@tonic-gate 		offset += (sockets[i].headerlen[TRANSPORT_LVL])(NULL);
10787c478bd9Sstevel@tonic-gate 		oc.igm_level = TRANSPORT_LVL;
10797c478bd9Sstevel@tonic-gate 	} else
10807c478bd9Sstevel@tonic-gate 		oc.igm_level = NETWORK_LVL;
10817c478bd9Sstevel@tonic-gate 	oc.igm_oflags = flags;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if (to != NULL) {
10847c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)to, (caddr_t)&oc.igm_saddr, tolen);
10857c478bd9Sstevel@tonic-gate 	} else {
10867c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&sockets[i].remote, (caddr_t)&oc.igm_saddr,
10877c478bd9Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	/* Get a legal source port if the socket isn't bound. */
10917c478bd9Sstevel@tonic-gate 	if (sockets[i].bound == B_FALSE &&
10927c478bd9Sstevel@tonic-gate 	    ntohs(oc.igm_saddr.sin_port == 0)) {
10937c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)&oc.igm_saddr)->sin_port =
10947c478bd9Sstevel@tonic-gate 		    get_source_port(B_FALSE);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	/* Round up to 16bit value for checksum purposes */
10987c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_DGRAM) {
10997c478bd9Sstevel@tonic-gate 		tlen = ((len + sizeof (uint16_t) - 1) &
11007c478bd9Sstevel@tonic-gate 		    ~(sizeof (uint16_t) - 1));
11017c478bd9Sstevel@tonic-gate 	} else
11027c478bd9Sstevel@tonic-gate 		tlen = len;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	if ((oc.igm_mp = allocb(tlen + offset, 0)) == NULL) {
11057c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
11067c478bd9Sstevel@tonic-gate 		return (-1);
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 	mp = oc.igm_mp;
11097c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr += offset;
11107c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)msg, mp->b_wptr, len);
11117c478bd9Sstevel@tonic-gate 	mp->b_wptr += len;
11127c478bd9Sstevel@tonic-gate 	for (l = TRANSPORT_LVL; l >= MEDIA_LVL; l--) {
11137c478bd9Sstevel@tonic-gate 		if (sockets[i].output[l] != NULL) {
11147c478bd9Sstevel@tonic-gate 			if (sockets[i].output[l](i, &oc) < 0) {
11157c478bd9Sstevel@tonic-gate 				freeb(mp);
11167c478bd9Sstevel@tonic-gate 				if (errno == 0)
11177c478bd9Sstevel@tonic-gate 					errno = EIO;
11187c478bd9Sstevel@tonic-gate 				return (-1);
11197c478bd9Sstevel@tonic-gate 			}
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 	freeb(mp);
11237c478bd9Sstevel@tonic-gate 	return (len);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate /* ARGSUSED */
11277c478bd9Sstevel@tonic-gate static ssize_t
stream_sendto(int i,const void * msg,size_t len,int flags)11287c478bd9Sstevel@tonic-gate stream_sendto(int i, const void *msg, size_t len, int flags)
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate 	int cnt;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	assert(sockets[i].pcb != NULL);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	/*
11357c478bd9Sstevel@tonic-gate 	 * Call directly TCP's send routine.  We do this because TCP
11367c478bd9Sstevel@tonic-gate 	 * needs to decide whether to send out the data.
11377c478bd9Sstevel@tonic-gate 	 *
11387c478bd9Sstevel@tonic-gate 	 * Note also that currently, TCP ignores all flags passed in for
11397c478bd9Sstevel@tonic-gate 	 * TCP socket.
11407c478bd9Sstevel@tonic-gate 	 */
11417c478bd9Sstevel@tonic-gate 	if ((cnt = tcp_send(i, sockets[i].pcb, msg, len)) < 0) {
11427c478bd9Sstevel@tonic-gate 		if (sockets[i].so_error != 0)
11437c478bd9Sstevel@tonic-gate 			errno = sockets[i].so_error;
11447c478bd9Sstevel@tonic-gate 		return (-1);
11457c478bd9Sstevel@tonic-gate 	} else {
11467c478bd9Sstevel@tonic-gate 		return (cnt);
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate  * Returns ptr to the last inetgram in the list, or null if list is null
11527c478bd9Sstevel@tonic-gate  */
11537c478bd9Sstevel@tonic-gate struct inetgram *
last_gram(struct inetgram * igp)11547c478bd9Sstevel@tonic-gate last_gram(struct inetgram *igp)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	struct inetgram	*wp;
11577c478bd9Sstevel@tonic-gate 	for (wp = igp; wp != NULL; wp = wp->igm_next) {
11587c478bd9Sstevel@tonic-gate 		if (wp->igm_next == NULL)
11597c478bd9Sstevel@tonic-gate 			return (wp);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 	return (NULL);
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate /*
11657c478bd9Sstevel@tonic-gate  * Adds an inetgram or list of inetgrams to the end of the list.
11667c478bd9Sstevel@tonic-gate  */
11677c478bd9Sstevel@tonic-gate void
add_grams(struct inetgram ** igpp,struct inetgram * newgp)11687c478bd9Sstevel@tonic-gate add_grams(struct inetgram **igpp, struct inetgram *newgp)
11697c478bd9Sstevel@tonic-gate {
11707c478bd9Sstevel@tonic-gate 	struct inetgram	 *wp;
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	if (newgp == NULL)
11737c478bd9Sstevel@tonic-gate 		return;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	if (*igpp == NULL)
11767c478bd9Sstevel@tonic-gate 		*igpp = newgp;
11777c478bd9Sstevel@tonic-gate 	else {
11787c478bd9Sstevel@tonic-gate 		wp = last_gram(*igpp);
11797c478bd9Sstevel@tonic-gate 		wp->igm_next = newgp;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate  * Nuke a whole list of grams.
11857c478bd9Sstevel@tonic-gate  */
11867c478bd9Sstevel@tonic-gate void
nuke_grams(struct inetgram ** lgpp)11877c478bd9Sstevel@tonic-gate nuke_grams(struct inetgram **lgpp)
11887c478bd9Sstevel@tonic-gate {
11897c478bd9Sstevel@tonic-gate 	while (*lgpp != NULL)
11907c478bd9Sstevel@tonic-gate 		del_gram(lgpp, *lgpp, B_TRUE);
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate /*
11947c478bd9Sstevel@tonic-gate  * Remove the referenced inetgram. List is altered accordingly. Destroy the
11957c478bd9Sstevel@tonic-gate  * referenced inetgram if freeit is B_TRUE.
11967c478bd9Sstevel@tonic-gate  */
11977c478bd9Sstevel@tonic-gate void
del_gram(struct inetgram ** lgpp,struct inetgram * igp,int freeit)11987c478bd9Sstevel@tonic-gate del_gram(struct inetgram **lgpp, struct inetgram *igp, int freeit)
11997c478bd9Sstevel@tonic-gate {
12007c478bd9Sstevel@tonic-gate 	struct inetgram	*wp, *pp = NULL;
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	if (lgpp == NULL || igp == NULL)
12037c478bd9Sstevel@tonic-gate 		return;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	wp = *lgpp;
12067c478bd9Sstevel@tonic-gate 	while (wp != NULL) {
12077c478bd9Sstevel@tonic-gate 		if (wp == igp) {
12087c478bd9Sstevel@tonic-gate 			/* detach wp from the list */
12097c478bd9Sstevel@tonic-gate 			if (*lgpp == wp)
12107c478bd9Sstevel@tonic-gate 				*lgpp = (*lgpp)->igm_next;
12117c478bd9Sstevel@tonic-gate 			else
12127c478bd9Sstevel@tonic-gate 				pp->igm_next = wp->igm_next;
12137c478bd9Sstevel@tonic-gate 			igp->igm_next = NULL;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 			if (freeit) {
12167c478bd9Sstevel@tonic-gate 				if (igp->igm_mp != NULL)
12177c478bd9Sstevel@tonic-gate 					freeb(igp->igm_mp);
12187c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)igp,
12197c478bd9Sstevel@tonic-gate 				    sizeof (struct inetgram));
12207c478bd9Sstevel@tonic-gate 			}
12217c478bd9Sstevel@tonic-gate 			break;
12227c478bd9Sstevel@tonic-gate 		}
12237c478bd9Sstevel@tonic-gate 		pp = wp;
12247c478bd9Sstevel@tonic-gate 		wp = wp->igm_next;
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate struct nct_t nct[] = {
12297c478bd9Sstevel@tonic-gate 	"bootp",	NCT_BOOTP_DHCP,
12307c478bd9Sstevel@tonic-gate 	"dhcp",		NCT_BOOTP_DHCP,
12317c478bd9Sstevel@tonic-gate 	"rarp",		NCT_RARP_BOOTPARAMS,
12327c478bd9Sstevel@tonic-gate 	"manual",	NCT_MANUAL
12337c478bd9Sstevel@tonic-gate };
12347c478bd9Sstevel@tonic-gate int	nct_entries = sizeof (nct) / sizeof (nct[0]);
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate /*
12377c478bd9Sstevel@tonic-gate  * Figure out from the bootpath what kind of network configuration strategy
12387c478bd9Sstevel@tonic-gate  * we should use. Returns the network config strategy.
12397c478bd9Sstevel@tonic-gate  */
12407c478bd9Sstevel@tonic-gate int
get_netconfig_strategy(void)12417c478bd9Sstevel@tonic-gate get_netconfig_strategy(void)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 	int	i;
12447c478bd9Sstevel@tonic-gate #define	ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\0')
12457c478bd9Sstevel@tonic-gate 	char	lbootpath[OBP_MAXPATHLEN];
12467c478bd9Sstevel@tonic-gate 	char	net_options[NCT_BUFSIZE];
12477c478bd9Sstevel@tonic-gate 	char	*op, *nop, *sp;
1248fa9e4066Sahrens 	pnode_t	cn;
12497c478bd9Sstevel@tonic-gate 	int	proplen;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	/* If the PROM DHCP cache exists, we're done */
12527c478bd9Sstevel@tonic-gate 	if (prom_cached_reply(B_TRUE))
12537c478bd9Sstevel@tonic-gate 		return (NCT_BOOTP_DHCP);
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	/*
12567c478bd9Sstevel@tonic-gate 	 *	Newer (version 4) PROMs will put the name in the
12577c478bd9Sstevel@tonic-gate 	 *	"net-config-strategy" property.
12587c478bd9Sstevel@tonic-gate 	 */
12597c478bd9Sstevel@tonic-gate 	cn = prom_finddevice("/chosen");
12607c478bd9Sstevel@tonic-gate 	if ((proplen = prom_getproplen(cn, "net-config-strategy")) <
12617c478bd9Sstevel@tonic-gate 	    sizeof (net_options)) {
12627c478bd9Sstevel@tonic-gate 		(void) prom_getprop(cn, "net-config-strategy", net_options);
12637c478bd9Sstevel@tonic-gate 		net_options[proplen] = '\0';
12647c478bd9Sstevel@tonic-gate 	} else {
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/*
12677c478bd9Sstevel@tonic-gate 		 * We're reduced to sacanning bootpath for the prototol to use.
12687c478bd9Sstevel@tonic-gate 		 * Since there was no "net-config-strategy" property, this is
12697c478bd9Sstevel@tonic-gate 		 * an old PROM, so we need to excise any extraneous key/value
12707c478bd9Sstevel@tonic-gate 		 * initializations from bootpath[].
12717c478bd9Sstevel@tonic-gate 		 */
12727c478bd9Sstevel@tonic-gate 		for (op = prom_bootpath(), sp = lbootpath; op != NULL &&
12737c478bd9Sstevel@tonic-gate 		    !ISSPACE(*op); sp++, op++)
12747c478bd9Sstevel@tonic-gate 			*sp = *op;
12757c478bd9Sstevel@tonic-gate 		*sp = '\0';
12767c478bd9Sstevel@tonic-gate 		/* find the last '/' (in the device path) */
12777c478bd9Sstevel@tonic-gate 		if ((op = strrchr(lbootpath, '/')) == NULL)	/* last '/' */
12787c478bd9Sstevel@tonic-gate 			op = lbootpath;
12797c478bd9Sstevel@tonic-gate 		else
12807c478bd9Sstevel@tonic-gate 			op++;
12817c478bd9Sstevel@tonic-gate 		/* then look for the ':' separating it from the protocol */
12827c478bd9Sstevel@tonic-gate 		while (*op != ':' && *op != '\0')
12837c478bd9Sstevel@tonic-gate 			op++;
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 		if (*op == ':') {
12867c478bd9Sstevel@tonic-gate 			for (nop = net_options, op++;
12877c478bd9Sstevel@tonic-gate 			    *op != '\0' && *op != '/' && !ISSPACE(*op) &&
12887c478bd9Sstevel@tonic-gate 			    nop < &net_options[NCT_BUFSIZE]; nop++, op++)
12897c478bd9Sstevel@tonic-gate 				*nop = *op;
12907c478bd9Sstevel@tonic-gate 			*nop = '\0';
12917c478bd9Sstevel@tonic-gate 		} else
12927c478bd9Sstevel@tonic-gate 			net_options[0] = '\0';
12937c478bd9Sstevel@tonic-gate 	}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate #undef	ISSPACE
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	for (i = 0; i < nct_entries; i++)
12987c478bd9Sstevel@tonic-gate 		if (strcmp(net_options, nct[i].p_name) == 0)
12997c478bd9Sstevel@tonic-gate 			return (nct[i].p_id);
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	return (NCT_DEFAULT);
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate /* Modified STREAM routines for ease of porting core TCP code. */
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13077c478bd9Sstevel@tonic-gate mblk_t *
allocb(size_t size,uint_t pri)13087c478bd9Sstevel@tonic-gate allocb(size_t size, uint_t pri)
13097c478bd9Sstevel@tonic-gate {
13107c478bd9Sstevel@tonic-gate 	unsigned char *base;
13117c478bd9Sstevel@tonic-gate 	mblk_t *mp;
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	if ((mp = (mblk_t *)bkmem_zalloc(sizeof (mblk_t))) == NULL)
13147c478bd9Sstevel@tonic-gate 		return (NULL);
13157c478bd9Sstevel@tonic-gate 	if ((base = (unsigned char *)bkmem_zalloc(size)) == NULL)
13167c478bd9Sstevel@tonic-gate 		return (NULL);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	mp->b_next = mp->b_prev = mp->b_cont = NULL;
13197c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr = mp->b_datap = (unsigned char *)base;
13207c478bd9Sstevel@tonic-gate 	mp->b_size = size;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	return (mp);
13237c478bd9Sstevel@tonic-gate }
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate void
freeb(mblk_t * mp)13267c478bd9Sstevel@tonic-gate freeb(mblk_t *mp)
13277c478bd9Sstevel@tonic-gate {
13287c478bd9Sstevel@tonic-gate #ifdef DEBUG
13297c478bd9Sstevel@tonic-gate 	printf("freeb datap %x\n", mp->b_datap);
13307c478bd9Sstevel@tonic-gate #endif
13317c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)(mp->b_datap), mp->b_size);
13327c478bd9Sstevel@tonic-gate #ifdef DEBUG
13337c478bd9Sstevel@tonic-gate 	printf("freeb mp %x\n", mp);
13347c478bd9Sstevel@tonic-gate #endif
13357c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)mp, sizeof (mblk_t));
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate void
freemsg(mblk_t * mp)13397c478bd9Sstevel@tonic-gate freemsg(mblk_t *mp)
13407c478bd9Sstevel@tonic-gate {
13417c478bd9Sstevel@tonic-gate 	while (mp) {
13427c478bd9Sstevel@tonic-gate 		mblk_t *mp_cont = mp->b_cont;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 		freeb(mp);
13457c478bd9Sstevel@tonic-gate 		mp = mp_cont;
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate mblk_t *
copyb(mblk_t * bp)13507c478bd9Sstevel@tonic-gate copyb(mblk_t *bp)
13517c478bd9Sstevel@tonic-gate {
13527c478bd9Sstevel@tonic-gate 	mblk_t *nbp;
13537c478bd9Sstevel@tonic-gate 	unsigned char *ndp;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	assert((uintptr_t)(bp->b_wptr - bp->b_rptr) >= 0);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	if (!(nbp = allocb(bp->b_size, 0)))
13587c478bd9Sstevel@tonic-gate 		return (NULL);
13597c478bd9Sstevel@tonic-gate 	nbp->b_cont = NULL;
13607c478bd9Sstevel@tonic-gate 	ndp = nbp->b_datap;
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	nbp->b_rptr = ndp + (bp->b_rptr - bp->b_datap);
13637c478bd9Sstevel@tonic-gate 	nbp->b_wptr = nbp->b_rptr + (bp->b_wptr - bp->b_rptr);
13647c478bd9Sstevel@tonic-gate 	bcopy(bp->b_datap, nbp->b_datap, bp->b_size);
13657c478bd9Sstevel@tonic-gate 	return (nbp);
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /* To simplify things, dupb() is implemented as copyb(). */
13697c478bd9Sstevel@tonic-gate mblk_t *
dupb(mblk_t * mp)13707c478bd9Sstevel@tonic-gate dupb(mblk_t *mp)
13717c478bd9Sstevel@tonic-gate {
13727c478bd9Sstevel@tonic-gate 	return (copyb(mp));
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate /*
13767c478bd9Sstevel@tonic-gate  * get number of data bytes in message
13777c478bd9Sstevel@tonic-gate  */
13787c478bd9Sstevel@tonic-gate size_t
msgdsize(mblk_t * bp)13797c478bd9Sstevel@tonic-gate msgdsize(mblk_t *bp)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate 	size_t count = 0;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	for (; bp != NULL; bp = bp->b_cont) {
13847c478bd9Sstevel@tonic-gate 		assert(bp->b_wptr >= bp->b_rptr);
13857c478bd9Sstevel@tonic-gate 		count += bp->b_wptr - bp->b_rptr;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 	return (count);
13887c478bd9Sstevel@tonic-gate }
1389