xref: /onnv-gate/usr/src/stand/lib/sock/socket.c (revision 6747:393cf276a040)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6747Sga159272  * Common Development and Distribution License (the "License").
6*6747Sga159272  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6747Sga159272  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * socket.c, Code implementing a simple socket interface.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include "socket_impl.h"
320Sstevel@tonic-gate #include <sys/isa_defs.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/bootconf.h>
350Sstevel@tonic-gate #include <sys/socket.h>
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <netinet/ip.h>
380Sstevel@tonic-gate #include <netinet/tcp.h>
390Sstevel@tonic-gate #include <sys/uio.h>
400Sstevel@tonic-gate #include <sys/salib.h>
410Sstevel@tonic-gate #include "socket_inet.h"
420Sstevel@tonic-gate #include "ipv4.h"
430Sstevel@tonic-gate #include "ipv4_impl.h"
440Sstevel@tonic-gate #include "udp_inet.h"
450Sstevel@tonic-gate #include "tcp_inet.h"
460Sstevel@tonic-gate #include "mac.h"
470Sstevel@tonic-gate #include "mac_impl.h"
480Sstevel@tonic-gate #include <sys/promif.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate struct inetboot_socket	sockets[MAXSOCKET] = { 0 };
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* Default send and receive socket buffer size */
530Sstevel@tonic-gate #define	SO_DEF_SNDBUF	48*1024
540Sstevel@tonic-gate #define	SO_DEF_RCVBUF	48*1024
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /* Default max socket buffer size */
570Sstevel@tonic-gate #define	SO_MAX_BUF	4*1024*1024
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static ssize_t dgram_sendto(int, const void *, size_t, int,
600Sstevel@tonic-gate     const struct sockaddr *, int);
610Sstevel@tonic-gate static ssize_t stream_sendto(int, const void *, size_t, int);
620Sstevel@tonic-gate static int bind_check(int, const struct sockaddr *);
630Sstevel@tonic-gate static int quickbind(int);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /* Check the validity of a fd and return the socket index of that fd. */
660Sstevel@tonic-gate int
so_check_fd(int fd,int * errno)670Sstevel@tonic-gate so_check_fd(int fd, int *errno)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	int i;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	i = FD_TO_SOCKET(fd);
720Sstevel@tonic-gate 	if (i < 0 || i >= MAXSOCKET) {
730Sstevel@tonic-gate 		*errno = ENOTSOCK;
740Sstevel@tonic-gate 		return (-1);
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_UNUSED) {
770Sstevel@tonic-gate 		*errno = ENOTSOCK;
780Sstevel@tonic-gate 		return (-1);
790Sstevel@tonic-gate 	}
800Sstevel@tonic-gate 	return (i);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * Create an endpoint for network communication. Returns a descriptor.
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  * Notes:
870Sstevel@tonic-gate  *	Only PF_INET communication domains are supported. Within
880Sstevel@tonic-gate  * 	this domain, only SOCK_RAW, SOCK_DGRAM and SOCK_STREAM types are
890Sstevel@tonic-gate  *	supported.
900Sstevel@tonic-gate  */
910Sstevel@tonic-gate int
socket(int domain,int type,int protocol)920Sstevel@tonic-gate socket(int domain, int type, int protocol)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	static int sock_initialized;
950Sstevel@tonic-gate 	int i;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	errno = 0;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	if (!sock_initialized) {
1000Sstevel@tonic-gate 		for (i = 0; i < MAXSOCKET; i++)
1010Sstevel@tonic-gate 			sockets[i].type = INETBOOT_UNUSED;
1020Sstevel@tonic-gate 		sock_initialized = B_TRUE;
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 	if (domain != AF_INET) {
1050Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
1060Sstevel@tonic-gate 		return (-1);
1070Sstevel@tonic-gate 	}
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	/* Find available socket */
1100Sstevel@tonic-gate 	for (i = 0; i < MAXSOCKET; i++) {
1110Sstevel@tonic-gate 		if (sockets[i].type == INETBOOT_UNUSED)
1120Sstevel@tonic-gate 			break;
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	if (i >= MAXSOCKET) {
1150Sstevel@tonic-gate 		errno = EMFILE;	/* No slots left. */
1160Sstevel@tonic-gate 		return (-1);
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* Some socket initialization... */
1200Sstevel@tonic-gate 	sockets[i].so_rcvbuf = SO_DEF_RCVBUF;
1210Sstevel@tonic-gate 	sockets[i].so_sndbuf = SO_DEF_SNDBUF;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * Note that we ignore the protocol field for SOCK_DGRAM and
1250Sstevel@tonic-gate 	 * SOCK_STREAM.  When we support different protocols in future,
1260Sstevel@tonic-gate 	 * this needs to be changed.
1270Sstevel@tonic-gate 	 */
1280Sstevel@tonic-gate 	switch (type) {
1290Sstevel@tonic-gate 	case SOCK_RAW:
1300Sstevel@tonic-gate 		ipv4_raw_socket(&sockets[i], (uint8_t)protocol);
1310Sstevel@tonic-gate 		break;
1320Sstevel@tonic-gate 	case SOCK_DGRAM:
1330Sstevel@tonic-gate 		udp_socket_init(&sockets[i]);
1340Sstevel@tonic-gate 		break;
1350Sstevel@tonic-gate 	case SOCK_STREAM:
1360Sstevel@tonic-gate 		tcp_socket_init(&sockets[i]);
1370Sstevel@tonic-gate 		break;
1380Sstevel@tonic-gate 	default:
1390Sstevel@tonic-gate 		errno = EPROTOTYPE;
1400Sstevel@tonic-gate 		break;
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if (errno != 0)
1440Sstevel@tonic-gate 		return (-1);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	/* IPv4 generic initialization. */
1470Sstevel@tonic-gate 	ipv4_socket_init(&sockets[i]);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/* MAC generic initialization. */
1500Sstevel@tonic-gate 	mac_socket_init(&sockets[i]);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	return (i + SOCKETTYPE);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate int
getsockname(int s,struct sockaddr * name,socklen_t * namelen)1560Sstevel@tonic-gate getsockname(int s, struct sockaddr *name,  socklen_t *namelen)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	int i;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	errno = 0;
1610Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
1620Sstevel@tonic-gate 		return (-1);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (*namelen < sizeof (struct sockaddr_in)) {
1650Sstevel@tonic-gate 		errno = ENOMEM;
1660Sstevel@tonic-gate 		return (-1);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/* Structure assignment... */
1700Sstevel@tonic-gate 	*((struct sockaddr_in *)name) = sockets[i].bind;
1710Sstevel@tonic-gate 	*namelen = sizeof (struct sockaddr_in);
1720Sstevel@tonic-gate 	return (0);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate  * The socket options we support are:
1770Sstevel@tonic-gate  * SO_RCVTIMEO	-	Value is in msecs, and is of uint32_t.
1780Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is an int, and is a boolean (nonzero if set).
1790Sstevel@tonic-gate  * SO_REUSEADDR -	Value is an int boolean.
1800Sstevel@tonic-gate  * SO_RCVBUF -		Value is an int.
1810Sstevel@tonic-gate  * SO_SNDBUF -		Value is an int.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate int
getsockopt(int s,int level,int option,void * optval,socklen_t * optlen)1840Sstevel@tonic-gate getsockopt(int s, int level, int option, void *optval, socklen_t *optlen)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	int i;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	errno = 0;
1890Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
1900Sstevel@tonic-gate 		return (-1);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	switch (level) {
1930Sstevel@tonic-gate 	case SOL_SOCKET: {
1940Sstevel@tonic-gate 		switch (option) {
1950Sstevel@tonic-gate 		case SO_RCVTIMEO:
1960Sstevel@tonic-gate 			if (*optlen == sizeof (uint32_t)) {
1970Sstevel@tonic-gate 				*(uint32_t *)optval = sockets[i].in_timeout;
1980Sstevel@tonic-gate 			} else {
1990Sstevel@tonic-gate 				*optlen = 0;
2000Sstevel@tonic-gate 				errno = EINVAL;
2010Sstevel@tonic-gate 			}
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 		case SO_DONTROUTE:
2040Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2050Sstevel@tonic-gate 				*(int *)optval =
2060Sstevel@tonic-gate 				    (sockets[i].out_flags & SO_DONTROUTE);
2070Sstevel@tonic-gate 			} else {
2080Sstevel@tonic-gate 				*optlen = 0;
2090Sstevel@tonic-gate 				errno = EINVAL;
2100Sstevel@tonic-gate 			}
2110Sstevel@tonic-gate 			break;
2120Sstevel@tonic-gate 		case SO_REUSEADDR:
2130Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2140Sstevel@tonic-gate 				*(int *)optval =
2150Sstevel@tonic-gate 				    (sockets[i].so_opt & SO_REUSEADDR);
2160Sstevel@tonic-gate 			} else {
2170Sstevel@tonic-gate 				*optlen = 0;
2180Sstevel@tonic-gate 				errno = EINVAL;
2190Sstevel@tonic-gate 			}
2200Sstevel@tonic-gate 			break;
2210Sstevel@tonic-gate 		case SO_RCVBUF:
2220Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2230Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_rcvbuf;
2240Sstevel@tonic-gate 			} else {
2250Sstevel@tonic-gate 				*optlen = 0;
2260Sstevel@tonic-gate 				errno = EINVAL;
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 			break;
2290Sstevel@tonic-gate 		case SO_SNDBUF:
2300Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
2310Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_sndbuf;
2320Sstevel@tonic-gate 			} else {
2330Sstevel@tonic-gate 				*optlen = 0;
2340Sstevel@tonic-gate 				errno = EINVAL;
2350Sstevel@tonic-gate 			}
2360Sstevel@tonic-gate 			break;
2370Sstevel@tonic-gate 		case SO_LINGER:
2380Sstevel@tonic-gate 			if (*optlen == sizeof (struct linger)) {
2390Sstevel@tonic-gate 				/* struct copy */
2400Sstevel@tonic-gate 				*(struct linger *)optval = sockets[i].so_linger;
2410Sstevel@tonic-gate 			} else {
2420Sstevel@tonic-gate 				*optlen = 0;
2430Sstevel@tonic-gate 				errno = EINVAL;
2440Sstevel@tonic-gate 			}
2450Sstevel@tonic-gate 		default:
2460Sstevel@tonic-gate 			errno = ENOPROTOOPT;
2470Sstevel@tonic-gate 			break;
2480Sstevel@tonic-gate 		}
2490Sstevel@tonic-gate 		break;
2500Sstevel@tonic-gate 	} /* case SOL_SOCKET */
2510Sstevel@tonic-gate 	case IPPROTO_TCP:
2520Sstevel@tonic-gate 	case IPPROTO_IP: {
2530Sstevel@tonic-gate 		switch (option) {
2540Sstevel@tonic-gate 		default:
2550Sstevel@tonic-gate 			*optlen = 0;
2560Sstevel@tonic-gate 			errno = ENOPROTOOPT;
2570Sstevel@tonic-gate 			break;
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 		break;
2600Sstevel@tonic-gate 	} /* case IPPROTO_IP or IPPROTO_TCP */
2610Sstevel@tonic-gate 	default:
2620Sstevel@tonic-gate 		errno = ENOPROTOOPT;
2630Sstevel@tonic-gate 		break;
2640Sstevel@tonic-gate 	} /* switch (level) */
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if (errno != 0)
2670Sstevel@tonic-gate 		return (-1);
2680Sstevel@tonic-gate 	else
2690Sstevel@tonic-gate 		return (0);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate  * Generate a network-order source port from the privileged range if
2740Sstevel@tonic-gate  * "reserved" is true, dynamic/private range otherwise. We consider the
2750Sstevel@tonic-gate  * range of 512-1023 privileged ports as ports we can use. This mirrors
2760Sstevel@tonic-gate  * historical rpc client practice for privileged port selection.
2770Sstevel@tonic-gate  */
2780Sstevel@tonic-gate in_port_t
get_source_port(boolean_t reserved)2790Sstevel@tonic-gate get_source_port(boolean_t reserved)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	static in_port_t	dynamic = IPPORT_DYNAMIC_START - 1,
282*6747Sga159272 	    rsvdport = (IPPORT_RESERVED / 2) - 1;
2830Sstevel@tonic-gate 	in_port_t		p;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	if (reserved) {
2860Sstevel@tonic-gate 		if (++rsvdport >= IPPORT_RESERVED)
2870Sstevel@tonic-gate 			p = rsvdport = IPPORT_RESERVED / 2;
2880Sstevel@tonic-gate 		else
2890Sstevel@tonic-gate 			p = rsvdport;
2900Sstevel@tonic-gate 	} else
2910Sstevel@tonic-gate 		p = ++dynamic;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	return (htons(p));
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * The socket options we support are:
2980Sstevel@tonic-gate  * SO_RECVTIMEO	-	Value is uint32_t msecs.
2990Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is int boolean (nonzero == TRUE, zero == FALSE).
3000Sstevel@tonic-gate  * SO_REUSEADDR -	value is int boolean.
3010Sstevel@tonic-gate  * SO_RCVBUF -		Value is int.
3020Sstevel@tonic-gate  * SO_SNDBUF -		Value is int.
3030Sstevel@tonic-gate  */
3040Sstevel@tonic-gate int
setsockopt(int s,int level,int option,const void * optval,socklen_t optlen)3050Sstevel@tonic-gate setsockopt(int s, int level, int option, const void *optval, socklen_t optlen)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	int i;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	errno = 0;
3100Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
3110Sstevel@tonic-gate 		return (-1);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	switch (level) {
3140Sstevel@tonic-gate 	case SOL_SOCKET: {
3150Sstevel@tonic-gate 		switch (option) {
3160Sstevel@tonic-gate 		case SO_RCVTIMEO:
3170Sstevel@tonic-gate 			if (optlen == sizeof (uint32_t))
3180Sstevel@tonic-gate 				sockets[i].in_timeout = *(uint32_t *)optval;
3190Sstevel@tonic-gate 			else {
3200Sstevel@tonic-gate 				errno = EINVAL;
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 			break;
3230Sstevel@tonic-gate 		case SO_DONTROUTE:
3240Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3250Sstevel@tonic-gate 				if (*(int *)optval)
3260Sstevel@tonic-gate 					sockets[i].out_flags |= SO_DONTROUTE;
3270Sstevel@tonic-gate 				else
3280Sstevel@tonic-gate 					sockets[i].out_flags &= ~SO_DONTROUTE;
3290Sstevel@tonic-gate 			} else {
3300Sstevel@tonic-gate 				errno = EINVAL;
3310Sstevel@tonic-gate 			}
3320Sstevel@tonic-gate 			break;
3330Sstevel@tonic-gate 		case SO_REUSEADDR:
3340Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3350Sstevel@tonic-gate 				if (*(int *)optval)
3360Sstevel@tonic-gate 					sockets[i].so_opt |= SO_REUSEADDR;
3370Sstevel@tonic-gate 				else
3380Sstevel@tonic-gate 					sockets[i].so_opt &= ~SO_REUSEADDR;
3390Sstevel@tonic-gate 			} else {
3400Sstevel@tonic-gate 				errno = EINVAL;
3410Sstevel@tonic-gate 			}
3420Sstevel@tonic-gate 			break;
3430Sstevel@tonic-gate 		case SO_RCVBUF:
3440Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3450Sstevel@tonic-gate 				sockets[i].so_rcvbuf = *(int *)optval;
3460Sstevel@tonic-gate 				if (sockets[i].so_rcvbuf > SO_MAX_BUF)
3470Sstevel@tonic-gate 					sockets[i].so_rcvbuf = SO_MAX_BUF;
3480Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3490Sstevel@tonic-gate 				    level, option, optval, optlen);
3500Sstevel@tonic-gate 			} else {
3510Sstevel@tonic-gate 				errno = EINVAL;
3520Sstevel@tonic-gate 			}
3530Sstevel@tonic-gate 			break;
3540Sstevel@tonic-gate 		case SO_SNDBUF:
3550Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
3560Sstevel@tonic-gate 				sockets[i].so_sndbuf = *(int *)optval;
3570Sstevel@tonic-gate 				if (sockets[i].so_sndbuf > SO_MAX_BUF)
3580Sstevel@tonic-gate 					sockets[i].so_sndbuf = SO_MAX_BUF;
3590Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3600Sstevel@tonic-gate 				    level, option, optval, optlen);
3610Sstevel@tonic-gate 			} else {
3620Sstevel@tonic-gate 				errno = EINVAL;
3630Sstevel@tonic-gate 			}
3640Sstevel@tonic-gate 			break;
3650Sstevel@tonic-gate 		case SO_LINGER:
3660Sstevel@tonic-gate 			if (optlen == sizeof (struct linger)) {
3670Sstevel@tonic-gate 				/* struct copy */
3680Sstevel@tonic-gate 				sockets[i].so_linger = *(struct linger *)optval;
3690Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
3700Sstevel@tonic-gate 				    level, option, optval, optlen);
3710Sstevel@tonic-gate 			} else {
3720Sstevel@tonic-gate 				errno = EINVAL;
3730Sstevel@tonic-gate 			}
3740Sstevel@tonic-gate 			break;
3750Sstevel@tonic-gate 		default:
3760Sstevel@tonic-gate 			errno = ENOPROTOOPT;
3770Sstevel@tonic-gate 			break;
3780Sstevel@tonic-gate 		}
3790Sstevel@tonic-gate 		break;
3800Sstevel@tonic-gate 	} /* case SOL_SOCKET */
3810Sstevel@tonic-gate 	case IPPROTO_TCP:
3820Sstevel@tonic-gate 	case IPPROTO_IP: {
3830Sstevel@tonic-gate 		switch (option) {
3840Sstevel@tonic-gate 		default:
3850Sstevel@tonic-gate 			errno = ENOPROTOOPT;
3860Sstevel@tonic-gate 			break;
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 		break;
3890Sstevel@tonic-gate 	} /* case IPPROTO_IP  or IPPROTO_TCP */
3900Sstevel@tonic-gate 	default:
3910Sstevel@tonic-gate 		errno = ENOPROTOOPT;
3920Sstevel@tonic-gate 		break;
3930Sstevel@tonic-gate 	} /* switch (level) */
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (errno != 0)
3960Sstevel@tonic-gate 		return (-1);
3970Sstevel@tonic-gate 	else
3980Sstevel@tonic-gate 		return (0);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * Shut down part of a full-duplex connection.
4030Sstevel@tonic-gate  *
4040Sstevel@tonic-gate  * Only supported for TCP sockets
4050Sstevel@tonic-gate  */
4060Sstevel@tonic-gate int
shutdown(int s,int how)4070Sstevel@tonic-gate shutdown(int s, int how)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 	int sock_id;
4100Sstevel@tonic-gate 	int i;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	errno = 0;
4130Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
4140Sstevel@tonic-gate 		return (-1);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/* shutdown only supported for TCP sockets */
4170Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
4180Sstevel@tonic-gate 		errno = EOPNOTSUPP;
4190Sstevel@tonic-gate 		return (-1);
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (!(sockets[sock_id].so_state & SS_ISCONNECTED)) {
4230Sstevel@tonic-gate 		errno = ENOTCONN;
4240Sstevel@tonic-gate 		return (-1);
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	switch (how) {
4280Sstevel@tonic-gate 	case 0:
4290Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTRCVMORE;
4300Sstevel@tonic-gate 		break;
4310Sstevel@tonic-gate 	case 1:
4320Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTSENDMORE;
4330Sstevel@tonic-gate 		break;
4340Sstevel@tonic-gate 	case 2:
4350Sstevel@tonic-gate 		sockets[sock_id].so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE);
4360Sstevel@tonic-gate 		break;
4370Sstevel@tonic-gate 	default:
4380Sstevel@tonic-gate 		errno = EINVAL;
4390Sstevel@tonic-gate 		return (-1);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	switch (sockets[sock_id].so_state &
443*6747Sga159272 	    (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
4440Sstevel@tonic-gate 	case (SS_CANTRCVMORE | SS_CANTSENDMORE):
4450Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
4460Sstevel@tonic-gate 		for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4470Sstevel@tonic-gate 			if (sockets[sock_id].close[i] != NULL) {
4480Sstevel@tonic-gate 				(void) sockets[sock_id].close[i](sock_id);
4490Sstevel@tonic-gate 			}
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
4520Sstevel@tonic-gate 		break;
4530Sstevel@tonic-gate 	case SS_CANTRCVMORE:
4540Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
4550Sstevel@tonic-gate 		break;
4560Sstevel@tonic-gate 	case SS_CANTSENDMORE:
4570Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
4580Sstevel@tonic-gate 		if (tcp_shutdown(sock_id) < 0)
4590Sstevel@tonic-gate 			return (-1);
4600Sstevel@tonic-gate 		break;
4610Sstevel@tonic-gate 	default:
4620Sstevel@tonic-gate 		errno = EINVAL;
4630Sstevel@tonic-gate 		return (-1);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	return (0);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate  * "close" a socket.
4710Sstevel@tonic-gate  */
4720Sstevel@tonic-gate int
socket_close(int s)4730Sstevel@tonic-gate socket_close(int s)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate 	int sock_id, i;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	errno = 0;
4780Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
4790Sstevel@tonic-gate 		return (-1);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/* Call lower level protocol close routine. */
4820Sstevel@tonic-gate 	for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4830Sstevel@tonic-gate 		if (sockets[sock_id].close[i] != NULL) {
4840Sstevel@tonic-gate 			/*
4850Sstevel@tonic-gate 			 * Note that the close() routine of other
4860Sstevel@tonic-gate 			 * layers can return an error.  But right
4870Sstevel@tonic-gate 			 * now, the only mechanism to report that
4880Sstevel@tonic-gate 			 * back is for the close() routine to set
4890Sstevel@tonic-gate 			 * the errno and socket_close() will return
4900Sstevel@tonic-gate 			 * an error.  But the close operation will
4910Sstevel@tonic-gate 			 * not be stopped.
4920Sstevel@tonic-gate 			 */
4930Sstevel@tonic-gate 			(void) sockets[sock_id].close[i](sock_id);
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * Clear the input queue.  This has to be done
4990Sstevel@tonic-gate 	 * after the lower level protocol close routines have been
5000Sstevel@tonic-gate 	 * called as they may want to do something about the queue.
5010Sstevel@tonic-gate 	 */
5020Sstevel@tonic-gate 	nuke_grams(&sockets[sock_id].inq);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	bzero((caddr_t)&sockets[sock_id], sizeof (struct inetboot_socket));
5050Sstevel@tonic-gate 	sockets[sock_id].type = INETBOOT_UNUSED;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	return (0);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * Read up to `nbyte' of data from socket `s' into `buf'; if non-zero,
5120Sstevel@tonic-gate  * then give up after `read_timeout' seconds.  Returns the number of
5130Sstevel@tonic-gate  * bytes read, or -1 on failure.
5140Sstevel@tonic-gate  */
5150Sstevel@tonic-gate int
socket_read(int s,void * buf,size_t nbyte,int read_timeout)5160Sstevel@tonic-gate socket_read(int s, void *buf, size_t nbyte, int read_timeout)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	ssize_t	n;
5190Sstevel@tonic-gate 	uint_t	start, diff;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	/*
5220Sstevel@tonic-gate 	 * keep calling non-blocking recvfrom until something received
5230Sstevel@tonic-gate 	 * or an error occurs
5240Sstevel@tonic-gate 	 */
5250Sstevel@tonic-gate 	start = prom_gettime();
526517Sjk115741 	for (;;) {
527517Sjk115741 		n = recvfrom(s, buf, nbyte, MSG_DONTWAIT, NULL, NULL);
528517Sjk115741 		if (n == -1 && errno == EWOULDBLOCK) {
529517Sjk115741 			diff = (uint_t)((prom_gettime() - start) + 500) / 1000;
530517Sjk115741 			if (read_timeout != 0 && diff > read_timeout) {
531517Sjk115741 				errno = EINTR;
532517Sjk115741 				return (-1);
533517Sjk115741 			}
534517Sjk115741 		} else {
535517Sjk115741 			return (n);
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate /*
5410Sstevel@tonic-gate  * Write up to `nbyte' bytes of data from `buf' to the address pointed to
5420Sstevel@tonic-gate  * `addr' using socket `s'.  Returns the number of bytes writte on success,
5430Sstevel@tonic-gate  * or -1 on failure.
5440Sstevel@tonic-gate  */
5450Sstevel@tonic-gate int
socket_write(int s,const void * buf,size_t nbyte,struct sockaddr_in * addr)5460Sstevel@tonic-gate socket_write(int s, const void *buf, size_t nbyte, struct sockaddr_in *addr)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	return (sendto(s, buf, nbyte, 0, (struct sockaddr *)addr,
5490Sstevel@tonic-gate 	    sizeof (*addr)));
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate static int
bind_check(int sock_id,const struct sockaddr * addr)5530Sstevel@tonic-gate bind_check(int sock_id, const struct sockaddr *addr)
5540Sstevel@tonic-gate {
5550Sstevel@tonic-gate 	int k;
5560Sstevel@tonic-gate 	struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/* Do not check for duplicate bind() if SO_REUSEADDR option is set. */
5590Sstevel@tonic-gate 	if (! (sockets[sock_id].so_opt & SO_REUSEADDR)) {
5600Sstevel@tonic-gate 		for (k = 0; k < MAXSOCKET; k++) {
5610Sstevel@tonic-gate 			if (sockets[k].type != INETBOOT_UNUSED &&
5620Sstevel@tonic-gate 			    sockets[k].proto == sockets[sock_id].proto &&
5630Sstevel@tonic-gate 			    sockets[k].bound) {
5640Sstevel@tonic-gate 				if ((sockets[k].bind.sin_addr.s_addr ==
5650Sstevel@tonic-gate 				    in_addr->sin_addr.s_addr) &&
5660Sstevel@tonic-gate 				    (sockets[k].bind.sin_port ==
5670Sstevel@tonic-gate 				    in_addr->sin_port)) {
5680Sstevel@tonic-gate 					errno = EADDRINUSE;
5690Sstevel@tonic-gate 					return (-1);
5700Sstevel@tonic-gate 				}
5710Sstevel@tonic-gate 			}
5720Sstevel@tonic-gate 		}
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 	return (0);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate /* Assign a name to an unnamed socket. */
5780Sstevel@tonic-gate int
bind(int s,const struct sockaddr * name,socklen_t namelen)5790Sstevel@tonic-gate bind(int s, const struct sockaddr *name, socklen_t namelen)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	int i;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	errno = 0;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
5860Sstevel@tonic-gate 		return (-1);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (name == NULL) {
5890Sstevel@tonic-gate 		/* unbind */
5900Sstevel@tonic-gate 		if (sockets[i].bound) {
5910Sstevel@tonic-gate 			bzero((caddr_t)&sockets[i].bind,
5920Sstevel@tonic-gate 			    sizeof (struct sockaddr_in));
5930Sstevel@tonic-gate 			sockets[i].bound = B_FALSE;
5940Sstevel@tonic-gate 		}
5950Sstevel@tonic-gate 		return (0);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 	if (namelen != sizeof (struct sockaddr_in) || name == NULL) {
5980Sstevel@tonic-gate 		errno = EINVAL;
5990Sstevel@tonic-gate 		return (-1);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 	if (name->sa_family != AF_INET) {
6020Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
6030Sstevel@tonic-gate 		return (-1);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 	if (sockets[i].bound) {
6060Sstevel@tonic-gate 		if (bcmp((caddr_t)&sockets[i].bind, (caddr_t)name,
6070Sstevel@tonic-gate 		    namelen) == 0) {
6080Sstevel@tonic-gate 			/* attempt to bind to same address ok... */
6090Sstevel@tonic-gate 			return (0);
6100Sstevel@tonic-gate 		}
6110Sstevel@tonic-gate 		errno = EINVAL;	/* already bound */
6120Sstevel@tonic-gate 		return (-1);
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (errno != 0) {
6160Sstevel@tonic-gate 		return (-1);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/* Check for duplicate bind(). */
6200Sstevel@tonic-gate 	if (bind_check(i, name) < 0)
6210Sstevel@tonic-gate 		return (-1);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	bcopy((caddr_t)name, (caddr_t)&sockets[i].bind, namelen);
6240Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_STREAM) {
6250Sstevel@tonic-gate 		if (tcp_bind(i) < 0) {
6260Sstevel@tonic-gate 			return (-1);
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	sockets[i].bound = B_TRUE;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	return (0);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate static int
quickbind(int sock_id)6350Sstevel@tonic-gate quickbind(int sock_id)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	int i;
6380Sstevel@tonic-gate 	struct sockaddr_in addr;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
6410Sstevel@tonic-gate 	 * XXX This needs more work.  Right now, if ipv4_setipaddr()
6420Sstevel@tonic-gate 	 * have not been called, this will be wrong.  But we need
6430Sstevel@tonic-gate 	 * something better.  Need to be revisited.
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	ipv4_getipaddr(&addr.sin_addr);
6460Sstevel@tonic-gate 	addr.sin_family = AF_INET;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	for (i = SMALLEST_ANON_PORT; i <= LARGEST_ANON_PORT; i++) {
6490Sstevel@tonic-gate 		addr.sin_port = htons(i);
6500Sstevel@tonic-gate 		if (bind_check(sock_id, (struct sockaddr *)&addr) == 0)
6510Sstevel@tonic-gate 			break;
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 	/* Need to clear errno as it is probably set by bind_check(). */
6540Sstevel@tonic-gate 	errno = 0;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (i <= LARGEST_ANON_PORT) {
6570Sstevel@tonic-gate 		bcopy((caddr_t)&addr, (caddr_t)&sockets[sock_id].bind,
6580Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
6590Sstevel@tonic-gate 		sockets[sock_id].bound = B_TRUE;
6600Sstevel@tonic-gate #ifdef DEBUG
6610Sstevel@tonic-gate 		printf("quick bind done addr %s port %d\n",
6620Sstevel@tonic-gate 		    inet_ntoa(sockets[sock_id].bind.sin_addr),
663*6747Sga159272 		    ntohs(sockets[sock_id].bind.sin_port));
6640Sstevel@tonic-gate #endif
6650Sstevel@tonic-gate 		return (0);
6660Sstevel@tonic-gate 	} else {
6670Sstevel@tonic-gate 		return (-1);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate int
listen(int fd,int backlog)6720Sstevel@tonic-gate listen(int fd, int backlog)
6730Sstevel@tonic-gate {
6740Sstevel@tonic-gate 	int sock_id;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	errno = 0;
6770Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
6780Sstevel@tonic-gate 		return (-1);
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
6810Sstevel@tonic-gate 		errno = EOPNOTSUPP;
6820Sstevel@tonic-gate 		return (-1);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
6850Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
6860Sstevel@tonic-gate 		return (-1);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 	return (tcp_listen(sock_id, backlog));
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate int
accept(int fd,struct sockaddr * addr,socklen_t * addr_len)6920Sstevel@tonic-gate accept(int fd, struct sockaddr *addr,  socklen_t *addr_len)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate 	int sock_id;
6950Sstevel@tonic-gate 	int new_sd;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	errno = 0;
6980Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
6990Sstevel@tonic-gate 		return (-1);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
7020Sstevel@tonic-gate 		errno = EOPNOTSUPP;
7030Sstevel@tonic-gate 		return (-1);
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
7060Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
7070Sstevel@tonic-gate 		return (-1);
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 	if ((new_sd = tcp_accept(sock_id, addr, addr_len)) == -1)
7100Sstevel@tonic-gate 		return (-1);
7110Sstevel@tonic-gate 	sock_id = so_check_fd(new_sd, &errno);
7120Sstevel@tonic-gate 	sockets[sock_id].so_state |= SS_ISCONNECTED;
7130Sstevel@tonic-gate 	return (new_sd);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate int
connect(int fd,const struct sockaddr * addr,socklen_t addr_len)7170Sstevel@tonic-gate connect(int fd, const  struct sockaddr *addr, socklen_t addr_len)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	int sock_id;
7200Sstevel@tonic-gate 	int so_type;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	errno = 0;
7230Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
7240Sstevel@tonic-gate 		return (-1);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (addr == NULL || addr_len == 0) {
7290Sstevel@tonic-gate 		errno = EINVAL;
7300Sstevel@tonic-gate 		return (-1);
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 	/* Don't allow connect for raw socket. */
7330Sstevel@tonic-gate 	if (so_type == INETBOOT_RAW) {
7340Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
7350Sstevel@tonic-gate 		return (-1);
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	if (sockets[sock_id].so_state & SS_ISCONNECTED) {
7390Sstevel@tonic-gate 		errno = EINVAL;
7400Sstevel@tonic-gate 		return (-1);
7410Sstevel@tonic-gate 	}
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
7440Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
7450Sstevel@tonic-gate 		return (-1);
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	/* If the socket is not bound, we need to do a quick bind. */
7490Sstevel@tonic-gate 	if (!sockets[sock_id].bound) {
7500Sstevel@tonic-gate 		/* For TCP socket, just call tcp_bind(). */
7510Sstevel@tonic-gate 		if (so_type == INETBOOT_STREAM) {
7520Sstevel@tonic-gate 			if (tcp_bind(sock_id) < 0)
7530Sstevel@tonic-gate 				return (-1);
7540Sstevel@tonic-gate 		} else {
7550Sstevel@tonic-gate 			if (quickbind(sock_id) < 0) {
7560Sstevel@tonic-gate 				errno = EADDRNOTAVAIL;
7570Sstevel@tonic-gate 				return (-1);
7580Sstevel@tonic-gate 			}
7590Sstevel@tonic-gate 		}
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 	/* Should do some sanity check for addr .... */
7620Sstevel@tonic-gate 	bcopy((caddr_t)addr, &sockets[sock_id].remote,
7630Sstevel@tonic-gate 	    sizeof (struct sockaddr_in));
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM) {
7660Sstevel@tonic-gate 		/* Call TCP connect routine. */
7670Sstevel@tonic-gate 		if (tcp_connect(sock_id) == 0)
7680Sstevel@tonic-gate 			sockets[sock_id].so_state |= SS_ISCONNECTED;
7690Sstevel@tonic-gate 		else {
7700Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0)
7710Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
7720Sstevel@tonic-gate 			return (-1);
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 	} else {
7750Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_ISCONNECTED;
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 	return (0);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate /* Just a wrapper around recvfrom(). */
7810Sstevel@tonic-gate ssize_t
recv(int s,void * buf,size_t len,int flags)7820Sstevel@tonic-gate recv(int s, void *buf, size_t len, int flags)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	return (recvfrom(s, buf, len, flags, NULL, NULL));
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate /*
7880Sstevel@tonic-gate  * Receive messages from a connectionless socket. Legal flags are 0 and
7890Sstevel@tonic-gate  * MSG_DONTWAIT. MSG_WAITALL is not currently supported.
7900Sstevel@tonic-gate  *
7910Sstevel@tonic-gate  * Returns length of message for success, -1 if error occurred.
7920Sstevel@tonic-gate  */
7930Sstevel@tonic-gate ssize_t
recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)7940Sstevel@tonic-gate recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
7950Sstevel@tonic-gate     socklen_t *fromlen)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	int			sock_id, i;
7980Sstevel@tonic-gate 	ssize_t			datalen, bytes = 0;
7990Sstevel@tonic-gate 	struct inetgram		*icp;
8000Sstevel@tonic-gate 	enum SockType		so_type;
8010Sstevel@tonic-gate 	char			*tmp_buf;
8020Sstevel@tonic-gate 	mblk_t			*mp;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	errno = 0;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
8070Sstevel@tonic-gate 		errno = EINVAL;
8080Sstevel@tonic-gate 		return (-1);
8090Sstevel@tonic-gate 	}
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM &&
8120Sstevel@tonic-gate 	    !(sockets[sock_id].so_state & SS_ISCONNECTED)) {
8130Sstevel@tonic-gate 		errno = ENOTCONN;
8140Sstevel@tonic-gate 		return (-1);
8150Sstevel@tonic-gate 	}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	if (buf == NULL || len == 0) {
8180Sstevel@tonic-gate 		errno = EINVAL;
8190Sstevel@tonic-gate 		return (-1);
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 	/* Yup - MSG_WAITALL not implemented */
8220Sstevel@tonic-gate 	if ((flags & ~MSG_DONTWAIT) != 0) {
8230Sstevel@tonic-gate 		errno = EINVAL;
8240Sstevel@tonic-gate 		return (-1);
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate retry:
8280Sstevel@tonic-gate 	if (sockets[sock_id].inq == NULL) {
8290Sstevel@tonic-gate 		/* Go out and check the wire */
8300Sstevel@tonic-gate 		for (i = MEDIA_LVL; i < APP_LVL; i++) {
8310Sstevel@tonic-gate 			if (sockets[sock_id].input[i] != NULL) {
8320Sstevel@tonic-gate 				if (sockets[sock_id].input[i](sock_id) < 0) {
8330Sstevel@tonic-gate 					if (sockets[sock_id].so_error != 0) {
8340Sstevel@tonic-gate 						errno =
8350Sstevel@tonic-gate 						    sockets[sock_id].so_error;
8360Sstevel@tonic-gate 					}
8370Sstevel@tonic-gate 					return (-1);
8380Sstevel@tonic-gate 				}
8390Sstevel@tonic-gate 			}
8400Sstevel@tonic-gate 		}
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	/* Remove unknown inetgrams from the head of inq.  Can this happen? */
8460Sstevel@tonic-gate 	while ((icp = sockets[sock_id].inq) != NULL) {
8470Sstevel@tonic-gate 		if ((so_type == INETBOOT_DGRAM ||
8480Sstevel@tonic-gate 		    so_type == INETBOOT_STREAM) &&
8490Sstevel@tonic-gate 		    icp->igm_level != APP_LVL) {
8500Sstevel@tonic-gate #ifdef	DEBUG
8510Sstevel@tonic-gate 			printf("recvfrom: unexpected level %d frame found\n",
8520Sstevel@tonic-gate 			    icp->igm_level);
8530Sstevel@tonic-gate #endif	/* DEBUG */
8540Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
8550Sstevel@tonic-gate 			continue;
8560Sstevel@tonic-gate 		} else {
8570Sstevel@tonic-gate 			break;
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	if (icp == NULL) {
8630Sstevel@tonic-gate 		/*
8640Sstevel@tonic-gate 		 * Checking for error should be done everytime a lower layer
8650Sstevel@tonic-gate 		 * input routing is called.  For example, if TCP gets a RST,
8660Sstevel@tonic-gate 		 * this should be reported asap.
8670Sstevel@tonic-gate 		 */
8680Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTRCVMORE) {
8690Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0) {
8700Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
8710Sstevel@tonic-gate 				return (-1);
8720Sstevel@tonic-gate 			} else {
8730Sstevel@tonic-gate 				return (0);
8740Sstevel@tonic-gate 			}
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		if ((flags & MSG_DONTWAIT) == 0)
8780Sstevel@tonic-gate 			goto retry;	/* wait forever */
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		/* no data */
8810Sstevel@tonic-gate 		errno = EWOULDBLOCK;
8820Sstevel@tonic-gate 		return (-1);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	if (from != NULL && fromlen != NULL) {
8860Sstevel@tonic-gate 		switch (so_type) {
8870Sstevel@tonic-gate 		case INETBOOT_STREAM:
8880Sstevel@tonic-gate 			/* Need to copy from the socket's remote address. */
8890Sstevel@tonic-gate 			bcopy(&(sockets[sock_id].remote), from, MIN(*fromlen,
8900Sstevel@tonic-gate 			    sizeof (struct sockaddr_in)));
8910Sstevel@tonic-gate 			break;
8920Sstevel@tonic-gate 		case INETBOOT_RAW:
8930Sstevel@tonic-gate 		case INETBOOT_DGRAM:
8940Sstevel@tonic-gate 		default:
8950Sstevel@tonic-gate 			if (*fromlen > sizeof (icp->igm_saddr))
8960Sstevel@tonic-gate 				*fromlen = sizeof (icp->igm_saddr);
8970Sstevel@tonic-gate 			bcopy((caddr_t)&(icp->igm_saddr), (caddr_t)from,
8980Sstevel@tonic-gate 			    MIN(*fromlen, sizeof (struct sockaddr_in)));
8990Sstevel@tonic-gate 			break;
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	mp = icp->igm_mp;
9040Sstevel@tonic-gate 	switch (so_type) {
9050Sstevel@tonic-gate 	case INETBOOT_STREAM:
9060Sstevel@tonic-gate 		/*
9070Sstevel@tonic-gate 		 * If the message has igm_id == TCP_CALLB_MAGIC_ID, we need
9080Sstevel@tonic-gate 		 * to drain the data held by tcp and try again.
9090Sstevel@tonic-gate 		 */
9100Sstevel@tonic-gate 		if (icp->igm_id == TCP_CALLB_MAGIC_ID) {
9110Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9120Sstevel@tonic-gate 			tcp_rcv_drain_sock(sock_id);
9130Sstevel@tonic-gate 			goto retry;
9140Sstevel@tonic-gate 		}
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		/* TCP should put only user data in the inetgram. */
9170Sstevel@tonic-gate 		tmp_buf = (char *)buf;
9180Sstevel@tonic-gate 		while (len > 0 && icp != NULL) {
9190Sstevel@tonic-gate 			datalen = mp->b_wptr - mp->b_rptr;
9200Sstevel@tonic-gate 			if (len < datalen) {
9210Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, len);
9220Sstevel@tonic-gate 				bytes += len;
9230Sstevel@tonic-gate 				mp->b_rptr += len;
9240Sstevel@tonic-gate 				break;
9250Sstevel@tonic-gate 			} else {
9260Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, datalen);
9270Sstevel@tonic-gate 				len -= datalen;
9280Sstevel@tonic-gate 				bytes += datalen;
9290Sstevel@tonic-gate 				tmp_buf += datalen;
9300Sstevel@tonic-gate 				del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 				/*
9330Sstevel@tonic-gate 				 * If we have any embedded magic messages just
9340Sstevel@tonic-gate 				 * drop them.
9350Sstevel@tonic-gate 				 */
9360Sstevel@tonic-gate 				while ((icp = sockets[sock_id].inq) != NULL) {
9370Sstevel@tonic-gate 					if (icp->igm_id != TCP_CALLB_MAGIC_ID)
9380Sstevel@tonic-gate 						break;
9390Sstevel@tonic-gate 					del_gram(&sockets[sock_id].inq, icp,
940*6747Sga159272 					    B_TRUE);
9410Sstevel@tonic-gate 				}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 				if (icp == NULL)
9440Sstevel@tonic-gate 					break;
9450Sstevel@tonic-gate 				mp = icp->igm_mp;
9460Sstevel@tonic-gate 			}
9470Sstevel@tonic-gate 		}
9480Sstevel@tonic-gate 		sockets[sock_id].so_rcvbuf += (int32_t)bytes;
9490Sstevel@tonic-gate 		break;
9500Sstevel@tonic-gate 	case INETBOOT_DGRAM:
9510Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
9520Sstevel@tonic-gate 		if (len < datalen)
9530Sstevel@tonic-gate 			bytes = len;
9540Sstevel@tonic-gate 		else
9550Sstevel@tonic-gate 			bytes = datalen;
9560Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
9570Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9580Sstevel@tonic-gate 		break;
9590Sstevel@tonic-gate 	case INETBOOT_RAW:
9600Sstevel@tonic-gate 	default:
9610Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
9620Sstevel@tonic-gate 		if (len < datalen)
9630Sstevel@tonic-gate 			bytes = len;
9640Sstevel@tonic-gate 		else
9650Sstevel@tonic-gate 			bytes = datalen;
9660Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
9670Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9680Sstevel@tonic-gate 		break;
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate #ifdef	DEBUG
9720Sstevel@tonic-gate 	printf("recvfrom(%d): data: (0x%x,%d)\n", sock_id,
9730Sstevel@tonic-gate 	    (icp != NULL) ? icp->igm_mp : 0, bytes);
9740Sstevel@tonic-gate #endif	/* DEBUG */
9750Sstevel@tonic-gate 	return (bytes);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate /* Just a wrapper around sendto(). */
9800Sstevel@tonic-gate ssize_t
send(int s,const void * msg,size_t len,int flags)9810Sstevel@tonic-gate send(int s, const void *msg, size_t len, int flags)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate 	return (sendto(s, msg, len, flags, NULL, 0));
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * Transmit a message through a socket.
9880Sstevel@tonic-gate  *
9890Sstevel@tonic-gate  * Supported flags: MSG_DONTROUTE or 0.
9900Sstevel@tonic-gate  */
9910Sstevel@tonic-gate ssize_t
sendto(int s,const void * msg,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)9920Sstevel@tonic-gate sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to,
9930Sstevel@tonic-gate     socklen_t tolen)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	enum SockType so_type;
9960Sstevel@tonic-gate 	int sock_id;
9970Sstevel@tonic-gate 	ssize_t bytes;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	errno = 0;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
10020Sstevel@tonic-gate 		return (-1);
10030Sstevel@tonic-gate 	}
10040Sstevel@tonic-gate 	if (msg == NULL) {
10050Sstevel@tonic-gate 		errno = EINVAL;
10060Sstevel@tonic-gate 		return (-1);
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
10090Sstevel@tonic-gate 	if ((flags & ~MSG_DONTROUTE) != 0) {
10100Sstevel@tonic-gate 		errno = EINVAL;
10110Sstevel@tonic-gate 		return (-1);
10120Sstevel@tonic-gate 	}
10130Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
10140Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
10150Sstevel@tonic-gate 		return (-1);
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 	if (to != NULL && to->sa_family != AF_INET) {
10180Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
10190Sstevel@tonic-gate 		return (-1);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	switch (so_type) {
10230Sstevel@tonic-gate 	case INETBOOT_RAW:
10240Sstevel@tonic-gate 	case INETBOOT_DGRAM:
10250Sstevel@tonic-gate 		if (!(sockets[sock_id].so_state & SS_ISCONNECTED) &&
10260Sstevel@tonic-gate 		    (to == NULL || tolen != sizeof (struct sockaddr_in))) {
10270Sstevel@tonic-gate 			errno = EINVAL;
10280Sstevel@tonic-gate 			return (-1);
10290Sstevel@tonic-gate 		}
10300Sstevel@tonic-gate 		bytes = dgram_sendto(sock_id, msg, len, flags, to, tolen);
10310Sstevel@tonic-gate 		break;
10320Sstevel@tonic-gate 	case INETBOOT_STREAM:
10330Sstevel@tonic-gate 		if (!((sockets[sock_id].so_state & SS_ISCONNECTED) ||
10340Sstevel@tonic-gate 		    (sockets[sock_id].so_state & SS_ISCONNECTING))) {
10350Sstevel@tonic-gate 			errno = EINVAL;
10360Sstevel@tonic-gate 			return (-1);
10370Sstevel@tonic-gate 		}
10380Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTSENDMORE) {
10390Sstevel@tonic-gate 			errno = EPIPE;
10400Sstevel@tonic-gate 			return (-1);
10410Sstevel@tonic-gate 		}
10420Sstevel@tonic-gate 		bytes = stream_sendto(sock_id, msg, len, flags);
10430Sstevel@tonic-gate 		break;
10440Sstevel@tonic-gate 	default:
10450Sstevel@tonic-gate 		/* Should not happen... */
10460Sstevel@tonic-gate 		errno = EPROTOTYPE;
10470Sstevel@tonic-gate 		return (-1);
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 	return (bytes);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate static ssize_t
dgram_sendto(int i,const void * msg,size_t len,int flags,const struct sockaddr * to,int tolen)10530Sstevel@tonic-gate dgram_sendto(int i, const void *msg, size_t len, int flags,
10540Sstevel@tonic-gate     const struct sockaddr *to, int tolen)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate 	struct inetgram		oc;
10570Sstevel@tonic-gate 	int			l, offset;
10580Sstevel@tonic-gate 	size_t			tlen;
10590Sstevel@tonic-gate 	mblk_t			*mp;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate #ifdef	DEBUG
10620Sstevel@tonic-gate 	{
10630Sstevel@tonic-gate 	struct sockaddr_in *sin = (struct sockaddr_in *)to;
10640Sstevel@tonic-gate 	printf("sendto(%d): msg of length: %d sent to port %d and host: %s\n",
10650Sstevel@tonic-gate 	    i, len, ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate #endif	/* DEBUG */
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	nuke_grams(&sockets[i].inq); /* flush the input queue */
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/* calculate offset for data */
10720Sstevel@tonic-gate 	offset = sockets[i].headerlen[MEDIA_LVL](NULL) +
10730Sstevel@tonic-gate 	    (sockets[i].headerlen[NETWORK_LVL])(NULL);
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	bzero((caddr_t)&oc, sizeof (oc));
10760Sstevel@tonic-gate 	if (sockets[i].type != INETBOOT_RAW) {
10770Sstevel@tonic-gate 		offset += (sockets[i].headerlen[TRANSPORT_LVL])(NULL);
10780Sstevel@tonic-gate 		oc.igm_level = TRANSPORT_LVL;
10790Sstevel@tonic-gate 	} else
10800Sstevel@tonic-gate 		oc.igm_level = NETWORK_LVL;
10810Sstevel@tonic-gate 	oc.igm_oflags = flags;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	if (to != NULL) {
10840Sstevel@tonic-gate 		bcopy((caddr_t)to, (caddr_t)&oc.igm_saddr, tolen);
10850Sstevel@tonic-gate 	} else {
10860Sstevel@tonic-gate 		bcopy((caddr_t)&sockets[i].remote, (caddr_t)&oc.igm_saddr,
10870Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/* Get a legal source port if the socket isn't bound. */
10910Sstevel@tonic-gate 	if (sockets[i].bound == B_FALSE &&
10920Sstevel@tonic-gate 	    ntohs(oc.igm_saddr.sin_port == 0)) {
10930Sstevel@tonic-gate 		((struct sockaddr_in *)&oc.igm_saddr)->sin_port =
10940Sstevel@tonic-gate 		    get_source_port(B_FALSE);
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/* Round up to 16bit value for checksum purposes */
10980Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_DGRAM) {
10990Sstevel@tonic-gate 		tlen = ((len + sizeof (uint16_t) - 1) &
11000Sstevel@tonic-gate 		    ~(sizeof (uint16_t) - 1));
11010Sstevel@tonic-gate 	} else
11020Sstevel@tonic-gate 		tlen = len;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	if ((oc.igm_mp = allocb(tlen + offset, 0)) == NULL) {
11050Sstevel@tonic-gate 		errno = ENOMEM;
11060Sstevel@tonic-gate 		return (-1);
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 	mp = oc.igm_mp;
11090Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr += offset;
11100Sstevel@tonic-gate 	bcopy((caddr_t)msg, mp->b_wptr, len);
11110Sstevel@tonic-gate 	mp->b_wptr += len;
11120Sstevel@tonic-gate 	for (l = TRANSPORT_LVL; l >= MEDIA_LVL; l--) {
11130Sstevel@tonic-gate 		if (sockets[i].output[l] != NULL) {
11140Sstevel@tonic-gate 			if (sockets[i].output[l](i, &oc) < 0) {
11150Sstevel@tonic-gate 				freeb(mp);
11160Sstevel@tonic-gate 				if (errno == 0)
11170Sstevel@tonic-gate 					errno = EIO;
11180Sstevel@tonic-gate 				return (-1);
11190Sstevel@tonic-gate 			}
11200Sstevel@tonic-gate 		}
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 	freeb(mp);
11230Sstevel@tonic-gate 	return (len);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate /* ARGSUSED */
11270Sstevel@tonic-gate static ssize_t
stream_sendto(int i,const void * msg,size_t len,int flags)11280Sstevel@tonic-gate stream_sendto(int i, const void *msg, size_t len, int flags)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate 	int cnt;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	assert(sockets[i].pcb != NULL);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	/*
11350Sstevel@tonic-gate 	 * Call directly TCP's send routine.  We do this because TCP
11360Sstevel@tonic-gate 	 * needs to decide whether to send out the data.
11370Sstevel@tonic-gate 	 *
11380Sstevel@tonic-gate 	 * Note also that currently, TCP ignores all flags passed in for
11390Sstevel@tonic-gate 	 * TCP socket.
11400Sstevel@tonic-gate 	 */
11410Sstevel@tonic-gate 	if ((cnt = tcp_send(i, sockets[i].pcb, msg, len)) < 0) {
11420Sstevel@tonic-gate 		if (sockets[i].so_error != 0)
11430Sstevel@tonic-gate 			errno = sockets[i].so_error;
11440Sstevel@tonic-gate 		return (-1);
11450Sstevel@tonic-gate 	} else {
11460Sstevel@tonic-gate 		return (cnt);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate /*
11510Sstevel@tonic-gate  * Returns ptr to the last inetgram in the list, or null if list is null
11520Sstevel@tonic-gate  */
11530Sstevel@tonic-gate struct inetgram *
last_gram(struct inetgram * igp)11540Sstevel@tonic-gate last_gram(struct inetgram *igp)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate 	struct inetgram	*wp;
11570Sstevel@tonic-gate 	for (wp = igp; wp != NULL; wp = wp->igm_next) {
11580Sstevel@tonic-gate 		if (wp->igm_next == NULL)
11590Sstevel@tonic-gate 			return (wp);
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 	return (NULL);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate  * Adds an inetgram or list of inetgrams to the end of the list.
11660Sstevel@tonic-gate  */
11670Sstevel@tonic-gate void
add_grams(struct inetgram ** igpp,struct inetgram * newgp)11680Sstevel@tonic-gate add_grams(struct inetgram **igpp, struct inetgram *newgp)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate 	struct inetgram	 *wp;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	if (newgp == NULL)
11730Sstevel@tonic-gate 		return;
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	if (*igpp == NULL)
11760Sstevel@tonic-gate 		*igpp = newgp;
11770Sstevel@tonic-gate 	else {
11780Sstevel@tonic-gate 		wp = last_gram(*igpp);
11790Sstevel@tonic-gate 		wp->igm_next = newgp;
11800Sstevel@tonic-gate 	}
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate /*
11840Sstevel@tonic-gate  * Nuke a whole list of grams.
11850Sstevel@tonic-gate  */
11860Sstevel@tonic-gate void
nuke_grams(struct inetgram ** lgpp)11870Sstevel@tonic-gate nuke_grams(struct inetgram **lgpp)
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate 	while (*lgpp != NULL)
11900Sstevel@tonic-gate 		del_gram(lgpp, *lgpp, B_TRUE);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate  * Remove the referenced inetgram. List is altered accordingly. Destroy the
11950Sstevel@tonic-gate  * referenced inetgram if freeit is B_TRUE.
11960Sstevel@tonic-gate  */
11970Sstevel@tonic-gate void
del_gram(struct inetgram ** lgpp,struct inetgram * igp,int freeit)11980Sstevel@tonic-gate del_gram(struct inetgram **lgpp, struct inetgram *igp, int freeit)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate 	struct inetgram	*wp, *pp = NULL;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	if (lgpp == NULL || igp == NULL)
12030Sstevel@tonic-gate 		return;
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	wp = *lgpp;
12060Sstevel@tonic-gate 	while (wp != NULL) {
12070Sstevel@tonic-gate 		if (wp == igp) {
12080Sstevel@tonic-gate 			/* detach wp from the list */
12090Sstevel@tonic-gate 			if (*lgpp == wp)
12100Sstevel@tonic-gate 				*lgpp = (*lgpp)->igm_next;
12110Sstevel@tonic-gate 			else
12120Sstevel@tonic-gate 				pp->igm_next = wp->igm_next;
12130Sstevel@tonic-gate 			igp->igm_next = NULL;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 			if (freeit) {
12160Sstevel@tonic-gate 				if (igp->igm_mp != NULL)
12170Sstevel@tonic-gate 					freeb(igp->igm_mp);
12180Sstevel@tonic-gate 				bkmem_free((caddr_t)igp,
12190Sstevel@tonic-gate 				    sizeof (struct inetgram));
12200Sstevel@tonic-gate 			}
12210Sstevel@tonic-gate 			break;
12220Sstevel@tonic-gate 		}
12230Sstevel@tonic-gate 		pp = wp;
12240Sstevel@tonic-gate 		wp = wp->igm_next;
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate struct nct_t nct[] = {
12290Sstevel@tonic-gate 	"bootp",	NCT_BOOTP_DHCP,
12300Sstevel@tonic-gate 	"dhcp",		NCT_BOOTP_DHCP,
12310Sstevel@tonic-gate 	"rarp",		NCT_RARP_BOOTPARAMS,
12320Sstevel@tonic-gate 	"manual",	NCT_MANUAL
12330Sstevel@tonic-gate };
12340Sstevel@tonic-gate int	nct_entries = sizeof (nct) / sizeof (nct[0]);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate /*
12370Sstevel@tonic-gate  * Figure out from the bootpath what kind of network configuration strategy
12380Sstevel@tonic-gate  * we should use. Returns the network config strategy.
12390Sstevel@tonic-gate  */
12400Sstevel@tonic-gate int
get_netconfig_strategy(void)12410Sstevel@tonic-gate get_netconfig_strategy(void)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	int	i;
12440Sstevel@tonic-gate #define	ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\0')
12450Sstevel@tonic-gate 	char	lbootpath[OBP_MAXPATHLEN];
12460Sstevel@tonic-gate 	char	net_options[NCT_BUFSIZE];
12470Sstevel@tonic-gate 	char	*op, *nop, *sp;
1248789Sahrens 	pnode_t	cn;
12490Sstevel@tonic-gate 	int	proplen;
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/* If the PROM DHCP cache exists, we're done */
12520Sstevel@tonic-gate 	if (prom_cached_reply(B_TRUE))
12530Sstevel@tonic-gate 		return (NCT_BOOTP_DHCP);
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	/*
12560Sstevel@tonic-gate 	 *	Newer (version 4) PROMs will put the name in the
12570Sstevel@tonic-gate 	 *	"net-config-strategy" property.
12580Sstevel@tonic-gate 	 */
12590Sstevel@tonic-gate 	cn = prom_finddevice("/chosen");
12600Sstevel@tonic-gate 	if ((proplen = prom_getproplen(cn, "net-config-strategy")) <
12610Sstevel@tonic-gate 	    sizeof (net_options)) {
12620Sstevel@tonic-gate 		(void) prom_getprop(cn, "net-config-strategy", net_options);
12630Sstevel@tonic-gate 		net_options[proplen] = '\0';
12640Sstevel@tonic-gate 	} else {
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 		/*
12670Sstevel@tonic-gate 		 * We're reduced to sacanning bootpath for the prototol to use.
12680Sstevel@tonic-gate 		 * Since there was no "net-config-strategy" property, this is
12690Sstevel@tonic-gate 		 * an old PROM, so we need to excise any extraneous key/value
12700Sstevel@tonic-gate 		 * initializations from bootpath[].
12710Sstevel@tonic-gate 		 */
12720Sstevel@tonic-gate 		for (op = prom_bootpath(), sp = lbootpath; op != NULL &&
12730Sstevel@tonic-gate 		    !ISSPACE(*op); sp++, op++)
12740Sstevel@tonic-gate 			*sp = *op;
12750Sstevel@tonic-gate 		*sp = '\0';
12760Sstevel@tonic-gate 		/* find the last '/' (in the device path) */
12770Sstevel@tonic-gate 		if ((op = strrchr(lbootpath, '/')) == NULL)	/* last '/' */
12780Sstevel@tonic-gate 			op = lbootpath;
12790Sstevel@tonic-gate 		else
12800Sstevel@tonic-gate 			op++;
12810Sstevel@tonic-gate 		/* then look for the ':' separating it from the protocol */
12820Sstevel@tonic-gate 		while (*op != ':' && *op != '\0')
12830Sstevel@tonic-gate 			op++;
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 		if (*op == ':') {
12860Sstevel@tonic-gate 			for (nop = net_options, op++;
12870Sstevel@tonic-gate 			    *op != '\0' && *op != '/' && !ISSPACE(*op) &&
12880Sstevel@tonic-gate 			    nop < &net_options[NCT_BUFSIZE]; nop++, op++)
12890Sstevel@tonic-gate 				*nop = *op;
12900Sstevel@tonic-gate 			*nop = '\0';
12910Sstevel@tonic-gate 		} else
12920Sstevel@tonic-gate 			net_options[0] = '\0';
12930Sstevel@tonic-gate 	}
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate #undef	ISSPACE
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	for (i = 0; i < nct_entries; i++)
12980Sstevel@tonic-gate 		if (strcmp(net_options, nct[i].p_name) == 0)
12990Sstevel@tonic-gate 			return (nct[i].p_id);
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	return (NCT_DEFAULT);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate /* Modified STREAM routines for ease of porting core TCP code. */
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate /*ARGSUSED*/
13070Sstevel@tonic-gate mblk_t *
allocb(size_t size,uint_t pri)13080Sstevel@tonic-gate allocb(size_t size, uint_t pri)
13090Sstevel@tonic-gate {
13100Sstevel@tonic-gate 	unsigned char *base;
13110Sstevel@tonic-gate 	mblk_t *mp;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	if ((mp = (mblk_t *)bkmem_zalloc(sizeof (mblk_t))) == NULL)
13140Sstevel@tonic-gate 		return (NULL);
13150Sstevel@tonic-gate 	if ((base = (unsigned char *)bkmem_zalloc(size)) == NULL)
13160Sstevel@tonic-gate 		return (NULL);
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	mp->b_next = mp->b_prev = mp->b_cont = NULL;
13190Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr = mp->b_datap = (unsigned char *)base;
13200Sstevel@tonic-gate 	mp->b_size = size;
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	return (mp);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate void
freeb(mblk_t * mp)13260Sstevel@tonic-gate freeb(mblk_t *mp)
13270Sstevel@tonic-gate {
13280Sstevel@tonic-gate #ifdef DEBUG
13290Sstevel@tonic-gate 	printf("freeb datap %x\n", mp->b_datap);
13300Sstevel@tonic-gate #endif
13310Sstevel@tonic-gate 	bkmem_free((caddr_t)(mp->b_datap), mp->b_size);
13320Sstevel@tonic-gate #ifdef DEBUG
13330Sstevel@tonic-gate 	printf("freeb mp %x\n", mp);
13340Sstevel@tonic-gate #endif
13350Sstevel@tonic-gate 	bkmem_free((caddr_t)mp, sizeof (mblk_t));
13360Sstevel@tonic-gate }
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate void
freemsg(mblk_t * mp)13390Sstevel@tonic-gate freemsg(mblk_t *mp)
13400Sstevel@tonic-gate {
13410Sstevel@tonic-gate 	while (mp) {
13420Sstevel@tonic-gate 		mblk_t *mp_cont = mp->b_cont;
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 		freeb(mp);
13450Sstevel@tonic-gate 		mp = mp_cont;
13460Sstevel@tonic-gate 	}
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate mblk_t *
copyb(mblk_t * bp)13500Sstevel@tonic-gate copyb(mblk_t *bp)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate 	mblk_t *nbp;
13530Sstevel@tonic-gate 	unsigned char *ndp;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	assert((uintptr_t)(bp->b_wptr - bp->b_rptr) >= 0);
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	if (!(nbp = allocb(bp->b_size, 0)))
13580Sstevel@tonic-gate 		return (NULL);
13590Sstevel@tonic-gate 	nbp->b_cont = NULL;
13600Sstevel@tonic-gate 	ndp = nbp->b_datap;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	nbp->b_rptr = ndp + (bp->b_rptr - bp->b_datap);
13630Sstevel@tonic-gate 	nbp->b_wptr = nbp->b_rptr + (bp->b_wptr - bp->b_rptr);
13640Sstevel@tonic-gate 	bcopy(bp->b_datap, nbp->b_datap, bp->b_size);
13650Sstevel@tonic-gate 	return (nbp);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate /* To simplify things, dupb() is implemented as copyb(). */
13690Sstevel@tonic-gate mblk_t *
dupb(mblk_t * mp)13700Sstevel@tonic-gate dupb(mblk_t *mp)
13710Sstevel@tonic-gate {
13720Sstevel@tonic-gate 	return (copyb(mp));
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate /*
13760Sstevel@tonic-gate  * get number of data bytes in message
13770Sstevel@tonic-gate  */
13780Sstevel@tonic-gate size_t
msgdsize(mblk_t * bp)13790Sstevel@tonic-gate msgdsize(mblk_t *bp)
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate 	size_t count = 0;
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	for (; bp != NULL; bp = bp->b_cont) {
13840Sstevel@tonic-gate 		assert(bp->b_wptr >= bp->b_rptr);
13850Sstevel@tonic-gate 		count += bp->b_wptr - bp->b_rptr;
13860Sstevel@tonic-gate 	}
13870Sstevel@tonic-gate 	return (count);
13880Sstevel@tonic-gate }
1389