xref: /titanic_50/usr/src/stand/lib/sock/socket.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * socket.c, Code implementing a simple socket interface.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
32*7c478bd9Sstevel@tonic-gate #include "socket_impl.h"
33*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
38*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
39*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/salib.h>
42*7c478bd9Sstevel@tonic-gate #include "socket_inet.h"
43*7c478bd9Sstevel@tonic-gate #include "ipv4.h"
44*7c478bd9Sstevel@tonic-gate #include "ipv4_impl.h"
45*7c478bd9Sstevel@tonic-gate #include "udp_inet.h"
46*7c478bd9Sstevel@tonic-gate #include "tcp_inet.h"
47*7c478bd9Sstevel@tonic-gate #include "mac.h"
48*7c478bd9Sstevel@tonic-gate #include "mac_impl.h"
49*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate struct inetboot_socket	sockets[MAXSOCKET] = { 0 };
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /* Default send and receive socket buffer size */
54*7c478bd9Sstevel@tonic-gate #define	SO_DEF_SNDBUF	48*1024
55*7c478bd9Sstevel@tonic-gate #define	SO_DEF_RCVBUF	48*1024
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /* Default max socket buffer size */
58*7c478bd9Sstevel@tonic-gate #define	SO_MAX_BUF	4*1024*1024
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static ssize_t dgram_sendto(int, const void *, size_t, int,
61*7c478bd9Sstevel@tonic-gate     const struct sockaddr *, int);
62*7c478bd9Sstevel@tonic-gate static ssize_t stream_sendto(int, const void *, size_t, int);
63*7c478bd9Sstevel@tonic-gate static int bind_check(int, const struct sockaddr *);
64*7c478bd9Sstevel@tonic-gate static int quickbind(int);
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /* Check the validity of a fd and return the socket index of that fd. */
67*7c478bd9Sstevel@tonic-gate int
68*7c478bd9Sstevel@tonic-gate so_check_fd(int fd, int *errno)
69*7c478bd9Sstevel@tonic-gate {
70*7c478bd9Sstevel@tonic-gate 	int i;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 	i = FD_TO_SOCKET(fd);
73*7c478bd9Sstevel@tonic-gate 	if (i < 0 || i >= MAXSOCKET) {
74*7c478bd9Sstevel@tonic-gate 		*errno = ENOTSOCK;
75*7c478bd9Sstevel@tonic-gate 		return (-1);
76*7c478bd9Sstevel@tonic-gate 	}
77*7c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_UNUSED) {
78*7c478bd9Sstevel@tonic-gate 		*errno = ENOTSOCK;
79*7c478bd9Sstevel@tonic-gate 		return (-1);
80*7c478bd9Sstevel@tonic-gate 	}
81*7c478bd9Sstevel@tonic-gate 	return (i);
82*7c478bd9Sstevel@tonic-gate }
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * Create an endpoint for network communication. Returns a descriptor.
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  * Notes:
88*7c478bd9Sstevel@tonic-gate  *	Only PF_INET communication domains are supported. Within
89*7c478bd9Sstevel@tonic-gate  * 	this domain, only SOCK_RAW, SOCK_DGRAM and SOCK_STREAM types are
90*7c478bd9Sstevel@tonic-gate  *	supported.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate int
93*7c478bd9Sstevel@tonic-gate socket(int domain, int type, int protocol)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	static int sock_initialized;
96*7c478bd9Sstevel@tonic-gate 	int i;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	errno = 0;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	if (!sock_initialized) {
101*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAXSOCKET; i++)
102*7c478bd9Sstevel@tonic-gate 			sockets[i].type = INETBOOT_UNUSED;
103*7c478bd9Sstevel@tonic-gate 		sock_initialized = B_TRUE;
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 	if (domain != AF_INET) {
106*7c478bd9Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
107*7c478bd9Sstevel@tonic-gate 		return (-1);
108*7c478bd9Sstevel@tonic-gate 	}
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	/* Find available socket */
111*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXSOCKET; i++) {
112*7c478bd9Sstevel@tonic-gate 		if (sockets[i].type == INETBOOT_UNUSED)
113*7c478bd9Sstevel@tonic-gate 			break;
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate 	if (i >= MAXSOCKET) {
116*7c478bd9Sstevel@tonic-gate 		errno = EMFILE;	/* No slots left. */
117*7c478bd9Sstevel@tonic-gate 		return (-1);
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	/* Some socket initialization... */
121*7c478bd9Sstevel@tonic-gate 	sockets[i].so_rcvbuf = SO_DEF_RCVBUF;
122*7c478bd9Sstevel@tonic-gate 	sockets[i].so_sndbuf = SO_DEF_SNDBUF;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	/*
125*7c478bd9Sstevel@tonic-gate 	 * Note that we ignore the protocol field for SOCK_DGRAM and
126*7c478bd9Sstevel@tonic-gate 	 * SOCK_STREAM.  When we support different protocols in future,
127*7c478bd9Sstevel@tonic-gate 	 * this needs to be changed.
128*7c478bd9Sstevel@tonic-gate 	 */
129*7c478bd9Sstevel@tonic-gate 	switch (type) {
130*7c478bd9Sstevel@tonic-gate 	case SOCK_RAW:
131*7c478bd9Sstevel@tonic-gate 		ipv4_raw_socket(&sockets[i], (uint8_t)protocol);
132*7c478bd9Sstevel@tonic-gate 		break;
133*7c478bd9Sstevel@tonic-gate 	case SOCK_DGRAM:
134*7c478bd9Sstevel@tonic-gate 		udp_socket_init(&sockets[i]);
135*7c478bd9Sstevel@tonic-gate 		break;
136*7c478bd9Sstevel@tonic-gate 	case SOCK_STREAM:
137*7c478bd9Sstevel@tonic-gate 		tcp_socket_init(&sockets[i]);
138*7c478bd9Sstevel@tonic-gate 		break;
139*7c478bd9Sstevel@tonic-gate 	default:
140*7c478bd9Sstevel@tonic-gate 		errno = EPROTOTYPE;
141*7c478bd9Sstevel@tonic-gate 		break;
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
145*7c478bd9Sstevel@tonic-gate 		return (-1);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/* IPv4 generic initialization. */
148*7c478bd9Sstevel@tonic-gate 	ipv4_socket_init(&sockets[i]);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	/* MAC generic initialization. */
151*7c478bd9Sstevel@tonic-gate 	mac_socket_init(&sockets[i]);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	return (i + SOCKETTYPE);
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate int
157*7c478bd9Sstevel@tonic-gate getsockname(int s, struct sockaddr *name,  socklen_t *namelen)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	int i;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	errno = 0;
162*7c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
163*7c478bd9Sstevel@tonic-gate 		return (-1);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if (*namelen < sizeof (struct sockaddr_in)) {
166*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
167*7c478bd9Sstevel@tonic-gate 		return (-1);
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	/* Structure assignment... */
171*7c478bd9Sstevel@tonic-gate 	*((struct sockaddr_in *)name) = sockets[i].bind;
172*7c478bd9Sstevel@tonic-gate 	*namelen = sizeof (struct sockaddr_in);
173*7c478bd9Sstevel@tonic-gate 	return (0);
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate /*
177*7c478bd9Sstevel@tonic-gate  * The socket options we support are:
178*7c478bd9Sstevel@tonic-gate  * SO_RCVTIMEO	-	Value is in msecs, and is of uint32_t.
179*7c478bd9Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is an int, and is a boolean (nonzero if set).
180*7c478bd9Sstevel@tonic-gate  * SO_REUSEADDR -	Value is an int boolean.
181*7c478bd9Sstevel@tonic-gate  * SO_RCVBUF -		Value is an int.
182*7c478bd9Sstevel@tonic-gate  * SO_SNDBUF -		Value is an int.
183*7c478bd9Sstevel@tonic-gate  */
184*7c478bd9Sstevel@tonic-gate int
185*7c478bd9Sstevel@tonic-gate getsockopt(int s, int level, int option, void *optval, socklen_t *optlen)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	int i;
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	errno = 0;
190*7c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
191*7c478bd9Sstevel@tonic-gate 		return (-1);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	switch (level) {
194*7c478bd9Sstevel@tonic-gate 	case SOL_SOCKET: {
195*7c478bd9Sstevel@tonic-gate 		switch (option) {
196*7c478bd9Sstevel@tonic-gate 		case SO_RCVTIMEO:
197*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (uint32_t)) {
198*7c478bd9Sstevel@tonic-gate 				*(uint32_t *)optval = sockets[i].in_timeout;
199*7c478bd9Sstevel@tonic-gate 			} else {
200*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
201*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
202*7c478bd9Sstevel@tonic-gate 			}
203*7c478bd9Sstevel@tonic-gate 			break;
204*7c478bd9Sstevel@tonic-gate 		case SO_DONTROUTE:
205*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
206*7c478bd9Sstevel@tonic-gate 				*(int *)optval =
207*7c478bd9Sstevel@tonic-gate 				    (sockets[i].out_flags & SO_DONTROUTE);
208*7c478bd9Sstevel@tonic-gate 			} else {
209*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
210*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 			break;
213*7c478bd9Sstevel@tonic-gate 		case SO_REUSEADDR:
214*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
215*7c478bd9Sstevel@tonic-gate 				*(int *)optval =
216*7c478bd9Sstevel@tonic-gate 				    (sockets[i].so_opt & SO_REUSEADDR);
217*7c478bd9Sstevel@tonic-gate 			} else {
218*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
219*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
220*7c478bd9Sstevel@tonic-gate 			}
221*7c478bd9Sstevel@tonic-gate 			break;
222*7c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
223*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
224*7c478bd9Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_rcvbuf;
225*7c478bd9Sstevel@tonic-gate 			} else {
226*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
227*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
228*7c478bd9Sstevel@tonic-gate 			}
229*7c478bd9Sstevel@tonic-gate 			break;
230*7c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
231*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (int)) {
232*7c478bd9Sstevel@tonic-gate 				*(int *)optval = sockets[i].so_sndbuf;
233*7c478bd9Sstevel@tonic-gate 			} else {
234*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
235*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
236*7c478bd9Sstevel@tonic-gate 			}
237*7c478bd9Sstevel@tonic-gate 			break;
238*7c478bd9Sstevel@tonic-gate 		case SO_LINGER:
239*7c478bd9Sstevel@tonic-gate 			if (*optlen == sizeof (struct linger)) {
240*7c478bd9Sstevel@tonic-gate 				/* struct copy */
241*7c478bd9Sstevel@tonic-gate 				*(struct linger *)optval = sockets[i].so_linger;
242*7c478bd9Sstevel@tonic-gate 			} else {
243*7c478bd9Sstevel@tonic-gate 				*optlen = 0;
244*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
245*7c478bd9Sstevel@tonic-gate 			}
246*7c478bd9Sstevel@tonic-gate 		default:
247*7c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
248*7c478bd9Sstevel@tonic-gate 			break;
249*7c478bd9Sstevel@tonic-gate 		}
250*7c478bd9Sstevel@tonic-gate 		break;
251*7c478bd9Sstevel@tonic-gate 	} /* case SOL_SOCKET */
252*7c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
253*7c478bd9Sstevel@tonic-gate 	case IPPROTO_IP: {
254*7c478bd9Sstevel@tonic-gate 		switch (option) {
255*7c478bd9Sstevel@tonic-gate 		default:
256*7c478bd9Sstevel@tonic-gate 			*optlen = 0;
257*7c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
258*7c478bd9Sstevel@tonic-gate 			break;
259*7c478bd9Sstevel@tonic-gate 		}
260*7c478bd9Sstevel@tonic-gate 		break;
261*7c478bd9Sstevel@tonic-gate 	} /* case IPPROTO_IP or IPPROTO_TCP */
262*7c478bd9Sstevel@tonic-gate 	default:
263*7c478bd9Sstevel@tonic-gate 		errno = ENOPROTOOPT;
264*7c478bd9Sstevel@tonic-gate 		break;
265*7c478bd9Sstevel@tonic-gate 	} /* switch (level) */
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
268*7c478bd9Sstevel@tonic-gate 		return (-1);
269*7c478bd9Sstevel@tonic-gate 	else
270*7c478bd9Sstevel@tonic-gate 		return (0);
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /*
274*7c478bd9Sstevel@tonic-gate  * Generate a network-order source port from the privileged range if
275*7c478bd9Sstevel@tonic-gate  * "reserved" is true, dynamic/private range otherwise. We consider the
276*7c478bd9Sstevel@tonic-gate  * range of 512-1023 privileged ports as ports we can use. This mirrors
277*7c478bd9Sstevel@tonic-gate  * historical rpc client practice for privileged port selection.
278*7c478bd9Sstevel@tonic-gate  */
279*7c478bd9Sstevel@tonic-gate in_port_t
280*7c478bd9Sstevel@tonic-gate get_source_port(boolean_t reserved)
281*7c478bd9Sstevel@tonic-gate {
282*7c478bd9Sstevel@tonic-gate 	static in_port_t	dynamic = IPPORT_DYNAMIC_START - 1,
283*7c478bd9Sstevel@tonic-gate 				    rsvdport = (IPPORT_RESERVED / 2) - 1;
284*7c478bd9Sstevel@tonic-gate 	in_port_t		p;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	if (reserved) {
287*7c478bd9Sstevel@tonic-gate 		if (++rsvdport >= IPPORT_RESERVED)
288*7c478bd9Sstevel@tonic-gate 			p = rsvdport = IPPORT_RESERVED / 2;
289*7c478bd9Sstevel@tonic-gate 		else
290*7c478bd9Sstevel@tonic-gate 			p = rsvdport;
291*7c478bd9Sstevel@tonic-gate 	} else
292*7c478bd9Sstevel@tonic-gate 		p = ++dynamic;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	return (htons(p));
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate /*
298*7c478bd9Sstevel@tonic-gate  * The socket options we support are:
299*7c478bd9Sstevel@tonic-gate  * SO_RECVTIMEO	-	Value is uint32_t msecs.
300*7c478bd9Sstevel@tonic-gate  * SO_DONTROUTE	-	Value is int boolean (nonzero == TRUE, zero == FALSE).
301*7c478bd9Sstevel@tonic-gate  * SO_REUSEADDR -	value is int boolean.
302*7c478bd9Sstevel@tonic-gate  * SO_RCVBUF -		Value is int.
303*7c478bd9Sstevel@tonic-gate  * SO_SNDBUF -		Value is int.
304*7c478bd9Sstevel@tonic-gate  */
305*7c478bd9Sstevel@tonic-gate int
306*7c478bd9Sstevel@tonic-gate setsockopt(int s, int level, int option, const void *optval, socklen_t optlen)
307*7c478bd9Sstevel@tonic-gate {
308*7c478bd9Sstevel@tonic-gate 	int i;
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	errno = 0;
311*7c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
312*7c478bd9Sstevel@tonic-gate 		return (-1);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	switch (level) {
315*7c478bd9Sstevel@tonic-gate 	case SOL_SOCKET: {
316*7c478bd9Sstevel@tonic-gate 		switch (option) {
317*7c478bd9Sstevel@tonic-gate 		case SO_RCVTIMEO:
318*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (uint32_t))
319*7c478bd9Sstevel@tonic-gate 				sockets[i].in_timeout = *(uint32_t *)optval;
320*7c478bd9Sstevel@tonic-gate 			else {
321*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
322*7c478bd9Sstevel@tonic-gate 			}
323*7c478bd9Sstevel@tonic-gate 			break;
324*7c478bd9Sstevel@tonic-gate 		case SO_DONTROUTE:
325*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
326*7c478bd9Sstevel@tonic-gate 				if (*(int *)optval)
327*7c478bd9Sstevel@tonic-gate 					sockets[i].out_flags |= SO_DONTROUTE;
328*7c478bd9Sstevel@tonic-gate 				else
329*7c478bd9Sstevel@tonic-gate 					sockets[i].out_flags &= ~SO_DONTROUTE;
330*7c478bd9Sstevel@tonic-gate 			} else {
331*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
332*7c478bd9Sstevel@tonic-gate 			}
333*7c478bd9Sstevel@tonic-gate 			break;
334*7c478bd9Sstevel@tonic-gate 		case SO_REUSEADDR:
335*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
336*7c478bd9Sstevel@tonic-gate 				if (*(int *)optval)
337*7c478bd9Sstevel@tonic-gate 					sockets[i].so_opt |= SO_REUSEADDR;
338*7c478bd9Sstevel@tonic-gate 				else
339*7c478bd9Sstevel@tonic-gate 					sockets[i].so_opt &= ~SO_REUSEADDR;
340*7c478bd9Sstevel@tonic-gate 			} else {
341*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
342*7c478bd9Sstevel@tonic-gate 			}
343*7c478bd9Sstevel@tonic-gate 			break;
344*7c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
345*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
346*7c478bd9Sstevel@tonic-gate 				sockets[i].so_rcvbuf = *(int *)optval;
347*7c478bd9Sstevel@tonic-gate 				if (sockets[i].so_rcvbuf > SO_MAX_BUF)
348*7c478bd9Sstevel@tonic-gate 					sockets[i].so_rcvbuf = SO_MAX_BUF;
349*7c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
350*7c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
351*7c478bd9Sstevel@tonic-gate 			} else {
352*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
353*7c478bd9Sstevel@tonic-gate 			}
354*7c478bd9Sstevel@tonic-gate 			break;
355*7c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
356*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (int)) {
357*7c478bd9Sstevel@tonic-gate 				sockets[i].so_sndbuf = *(int *)optval;
358*7c478bd9Sstevel@tonic-gate 				if (sockets[i].so_sndbuf > SO_MAX_BUF)
359*7c478bd9Sstevel@tonic-gate 					sockets[i].so_sndbuf = SO_MAX_BUF;
360*7c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
361*7c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
362*7c478bd9Sstevel@tonic-gate 			} else {
363*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
364*7c478bd9Sstevel@tonic-gate 			}
365*7c478bd9Sstevel@tonic-gate 			break;
366*7c478bd9Sstevel@tonic-gate 		case SO_LINGER:
367*7c478bd9Sstevel@tonic-gate 			if (optlen == sizeof (struct linger)) {
368*7c478bd9Sstevel@tonic-gate 				/* struct copy */
369*7c478bd9Sstevel@tonic-gate 				sockets[i].so_linger = *(struct linger *)optval;
370*7c478bd9Sstevel@tonic-gate 				(void) tcp_opt_set(sockets[i].pcb,
371*7c478bd9Sstevel@tonic-gate 				    level, option, optval, optlen);
372*7c478bd9Sstevel@tonic-gate 			} else {
373*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
374*7c478bd9Sstevel@tonic-gate 			}
375*7c478bd9Sstevel@tonic-gate 			break;
376*7c478bd9Sstevel@tonic-gate 		default:
377*7c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
378*7c478bd9Sstevel@tonic-gate 			break;
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 		break;
381*7c478bd9Sstevel@tonic-gate 	} /* case SOL_SOCKET */
382*7c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
383*7c478bd9Sstevel@tonic-gate 	case IPPROTO_IP: {
384*7c478bd9Sstevel@tonic-gate 		switch (option) {
385*7c478bd9Sstevel@tonic-gate 		default:
386*7c478bd9Sstevel@tonic-gate 			errno = ENOPROTOOPT;
387*7c478bd9Sstevel@tonic-gate 			break;
388*7c478bd9Sstevel@tonic-gate 		}
389*7c478bd9Sstevel@tonic-gate 		break;
390*7c478bd9Sstevel@tonic-gate 	} /* case IPPROTO_IP  or IPPROTO_TCP */
391*7c478bd9Sstevel@tonic-gate 	default:
392*7c478bd9Sstevel@tonic-gate 		errno = ENOPROTOOPT;
393*7c478bd9Sstevel@tonic-gate 		break;
394*7c478bd9Sstevel@tonic-gate 	} /* switch (level) */
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
397*7c478bd9Sstevel@tonic-gate 		return (-1);
398*7c478bd9Sstevel@tonic-gate 	else
399*7c478bd9Sstevel@tonic-gate 		return (0);
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate /*
403*7c478bd9Sstevel@tonic-gate  * Shut down part of a full-duplex connection.
404*7c478bd9Sstevel@tonic-gate  *
405*7c478bd9Sstevel@tonic-gate  * Only supported for TCP sockets
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate int
408*7c478bd9Sstevel@tonic-gate shutdown(int s, int how)
409*7c478bd9Sstevel@tonic-gate {
410*7c478bd9Sstevel@tonic-gate 	int sock_id;
411*7c478bd9Sstevel@tonic-gate 	int i;
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	errno = 0;
414*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
415*7c478bd9Sstevel@tonic-gate 		return (-1);
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/* shutdown only supported for TCP sockets */
418*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
419*7c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
420*7c478bd9Sstevel@tonic-gate 		return (-1);
421*7c478bd9Sstevel@tonic-gate 	}
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if (!(sockets[sock_id].so_state & SS_ISCONNECTED)) {
424*7c478bd9Sstevel@tonic-gate 		errno = ENOTCONN;
425*7c478bd9Sstevel@tonic-gate 		return (-1);
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	switch (how) {
429*7c478bd9Sstevel@tonic-gate 	case 0:
430*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTRCVMORE;
431*7c478bd9Sstevel@tonic-gate 		break;
432*7c478bd9Sstevel@tonic-gate 	case 1:
433*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_CANTSENDMORE;
434*7c478bd9Sstevel@tonic-gate 		break;
435*7c478bd9Sstevel@tonic-gate 	case 2:
436*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE);
437*7c478bd9Sstevel@tonic-gate 		break;
438*7c478bd9Sstevel@tonic-gate 	default:
439*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
440*7c478bd9Sstevel@tonic-gate 		return (-1);
441*7c478bd9Sstevel@tonic-gate 	}
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	switch (sockets[sock_id].so_state &
444*7c478bd9Sstevel@tonic-gate 				(SS_CANTRCVMORE | SS_CANTSENDMORE)) {
445*7c478bd9Sstevel@tonic-gate 	case (SS_CANTRCVMORE | SS_CANTSENDMORE):
446*7c478bd9Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
447*7c478bd9Sstevel@tonic-gate 		for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
448*7c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].close[i] != NULL) {
449*7c478bd9Sstevel@tonic-gate 				(void) sockets[sock_id].close[i](sock_id);
450*7c478bd9Sstevel@tonic-gate 			}
451*7c478bd9Sstevel@tonic-gate 		}
452*7c478bd9Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
453*7c478bd9Sstevel@tonic-gate 		break;
454*7c478bd9Sstevel@tonic-gate 	case SS_CANTRCVMORE:
455*7c478bd9Sstevel@tonic-gate 		nuke_grams(&sockets[sock_id].inq);
456*7c478bd9Sstevel@tonic-gate 		break;
457*7c478bd9Sstevel@tonic-gate 	case SS_CANTSENDMORE:
458*7c478bd9Sstevel@tonic-gate 		/* Call lower level protocol close routine. */
459*7c478bd9Sstevel@tonic-gate 		if (tcp_shutdown(sock_id) < 0)
460*7c478bd9Sstevel@tonic-gate 			return (-1);
461*7c478bd9Sstevel@tonic-gate 		break;
462*7c478bd9Sstevel@tonic-gate 	default:
463*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
464*7c478bd9Sstevel@tonic-gate 		return (-1);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	return (0);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate  * "close" a socket.
472*7c478bd9Sstevel@tonic-gate  */
473*7c478bd9Sstevel@tonic-gate int
474*7c478bd9Sstevel@tonic-gate socket_close(int s)
475*7c478bd9Sstevel@tonic-gate {
476*7c478bd9Sstevel@tonic-gate 	int sock_id, i;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	errno = 0;
479*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1)
480*7c478bd9Sstevel@tonic-gate 		return (-1);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	/* Call lower level protocol close routine. */
483*7c478bd9Sstevel@tonic-gate 	for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
484*7c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].close[i] != NULL) {
485*7c478bd9Sstevel@tonic-gate 			/*
486*7c478bd9Sstevel@tonic-gate 			 * Note that the close() routine of other
487*7c478bd9Sstevel@tonic-gate 			 * layers can return an error.  But right
488*7c478bd9Sstevel@tonic-gate 			 * now, the only mechanism to report that
489*7c478bd9Sstevel@tonic-gate 			 * back is for the close() routine to set
490*7c478bd9Sstevel@tonic-gate 			 * the errno and socket_close() will return
491*7c478bd9Sstevel@tonic-gate 			 * an error.  But the close operation will
492*7c478bd9Sstevel@tonic-gate 			 * not be stopped.
493*7c478bd9Sstevel@tonic-gate 			 */
494*7c478bd9Sstevel@tonic-gate 			(void) sockets[sock_id].close[i](sock_id);
495*7c478bd9Sstevel@tonic-gate 		}
496*7c478bd9Sstevel@tonic-gate 	}
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	/*
499*7c478bd9Sstevel@tonic-gate 	 * Clear the input queue.  This has to be done
500*7c478bd9Sstevel@tonic-gate 	 * after the lower level protocol close routines have been
501*7c478bd9Sstevel@tonic-gate 	 * called as they may want to do something about the queue.
502*7c478bd9Sstevel@tonic-gate 	 */
503*7c478bd9Sstevel@tonic-gate 	nuke_grams(&sockets[sock_id].inq);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&sockets[sock_id], sizeof (struct inetboot_socket));
506*7c478bd9Sstevel@tonic-gate 	sockets[sock_id].type = INETBOOT_UNUSED;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	return (0);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate /*
512*7c478bd9Sstevel@tonic-gate  * Read up to `nbyte' of data from socket `s' into `buf'; if non-zero,
513*7c478bd9Sstevel@tonic-gate  * then give up after `read_timeout' seconds.  Returns the number of
514*7c478bd9Sstevel@tonic-gate  * bytes read, or -1 on failure.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate int
517*7c478bd9Sstevel@tonic-gate socket_read(int s, void *buf, size_t nbyte, int read_timeout)
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	ssize_t	n;
520*7c478bd9Sstevel@tonic-gate 	uint_t	start, diff;
521*7c478bd9Sstevel@tonic-gate 	struct sockaddr from;
522*7c478bd9Sstevel@tonic-gate 	uint_t fromlen = sizeof (from);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	/*
525*7c478bd9Sstevel@tonic-gate 	 * keep calling non-blocking recvfrom until something received
526*7c478bd9Sstevel@tonic-gate 	 * or an error occurs
527*7c478bd9Sstevel@tonic-gate 	 */
528*7c478bd9Sstevel@tonic-gate 	start = prom_gettime();
529*7c478bd9Sstevel@tonic-gate 	while ((n = recvfrom(s, buf, nbyte, 0, &from, &fromlen)) == 0) {
530*7c478bd9Sstevel@tonic-gate 		diff = (uint_t)((prom_gettime() - start) + 500) / 1000;
531*7c478bd9Sstevel@tonic-gate 		if (read_timeout != 0 && diff > read_timeout) {
532*7c478bd9Sstevel@tonic-gate 			errno = EINTR;
533*7c478bd9Sstevel@tonic-gate 			return (-1);
534*7c478bd9Sstevel@tonic-gate 		}
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate 	return (n);
537*7c478bd9Sstevel@tonic-gate }
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate /*
540*7c478bd9Sstevel@tonic-gate  * Write up to `nbyte' bytes of data from `buf' to the address pointed to
541*7c478bd9Sstevel@tonic-gate  * `addr' using socket `s'.  Returns the number of bytes writte on success,
542*7c478bd9Sstevel@tonic-gate  * or -1 on failure.
543*7c478bd9Sstevel@tonic-gate  */
544*7c478bd9Sstevel@tonic-gate int
545*7c478bd9Sstevel@tonic-gate socket_write(int s, const void *buf, size_t nbyte, struct sockaddr_in *addr)
546*7c478bd9Sstevel@tonic-gate {
547*7c478bd9Sstevel@tonic-gate 	return (sendto(s, buf, nbyte, 0, (struct sockaddr *)addr,
548*7c478bd9Sstevel@tonic-gate 	    sizeof (*addr)));
549*7c478bd9Sstevel@tonic-gate }
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate static int
552*7c478bd9Sstevel@tonic-gate bind_check(int sock_id, const struct sockaddr *addr)
553*7c478bd9Sstevel@tonic-gate {
554*7c478bd9Sstevel@tonic-gate 	int k;
555*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	/* Do not check for duplicate bind() if SO_REUSEADDR option is set. */
558*7c478bd9Sstevel@tonic-gate 	if (! (sockets[sock_id].so_opt & SO_REUSEADDR)) {
559*7c478bd9Sstevel@tonic-gate 		for (k = 0; k < MAXSOCKET; k++) {
560*7c478bd9Sstevel@tonic-gate 			if (sockets[k].type != INETBOOT_UNUSED &&
561*7c478bd9Sstevel@tonic-gate 			    sockets[k].proto == sockets[sock_id].proto &&
562*7c478bd9Sstevel@tonic-gate 			    sockets[k].bound) {
563*7c478bd9Sstevel@tonic-gate 				if ((sockets[k].bind.sin_addr.s_addr ==
564*7c478bd9Sstevel@tonic-gate 				    in_addr->sin_addr.s_addr) &&
565*7c478bd9Sstevel@tonic-gate 				    (sockets[k].bind.sin_port ==
566*7c478bd9Sstevel@tonic-gate 				    in_addr->sin_port)) {
567*7c478bd9Sstevel@tonic-gate 					errno = EADDRINUSE;
568*7c478bd9Sstevel@tonic-gate 					return (-1);
569*7c478bd9Sstevel@tonic-gate 				}
570*7c478bd9Sstevel@tonic-gate 			}
571*7c478bd9Sstevel@tonic-gate 		}
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 	return (0);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /* Assign a name to an unnamed socket. */
577*7c478bd9Sstevel@tonic-gate int
578*7c478bd9Sstevel@tonic-gate bind(int s, const struct sockaddr *name, socklen_t namelen)
579*7c478bd9Sstevel@tonic-gate {
580*7c478bd9Sstevel@tonic-gate 	int i;
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	errno = 0;
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	if ((i = so_check_fd(s, &errno)) == -1)
585*7c478bd9Sstevel@tonic-gate 		return (-1);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	if (name == NULL) {
588*7c478bd9Sstevel@tonic-gate 		/* unbind */
589*7c478bd9Sstevel@tonic-gate 		if (sockets[i].bound) {
590*7c478bd9Sstevel@tonic-gate 			bzero((caddr_t)&sockets[i].bind,
591*7c478bd9Sstevel@tonic-gate 			    sizeof (struct sockaddr_in));
592*7c478bd9Sstevel@tonic-gate 			sockets[i].bound = B_FALSE;
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 		return (0);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 	if (namelen != sizeof (struct sockaddr_in) || name == NULL) {
597*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
598*7c478bd9Sstevel@tonic-gate 		return (-1);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 	if (name->sa_family != AF_INET) {
601*7c478bd9Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
602*7c478bd9Sstevel@tonic-gate 		return (-1);
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 	if (sockets[i].bound) {
605*7c478bd9Sstevel@tonic-gate 		if (bcmp((caddr_t)&sockets[i].bind, (caddr_t)name,
606*7c478bd9Sstevel@tonic-gate 		    namelen) == 0) {
607*7c478bd9Sstevel@tonic-gate 			/* attempt to bind to same address ok... */
608*7c478bd9Sstevel@tonic-gate 			return (0);
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;	/* already bound */
611*7c478bd9Sstevel@tonic-gate 		return (-1);
612*7c478bd9Sstevel@tonic-gate 	}
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
615*7c478bd9Sstevel@tonic-gate 		return (-1);
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	/* Check for duplicate bind(). */
619*7c478bd9Sstevel@tonic-gate 	if (bind_check(i, name) < 0)
620*7c478bd9Sstevel@tonic-gate 		return (-1);
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)name, (caddr_t)&sockets[i].bind, namelen);
623*7c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_STREAM) {
624*7c478bd9Sstevel@tonic-gate 		if (tcp_bind(i) < 0) {
625*7c478bd9Sstevel@tonic-gate 			return (-1);
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 	sockets[i].bound = B_TRUE;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	return (0);
631*7c478bd9Sstevel@tonic-gate }
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate static int
634*7c478bd9Sstevel@tonic-gate quickbind(int sock_id)
635*7c478bd9Sstevel@tonic-gate {
636*7c478bd9Sstevel@tonic-gate 	int i;
637*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in addr;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	/*
640*7c478bd9Sstevel@tonic-gate 	 * XXX This needs more work.  Right now, if ipv4_setipaddr()
641*7c478bd9Sstevel@tonic-gate 	 * have not been called, this will be wrong.  But we need
642*7c478bd9Sstevel@tonic-gate 	 * something better.  Need to be revisited.
643*7c478bd9Sstevel@tonic-gate 	 */
644*7c478bd9Sstevel@tonic-gate 	ipv4_getipaddr(&addr.sin_addr);
645*7c478bd9Sstevel@tonic-gate 	addr.sin_family = AF_INET;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	for (i = SMALLEST_ANON_PORT; i <= LARGEST_ANON_PORT; i++) {
648*7c478bd9Sstevel@tonic-gate 		addr.sin_port = htons(i);
649*7c478bd9Sstevel@tonic-gate 		if (bind_check(sock_id, (struct sockaddr *)&addr) == 0)
650*7c478bd9Sstevel@tonic-gate 			break;
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 	/* Need to clear errno as it is probably set by bind_check(). */
653*7c478bd9Sstevel@tonic-gate 	errno = 0;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	if (i <= LARGEST_ANON_PORT) {
656*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&addr, (caddr_t)&sockets[sock_id].bind,
657*7c478bd9Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
658*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].bound = B_TRUE;
659*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
660*7c478bd9Sstevel@tonic-gate 		printf("quick bind done addr %s port %d\n",
661*7c478bd9Sstevel@tonic-gate 		    inet_ntoa(sockets[sock_id].bind.sin_addr),
662*7c478bd9Sstevel@tonic-gate 			ntohs(sockets[sock_id].bind.sin_port));
663*7c478bd9Sstevel@tonic-gate #endif
664*7c478bd9Sstevel@tonic-gate 		return (0);
665*7c478bd9Sstevel@tonic-gate 	} else {
666*7c478bd9Sstevel@tonic-gate 		return (-1);
667*7c478bd9Sstevel@tonic-gate 	}
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate int
671*7c478bd9Sstevel@tonic-gate listen(int fd, int backlog)
672*7c478bd9Sstevel@tonic-gate {
673*7c478bd9Sstevel@tonic-gate 	int sock_id;
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	errno = 0;
676*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
677*7c478bd9Sstevel@tonic-gate 		return (-1);
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
680*7c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
681*7c478bd9Sstevel@tonic-gate 		return (-1);
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
684*7c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
685*7c478bd9Sstevel@tonic-gate 		return (-1);
686*7c478bd9Sstevel@tonic-gate 	}
687*7c478bd9Sstevel@tonic-gate 	return (tcp_listen(sock_id, backlog));
688*7c478bd9Sstevel@tonic-gate }
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate int
691*7c478bd9Sstevel@tonic-gate accept(int fd, struct sockaddr *addr,  socklen_t *addr_len)
692*7c478bd9Sstevel@tonic-gate {
693*7c478bd9Sstevel@tonic-gate 	int sock_id;
694*7c478bd9Sstevel@tonic-gate 	int new_sd;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	errno = 0;
697*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
698*7c478bd9Sstevel@tonic-gate 		return (-1);
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type != INETBOOT_STREAM) {
701*7c478bd9Sstevel@tonic-gate 		errno = EOPNOTSUPP;
702*7c478bd9Sstevel@tonic-gate 		return (-1);
703*7c478bd9Sstevel@tonic-gate 	}
704*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
705*7c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
706*7c478bd9Sstevel@tonic-gate 		return (-1);
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 	if ((new_sd = tcp_accept(sock_id, addr, addr_len)) == -1)
709*7c478bd9Sstevel@tonic-gate 		return (-1);
710*7c478bd9Sstevel@tonic-gate 	sock_id = so_check_fd(new_sd, &errno);
711*7c478bd9Sstevel@tonic-gate 	sockets[sock_id].so_state |= SS_ISCONNECTED;
712*7c478bd9Sstevel@tonic-gate 	return (new_sd);
713*7c478bd9Sstevel@tonic-gate }
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate int
716*7c478bd9Sstevel@tonic-gate connect(int fd, const  struct sockaddr *addr, socklen_t addr_len)
717*7c478bd9Sstevel@tonic-gate {
718*7c478bd9Sstevel@tonic-gate 	int sock_id;
719*7c478bd9Sstevel@tonic-gate 	int so_type;
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	errno = 0;
722*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(fd, &errno)) == -1)
723*7c478bd9Sstevel@tonic-gate 		return (-1);
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	if (addr == NULL || addr_len == 0) {
728*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
729*7c478bd9Sstevel@tonic-gate 		return (-1);
730*7c478bd9Sstevel@tonic-gate 	}
731*7c478bd9Sstevel@tonic-gate 	/* Don't allow connect for raw socket. */
732*7c478bd9Sstevel@tonic-gate 	if (so_type == INETBOOT_RAW) {
733*7c478bd9Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
734*7c478bd9Sstevel@tonic-gate 		return (-1);
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_state & SS_ISCONNECTED) {
738*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
739*7c478bd9Sstevel@tonic-gate 		return (-1);
740*7c478bd9Sstevel@tonic-gate 	}
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
743*7c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
744*7c478bd9Sstevel@tonic-gate 		return (-1);
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	/* If the socket is not bound, we need to do a quick bind. */
748*7c478bd9Sstevel@tonic-gate 	if (!sockets[sock_id].bound) {
749*7c478bd9Sstevel@tonic-gate 		/* For TCP socket, just call tcp_bind(). */
750*7c478bd9Sstevel@tonic-gate 		if (so_type == INETBOOT_STREAM) {
751*7c478bd9Sstevel@tonic-gate 			if (tcp_bind(sock_id) < 0)
752*7c478bd9Sstevel@tonic-gate 				return (-1);
753*7c478bd9Sstevel@tonic-gate 		} else {
754*7c478bd9Sstevel@tonic-gate 			if (quickbind(sock_id) < 0) {
755*7c478bd9Sstevel@tonic-gate 				errno = EADDRNOTAVAIL;
756*7c478bd9Sstevel@tonic-gate 				return (-1);
757*7c478bd9Sstevel@tonic-gate 			}
758*7c478bd9Sstevel@tonic-gate 		}
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 	/* Should do some sanity check for addr .... */
761*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)addr, &sockets[sock_id].remote,
762*7c478bd9Sstevel@tonic-gate 	    sizeof (struct sockaddr_in));
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM) {
765*7c478bd9Sstevel@tonic-gate 		/* Call TCP connect routine. */
766*7c478bd9Sstevel@tonic-gate 		if (tcp_connect(sock_id) == 0)
767*7c478bd9Sstevel@tonic-gate 			sockets[sock_id].so_state |= SS_ISCONNECTED;
768*7c478bd9Sstevel@tonic-gate 		else {
769*7c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0)
770*7c478bd9Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
771*7c478bd9Sstevel@tonic-gate 			return (-1);
772*7c478bd9Sstevel@tonic-gate 		}
773*7c478bd9Sstevel@tonic-gate 	} else {
774*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_state |= SS_ISCONNECTED;
775*7c478bd9Sstevel@tonic-gate 	}
776*7c478bd9Sstevel@tonic-gate 	return (0);
777*7c478bd9Sstevel@tonic-gate }
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate /* Just a wrapper around recvfrom(). */
780*7c478bd9Sstevel@tonic-gate ssize_t
781*7c478bd9Sstevel@tonic-gate recv(int s, void *buf, size_t len, int flags)
782*7c478bd9Sstevel@tonic-gate {
783*7c478bd9Sstevel@tonic-gate 	return (recvfrom(s, buf, len, flags, NULL, NULL));
784*7c478bd9Sstevel@tonic-gate }
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate /*
787*7c478bd9Sstevel@tonic-gate  * Receive messages from a connectionless socket. Legal flags are 0 and
788*7c478bd9Sstevel@tonic-gate  * MSG_DONTWAIT. MSG_WAITALL is not currently supported.
789*7c478bd9Sstevel@tonic-gate  *
790*7c478bd9Sstevel@tonic-gate  * Returns length of message for success, -1 if error occurred.
791*7c478bd9Sstevel@tonic-gate  */
792*7c478bd9Sstevel@tonic-gate ssize_t
793*7c478bd9Sstevel@tonic-gate recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
794*7c478bd9Sstevel@tonic-gate     socklen_t *fromlen)
795*7c478bd9Sstevel@tonic-gate {
796*7c478bd9Sstevel@tonic-gate 	int			sock_id, i;
797*7c478bd9Sstevel@tonic-gate 	ssize_t			datalen, bytes = 0;
798*7c478bd9Sstevel@tonic-gate 	struct inetgram		*icp;
799*7c478bd9Sstevel@tonic-gate 	enum SockType		so_type;
800*7c478bd9Sstevel@tonic-gate 	char			*tmp_buf;
801*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	errno = 0;
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
806*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
807*7c478bd9Sstevel@tonic-gate 		return (-1);
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].type == INETBOOT_STREAM &&
811*7c478bd9Sstevel@tonic-gate 	    !(sockets[sock_id].so_state & SS_ISCONNECTED)) {
812*7c478bd9Sstevel@tonic-gate 		errno = ENOTCONN;
813*7c478bd9Sstevel@tonic-gate 		return (-1);
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if (buf == NULL || len == 0) {
817*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
818*7c478bd9Sstevel@tonic-gate 		return (-1);
819*7c478bd9Sstevel@tonic-gate 	}
820*7c478bd9Sstevel@tonic-gate 	/* Yup - MSG_WAITALL not implemented */
821*7c478bd9Sstevel@tonic-gate 	if ((flags & ~MSG_DONTWAIT) != 0) {
822*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
823*7c478bd9Sstevel@tonic-gate 		return (-1);
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate retry:
827*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].inq == NULL) {
828*7c478bd9Sstevel@tonic-gate 		/* Go out and check the wire */
829*7c478bd9Sstevel@tonic-gate 		for (i = MEDIA_LVL; i < APP_LVL; i++) {
830*7c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].input[i] != NULL) {
831*7c478bd9Sstevel@tonic-gate 				if (sockets[sock_id].input[i](sock_id) < 0) {
832*7c478bd9Sstevel@tonic-gate 					if (sockets[sock_id].so_error != 0) {
833*7c478bd9Sstevel@tonic-gate 						errno =
834*7c478bd9Sstevel@tonic-gate 						    sockets[sock_id].so_error;
835*7c478bd9Sstevel@tonic-gate 					}
836*7c478bd9Sstevel@tonic-gate 					return (-1);
837*7c478bd9Sstevel@tonic-gate 				}
838*7c478bd9Sstevel@tonic-gate 			}
839*7c478bd9Sstevel@tonic-gate 		}
840*7c478bd9Sstevel@tonic-gate 	}
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	/* Remove unknown inetgrams from the head of inq.  Can this happen? */
845*7c478bd9Sstevel@tonic-gate 	while ((icp = sockets[sock_id].inq) != NULL) {
846*7c478bd9Sstevel@tonic-gate 		if ((so_type == INETBOOT_DGRAM ||
847*7c478bd9Sstevel@tonic-gate 		    so_type == INETBOOT_STREAM) &&
848*7c478bd9Sstevel@tonic-gate 		    icp->igm_level != APP_LVL) {
849*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
850*7c478bd9Sstevel@tonic-gate 			printf("recvfrom: unexpected level %d frame found\n",
851*7c478bd9Sstevel@tonic-gate 			    icp->igm_level);
852*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
853*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
854*7c478bd9Sstevel@tonic-gate 			continue;
855*7c478bd9Sstevel@tonic-gate 		} else {
856*7c478bd9Sstevel@tonic-gate 			break;
857*7c478bd9Sstevel@tonic-gate 		}
858*7c478bd9Sstevel@tonic-gate 	}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	if (icp == NULL) {
862*7c478bd9Sstevel@tonic-gate 		/*
863*7c478bd9Sstevel@tonic-gate 		 * Checking for error should be done everytime a lower layer
864*7c478bd9Sstevel@tonic-gate 		 * input routing is called.  For example, if TCP gets a RST,
865*7c478bd9Sstevel@tonic-gate 		 * this should be reported asap.
866*7c478bd9Sstevel@tonic-gate 		 */
867*7c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTRCVMORE) {
868*7c478bd9Sstevel@tonic-gate 			if (sockets[sock_id].so_error != 0) {
869*7c478bd9Sstevel@tonic-gate 				errno = sockets[sock_id].so_error;
870*7c478bd9Sstevel@tonic-gate 				return (-1);
871*7c478bd9Sstevel@tonic-gate 			} else {
872*7c478bd9Sstevel@tonic-gate 				return (0);
873*7c478bd9Sstevel@tonic-gate 			}
874*7c478bd9Sstevel@tonic-gate 		}
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 		if ((flags & MSG_DONTWAIT) == 0)
877*7c478bd9Sstevel@tonic-gate 			goto retry;	/* wait forever */
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 		/* no data */
880*7c478bd9Sstevel@tonic-gate 		errno = EWOULDBLOCK;
881*7c478bd9Sstevel@tonic-gate 		return (-1);
882*7c478bd9Sstevel@tonic-gate 	}
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	if (from != NULL && fromlen != NULL) {
885*7c478bd9Sstevel@tonic-gate 		switch (so_type) {
886*7c478bd9Sstevel@tonic-gate 		case INETBOOT_STREAM:
887*7c478bd9Sstevel@tonic-gate 			/* Need to copy from the socket's remote address. */
888*7c478bd9Sstevel@tonic-gate 			bcopy(&(sockets[sock_id].remote), from, MIN(*fromlen,
889*7c478bd9Sstevel@tonic-gate 			    sizeof (struct sockaddr_in)));
890*7c478bd9Sstevel@tonic-gate 			break;
891*7c478bd9Sstevel@tonic-gate 		case INETBOOT_RAW:
892*7c478bd9Sstevel@tonic-gate 		case INETBOOT_DGRAM:
893*7c478bd9Sstevel@tonic-gate 		default:
894*7c478bd9Sstevel@tonic-gate 			if (*fromlen > sizeof (icp->igm_saddr))
895*7c478bd9Sstevel@tonic-gate 				*fromlen = sizeof (icp->igm_saddr);
896*7c478bd9Sstevel@tonic-gate 			bcopy((caddr_t)&(icp->igm_saddr), (caddr_t)from,
897*7c478bd9Sstevel@tonic-gate 			    MIN(*fromlen, sizeof (struct sockaddr_in)));
898*7c478bd9Sstevel@tonic-gate 			break;
899*7c478bd9Sstevel@tonic-gate 		}
900*7c478bd9Sstevel@tonic-gate 	}
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	mp = icp->igm_mp;
903*7c478bd9Sstevel@tonic-gate 	switch (so_type) {
904*7c478bd9Sstevel@tonic-gate 	case INETBOOT_STREAM:
905*7c478bd9Sstevel@tonic-gate 		/*
906*7c478bd9Sstevel@tonic-gate 		 * If the message has igm_id == TCP_CALLB_MAGIC_ID, we need
907*7c478bd9Sstevel@tonic-gate 		 * to drain the data held by tcp and try again.
908*7c478bd9Sstevel@tonic-gate 		 */
909*7c478bd9Sstevel@tonic-gate 		if (icp->igm_id == TCP_CALLB_MAGIC_ID) {
910*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[sock_id].inq, icp, B_TRUE);
911*7c478bd9Sstevel@tonic-gate 			tcp_rcv_drain_sock(sock_id);
912*7c478bd9Sstevel@tonic-gate 			goto retry;
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 		/* TCP should put only user data in the inetgram. */
916*7c478bd9Sstevel@tonic-gate 		tmp_buf = (char *)buf;
917*7c478bd9Sstevel@tonic-gate 		while (len > 0 && icp != NULL) {
918*7c478bd9Sstevel@tonic-gate 			datalen = mp->b_wptr - mp->b_rptr;
919*7c478bd9Sstevel@tonic-gate 			if (len < datalen) {
920*7c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, len);
921*7c478bd9Sstevel@tonic-gate 				bytes += len;
922*7c478bd9Sstevel@tonic-gate 				mp->b_rptr += len;
923*7c478bd9Sstevel@tonic-gate 				break;
924*7c478bd9Sstevel@tonic-gate 			} else {
925*7c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, tmp_buf, datalen);
926*7c478bd9Sstevel@tonic-gate 				len -= datalen;
927*7c478bd9Sstevel@tonic-gate 				bytes += datalen;
928*7c478bd9Sstevel@tonic-gate 				tmp_buf += datalen;
929*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[sock_id].inq, icp, B_TRUE);
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 				/*
932*7c478bd9Sstevel@tonic-gate 				 * If we have any embedded magic messages just
933*7c478bd9Sstevel@tonic-gate 				 * drop them.
934*7c478bd9Sstevel@tonic-gate 				 */
935*7c478bd9Sstevel@tonic-gate 				while ((icp = sockets[sock_id].inq) != NULL) {
936*7c478bd9Sstevel@tonic-gate 					if (icp->igm_id != TCP_CALLB_MAGIC_ID)
937*7c478bd9Sstevel@tonic-gate 						break;
938*7c478bd9Sstevel@tonic-gate 					del_gram(&sockets[sock_id].inq, icp,
939*7c478bd9Sstevel@tonic-gate 						B_TRUE);
940*7c478bd9Sstevel@tonic-gate 				}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 				if (icp == NULL)
943*7c478bd9Sstevel@tonic-gate 					break;
944*7c478bd9Sstevel@tonic-gate 				mp = icp->igm_mp;
945*7c478bd9Sstevel@tonic-gate 			}
946*7c478bd9Sstevel@tonic-gate 		}
947*7c478bd9Sstevel@tonic-gate 		sockets[sock_id].so_rcvbuf += (int32_t)bytes;
948*7c478bd9Sstevel@tonic-gate 		break;
949*7c478bd9Sstevel@tonic-gate 	case INETBOOT_DGRAM:
950*7c478bd9Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
951*7c478bd9Sstevel@tonic-gate 		if (len < datalen)
952*7c478bd9Sstevel@tonic-gate 			bytes = len;
953*7c478bd9Sstevel@tonic-gate 		else
954*7c478bd9Sstevel@tonic-gate 			bytes = datalen;
955*7c478bd9Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
956*7c478bd9Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
957*7c478bd9Sstevel@tonic-gate 		break;
958*7c478bd9Sstevel@tonic-gate 	case INETBOOT_RAW:
959*7c478bd9Sstevel@tonic-gate 	default:
960*7c478bd9Sstevel@tonic-gate 		datalen = mp->b_wptr - mp->b_rptr;
961*7c478bd9Sstevel@tonic-gate 		if (len < datalen)
962*7c478bd9Sstevel@tonic-gate 			bytes = len;
963*7c478bd9Sstevel@tonic-gate 		else
964*7c478bd9Sstevel@tonic-gate 			bytes = datalen;
965*7c478bd9Sstevel@tonic-gate 		bcopy(mp->b_rptr, buf, bytes);
966*7c478bd9Sstevel@tonic-gate 		del_gram(&sockets[sock_id].inq, icp, B_TRUE);
967*7c478bd9Sstevel@tonic-gate 		break;
968*7c478bd9Sstevel@tonic-gate 	}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
971*7c478bd9Sstevel@tonic-gate 	printf("recvfrom(%d): data: (0x%x,%d)\n", sock_id,
972*7c478bd9Sstevel@tonic-gate 	    (icp != NULL) ? icp->igm_mp : 0, bytes);
973*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
974*7c478bd9Sstevel@tonic-gate 	return (bytes);
975*7c478bd9Sstevel@tonic-gate }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate /* Just a wrapper around sendto(). */
979*7c478bd9Sstevel@tonic-gate ssize_t
980*7c478bd9Sstevel@tonic-gate send(int s, const void *msg, size_t len, int flags)
981*7c478bd9Sstevel@tonic-gate {
982*7c478bd9Sstevel@tonic-gate 	return (sendto(s, msg, len, flags, NULL, 0));
983*7c478bd9Sstevel@tonic-gate }
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate /*
986*7c478bd9Sstevel@tonic-gate  * Transmit a message through a socket.
987*7c478bd9Sstevel@tonic-gate  *
988*7c478bd9Sstevel@tonic-gate  * Supported flags: MSG_DONTROUTE or 0.
989*7c478bd9Sstevel@tonic-gate  */
990*7c478bd9Sstevel@tonic-gate ssize_t
991*7c478bd9Sstevel@tonic-gate sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to,
992*7c478bd9Sstevel@tonic-gate     socklen_t tolen)
993*7c478bd9Sstevel@tonic-gate {
994*7c478bd9Sstevel@tonic-gate 	enum SockType so_type;
995*7c478bd9Sstevel@tonic-gate 	int sock_id;
996*7c478bd9Sstevel@tonic-gate 	ssize_t bytes;
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	errno = 0;
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	if ((sock_id = so_check_fd(s, &errno)) == -1) {
1001*7c478bd9Sstevel@tonic-gate 		return (-1);
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate 	if (msg == NULL) {
1004*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1005*7c478bd9Sstevel@tonic-gate 		return (-1);
1006*7c478bd9Sstevel@tonic-gate 	}
1007*7c478bd9Sstevel@tonic-gate 	so_type = sockets[sock_id].type;
1008*7c478bd9Sstevel@tonic-gate 	if ((flags & ~MSG_DONTROUTE) != 0) {
1009*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1010*7c478bd9Sstevel@tonic-gate 		return (-1);
1011*7c478bd9Sstevel@tonic-gate 	}
1012*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].so_error != 0) {
1013*7c478bd9Sstevel@tonic-gate 		errno = sockets[sock_id].so_error;
1014*7c478bd9Sstevel@tonic-gate 		return (-1);
1015*7c478bd9Sstevel@tonic-gate 	}
1016*7c478bd9Sstevel@tonic-gate 	if (to != NULL && to->sa_family != AF_INET) {
1017*7c478bd9Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
1018*7c478bd9Sstevel@tonic-gate 		return (-1);
1019*7c478bd9Sstevel@tonic-gate 	}
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	switch (so_type) {
1022*7c478bd9Sstevel@tonic-gate 	case INETBOOT_RAW:
1023*7c478bd9Sstevel@tonic-gate 	case INETBOOT_DGRAM:
1024*7c478bd9Sstevel@tonic-gate 		if (!(sockets[sock_id].so_state & SS_ISCONNECTED) &&
1025*7c478bd9Sstevel@tonic-gate 		    (to == NULL || tolen != sizeof (struct sockaddr_in))) {
1026*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1027*7c478bd9Sstevel@tonic-gate 			return (-1);
1028*7c478bd9Sstevel@tonic-gate 		}
1029*7c478bd9Sstevel@tonic-gate 		bytes = dgram_sendto(sock_id, msg, len, flags, to, tolen);
1030*7c478bd9Sstevel@tonic-gate 		break;
1031*7c478bd9Sstevel@tonic-gate 	case INETBOOT_STREAM:
1032*7c478bd9Sstevel@tonic-gate 		if (!((sockets[sock_id].so_state & SS_ISCONNECTED) ||
1033*7c478bd9Sstevel@tonic-gate 		    (sockets[sock_id].so_state & SS_ISCONNECTING))) {
1034*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1035*7c478bd9Sstevel@tonic-gate 			return (-1);
1036*7c478bd9Sstevel@tonic-gate 		}
1037*7c478bd9Sstevel@tonic-gate 		if (sockets[sock_id].so_state & SS_CANTSENDMORE) {
1038*7c478bd9Sstevel@tonic-gate 			errno = EPIPE;
1039*7c478bd9Sstevel@tonic-gate 			return (-1);
1040*7c478bd9Sstevel@tonic-gate 		}
1041*7c478bd9Sstevel@tonic-gate 		bytes = stream_sendto(sock_id, msg, len, flags);
1042*7c478bd9Sstevel@tonic-gate 		break;
1043*7c478bd9Sstevel@tonic-gate 	default:
1044*7c478bd9Sstevel@tonic-gate 		/* Should not happen... */
1045*7c478bd9Sstevel@tonic-gate 		errno = EPROTOTYPE;
1046*7c478bd9Sstevel@tonic-gate 		return (-1);
1047*7c478bd9Sstevel@tonic-gate 	}
1048*7c478bd9Sstevel@tonic-gate 	return (bytes);
1049*7c478bd9Sstevel@tonic-gate }
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate static ssize_t
1052*7c478bd9Sstevel@tonic-gate dgram_sendto(int i, const void *msg, size_t len, int flags,
1053*7c478bd9Sstevel@tonic-gate     const struct sockaddr *to, int tolen)
1054*7c478bd9Sstevel@tonic-gate {
1055*7c478bd9Sstevel@tonic-gate 	struct inetgram		oc;
1056*7c478bd9Sstevel@tonic-gate 	int			l, offset;
1057*7c478bd9Sstevel@tonic-gate 	size_t			tlen;
1058*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1061*7c478bd9Sstevel@tonic-gate 	{
1062*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin = (struct sockaddr_in *)to;
1063*7c478bd9Sstevel@tonic-gate 	printf("sendto(%d): msg of length: %d sent to port %d and host: %s\n",
1064*7c478bd9Sstevel@tonic-gate 	    i, len, ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
1065*7c478bd9Sstevel@tonic-gate 	}
1066*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	nuke_grams(&sockets[i].inq); /* flush the input queue */
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 	/* calculate offset for data */
1071*7c478bd9Sstevel@tonic-gate 	offset = sockets[i].headerlen[MEDIA_LVL](NULL) +
1072*7c478bd9Sstevel@tonic-gate 	    (sockets[i].headerlen[NETWORK_LVL])(NULL);
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&oc, sizeof (oc));
1075*7c478bd9Sstevel@tonic-gate 	if (sockets[i].type != INETBOOT_RAW) {
1076*7c478bd9Sstevel@tonic-gate 		offset += (sockets[i].headerlen[TRANSPORT_LVL])(NULL);
1077*7c478bd9Sstevel@tonic-gate 		oc.igm_level = TRANSPORT_LVL;
1078*7c478bd9Sstevel@tonic-gate 	} else
1079*7c478bd9Sstevel@tonic-gate 		oc.igm_level = NETWORK_LVL;
1080*7c478bd9Sstevel@tonic-gate 	oc.igm_oflags = flags;
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	if (to != NULL) {
1083*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)to, (caddr_t)&oc.igm_saddr, tolen);
1084*7c478bd9Sstevel@tonic-gate 	} else {
1085*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&sockets[i].remote, (caddr_t)&oc.igm_saddr,
1086*7c478bd9Sstevel@tonic-gate 		    sizeof (struct sockaddr_in));
1087*7c478bd9Sstevel@tonic-gate 	}
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	/* Get a legal source port if the socket isn't bound. */
1090*7c478bd9Sstevel@tonic-gate 	if (sockets[i].bound == B_FALSE &&
1091*7c478bd9Sstevel@tonic-gate 	    ntohs(oc.igm_saddr.sin_port == 0)) {
1092*7c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)&oc.igm_saddr)->sin_port =
1093*7c478bd9Sstevel@tonic-gate 		    get_source_port(B_FALSE);
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	/* Round up to 16bit value for checksum purposes */
1097*7c478bd9Sstevel@tonic-gate 	if (sockets[i].type == INETBOOT_DGRAM) {
1098*7c478bd9Sstevel@tonic-gate 		tlen = ((len + sizeof (uint16_t) - 1) &
1099*7c478bd9Sstevel@tonic-gate 		    ~(sizeof (uint16_t) - 1));
1100*7c478bd9Sstevel@tonic-gate 	} else
1101*7c478bd9Sstevel@tonic-gate 		tlen = len;
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	if ((oc.igm_mp = allocb(tlen + offset, 0)) == NULL) {
1104*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1105*7c478bd9Sstevel@tonic-gate 		return (-1);
1106*7c478bd9Sstevel@tonic-gate 	}
1107*7c478bd9Sstevel@tonic-gate 	mp = oc.igm_mp;
1108*7c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr += offset;
1109*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)msg, mp->b_wptr, len);
1110*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += len;
1111*7c478bd9Sstevel@tonic-gate 	for (l = TRANSPORT_LVL; l >= MEDIA_LVL; l--) {
1112*7c478bd9Sstevel@tonic-gate 		if (sockets[i].output[l] != NULL) {
1113*7c478bd9Sstevel@tonic-gate 			if (sockets[i].output[l](i, &oc) < 0) {
1114*7c478bd9Sstevel@tonic-gate 				freeb(mp);
1115*7c478bd9Sstevel@tonic-gate 				if (errno == 0)
1116*7c478bd9Sstevel@tonic-gate 					errno = EIO;
1117*7c478bd9Sstevel@tonic-gate 				return (-1);
1118*7c478bd9Sstevel@tonic-gate 			}
1119*7c478bd9Sstevel@tonic-gate 		}
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 	freeb(mp);
1122*7c478bd9Sstevel@tonic-gate 	return (len);
1123*7c478bd9Sstevel@tonic-gate }
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1126*7c478bd9Sstevel@tonic-gate static ssize_t
1127*7c478bd9Sstevel@tonic-gate stream_sendto(int i, const void *msg, size_t len, int flags)
1128*7c478bd9Sstevel@tonic-gate {
1129*7c478bd9Sstevel@tonic-gate 	int cnt;
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	assert(sockets[i].pcb != NULL);
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 	/*
1134*7c478bd9Sstevel@tonic-gate 	 * Call directly TCP's send routine.  We do this because TCP
1135*7c478bd9Sstevel@tonic-gate 	 * needs to decide whether to send out the data.
1136*7c478bd9Sstevel@tonic-gate 	 *
1137*7c478bd9Sstevel@tonic-gate 	 * Note also that currently, TCP ignores all flags passed in for
1138*7c478bd9Sstevel@tonic-gate 	 * TCP socket.
1139*7c478bd9Sstevel@tonic-gate 	 */
1140*7c478bd9Sstevel@tonic-gate 	if ((cnt = tcp_send(i, sockets[i].pcb, msg, len)) < 0) {
1141*7c478bd9Sstevel@tonic-gate 		if (sockets[i].so_error != 0)
1142*7c478bd9Sstevel@tonic-gate 			errno = sockets[i].so_error;
1143*7c478bd9Sstevel@tonic-gate 		return (-1);
1144*7c478bd9Sstevel@tonic-gate 	} else {
1145*7c478bd9Sstevel@tonic-gate 		return (cnt);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate /*
1150*7c478bd9Sstevel@tonic-gate  * Returns ptr to the last inetgram in the list, or null if list is null
1151*7c478bd9Sstevel@tonic-gate  */
1152*7c478bd9Sstevel@tonic-gate struct inetgram *
1153*7c478bd9Sstevel@tonic-gate last_gram(struct inetgram *igp)
1154*7c478bd9Sstevel@tonic-gate {
1155*7c478bd9Sstevel@tonic-gate 	struct inetgram	*wp;
1156*7c478bd9Sstevel@tonic-gate 	for (wp = igp; wp != NULL; wp = wp->igm_next) {
1157*7c478bd9Sstevel@tonic-gate 		if (wp->igm_next == NULL)
1158*7c478bd9Sstevel@tonic-gate 			return (wp);
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 	return (NULL);
1161*7c478bd9Sstevel@tonic-gate }
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate /*
1164*7c478bd9Sstevel@tonic-gate  * Adds an inetgram or list of inetgrams to the end of the list.
1165*7c478bd9Sstevel@tonic-gate  */
1166*7c478bd9Sstevel@tonic-gate void
1167*7c478bd9Sstevel@tonic-gate add_grams(struct inetgram **igpp, struct inetgram *newgp)
1168*7c478bd9Sstevel@tonic-gate {
1169*7c478bd9Sstevel@tonic-gate 	struct inetgram	 *wp;
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 	if (newgp == NULL)
1172*7c478bd9Sstevel@tonic-gate 		return;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (*igpp == NULL)
1175*7c478bd9Sstevel@tonic-gate 		*igpp = newgp;
1176*7c478bd9Sstevel@tonic-gate 	else {
1177*7c478bd9Sstevel@tonic-gate 		wp = last_gram(*igpp);
1178*7c478bd9Sstevel@tonic-gate 		wp->igm_next = newgp;
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate }
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate /*
1183*7c478bd9Sstevel@tonic-gate  * Nuke a whole list of grams.
1184*7c478bd9Sstevel@tonic-gate  */
1185*7c478bd9Sstevel@tonic-gate void
1186*7c478bd9Sstevel@tonic-gate nuke_grams(struct inetgram **lgpp)
1187*7c478bd9Sstevel@tonic-gate {
1188*7c478bd9Sstevel@tonic-gate 	while (*lgpp != NULL)
1189*7c478bd9Sstevel@tonic-gate 		del_gram(lgpp, *lgpp, B_TRUE);
1190*7c478bd9Sstevel@tonic-gate }
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate /*
1193*7c478bd9Sstevel@tonic-gate  * Remove the referenced inetgram. List is altered accordingly. Destroy the
1194*7c478bd9Sstevel@tonic-gate  * referenced inetgram if freeit is B_TRUE.
1195*7c478bd9Sstevel@tonic-gate  */
1196*7c478bd9Sstevel@tonic-gate void
1197*7c478bd9Sstevel@tonic-gate del_gram(struct inetgram **lgpp, struct inetgram *igp, int freeit)
1198*7c478bd9Sstevel@tonic-gate {
1199*7c478bd9Sstevel@tonic-gate 	struct inetgram	*wp, *pp = NULL;
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 	if (lgpp == NULL || igp == NULL)
1202*7c478bd9Sstevel@tonic-gate 		return;
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	wp = *lgpp;
1205*7c478bd9Sstevel@tonic-gate 	while (wp != NULL) {
1206*7c478bd9Sstevel@tonic-gate 		if (wp == igp) {
1207*7c478bd9Sstevel@tonic-gate 			/* detach wp from the list */
1208*7c478bd9Sstevel@tonic-gate 			if (*lgpp == wp)
1209*7c478bd9Sstevel@tonic-gate 				*lgpp = (*lgpp)->igm_next;
1210*7c478bd9Sstevel@tonic-gate 			else
1211*7c478bd9Sstevel@tonic-gate 				pp->igm_next = wp->igm_next;
1212*7c478bd9Sstevel@tonic-gate 			igp->igm_next = NULL;
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 			if (freeit) {
1215*7c478bd9Sstevel@tonic-gate 				if (igp->igm_mp != NULL)
1216*7c478bd9Sstevel@tonic-gate 					freeb(igp->igm_mp);
1217*7c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)igp,
1218*7c478bd9Sstevel@tonic-gate 				    sizeof (struct inetgram));
1219*7c478bd9Sstevel@tonic-gate 			}
1220*7c478bd9Sstevel@tonic-gate 			break;
1221*7c478bd9Sstevel@tonic-gate 		}
1222*7c478bd9Sstevel@tonic-gate 		pp = wp;
1223*7c478bd9Sstevel@tonic-gate 		wp = wp->igm_next;
1224*7c478bd9Sstevel@tonic-gate 	}
1225*7c478bd9Sstevel@tonic-gate }
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate struct nct_t nct[] = {
1228*7c478bd9Sstevel@tonic-gate 	"bootp",	NCT_BOOTP_DHCP,
1229*7c478bd9Sstevel@tonic-gate 	"dhcp",		NCT_BOOTP_DHCP,
1230*7c478bd9Sstevel@tonic-gate 	"rarp",		NCT_RARP_BOOTPARAMS,
1231*7c478bd9Sstevel@tonic-gate 	"manual",	NCT_MANUAL
1232*7c478bd9Sstevel@tonic-gate };
1233*7c478bd9Sstevel@tonic-gate int	nct_entries = sizeof (nct) / sizeof (nct[0]);
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate /*
1236*7c478bd9Sstevel@tonic-gate  * Figure out from the bootpath what kind of network configuration strategy
1237*7c478bd9Sstevel@tonic-gate  * we should use. Returns the network config strategy.
1238*7c478bd9Sstevel@tonic-gate  */
1239*7c478bd9Sstevel@tonic-gate int
1240*7c478bd9Sstevel@tonic-gate get_netconfig_strategy(void)
1241*7c478bd9Sstevel@tonic-gate {
1242*7c478bd9Sstevel@tonic-gate 	int	i;
1243*7c478bd9Sstevel@tonic-gate #if !defined(__i386)
1244*7c478bd9Sstevel@tonic-gate 	/* sparc */
1245*7c478bd9Sstevel@tonic-gate #define	ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\0')
1246*7c478bd9Sstevel@tonic-gate 	char	lbootpath[OBP_MAXPATHLEN];
1247*7c478bd9Sstevel@tonic-gate 	char	net_options[NCT_BUFSIZE];
1248*7c478bd9Sstevel@tonic-gate 	char	*op, *nop, *sp;
1249*7c478bd9Sstevel@tonic-gate 	dnode_t	cn;
1250*7c478bd9Sstevel@tonic-gate 	int	proplen;
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	/* If the PROM DHCP cache exists, we're done */
1253*7c478bd9Sstevel@tonic-gate 	if (prom_cached_reply(B_TRUE))
1254*7c478bd9Sstevel@tonic-gate 		return (NCT_BOOTP_DHCP);
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	/*
1257*7c478bd9Sstevel@tonic-gate 	 *	Newer (version 4) PROMs will put the name in the
1258*7c478bd9Sstevel@tonic-gate 	 *	"net-config-strategy" property.
1259*7c478bd9Sstevel@tonic-gate 	 */
1260*7c478bd9Sstevel@tonic-gate 	cn = prom_finddevice("/chosen");
1261*7c478bd9Sstevel@tonic-gate 	if ((proplen = prom_getproplen(cn, "net-config-strategy")) <
1262*7c478bd9Sstevel@tonic-gate 	    sizeof (net_options)) {
1263*7c478bd9Sstevel@tonic-gate 		(void) prom_getprop(cn, "net-config-strategy", net_options);
1264*7c478bd9Sstevel@tonic-gate 		net_options[proplen] = '\0';
1265*7c478bd9Sstevel@tonic-gate 	} else {
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 		/*
1268*7c478bd9Sstevel@tonic-gate 		 * We're reduced to sacanning bootpath for the prototol to use.
1269*7c478bd9Sstevel@tonic-gate 		 * Since there was no "net-config-strategy" property, this is
1270*7c478bd9Sstevel@tonic-gate 		 * an old PROM, so we need to excise any extraneous key/value
1271*7c478bd9Sstevel@tonic-gate 		 * initializations from bootpath[].
1272*7c478bd9Sstevel@tonic-gate 		 */
1273*7c478bd9Sstevel@tonic-gate 		for (op = prom_bootpath(), sp = lbootpath; op != NULL &&
1274*7c478bd9Sstevel@tonic-gate 		    !ISSPACE(*op); sp++, op++)
1275*7c478bd9Sstevel@tonic-gate 			*sp = *op;
1276*7c478bd9Sstevel@tonic-gate 		*sp = '\0';
1277*7c478bd9Sstevel@tonic-gate 		/* find the last '/' (in the device path) */
1278*7c478bd9Sstevel@tonic-gate 		if ((op = strrchr(lbootpath, '/')) == NULL)	/* last '/' */
1279*7c478bd9Sstevel@tonic-gate 			op = lbootpath;
1280*7c478bd9Sstevel@tonic-gate 		else
1281*7c478bd9Sstevel@tonic-gate 			op++;
1282*7c478bd9Sstevel@tonic-gate 		/* then look for the ':' separating it from the protocol */
1283*7c478bd9Sstevel@tonic-gate 		while (*op != ':' && *op != '\0')
1284*7c478bd9Sstevel@tonic-gate 			op++;
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 		if (*op == ':') {
1287*7c478bd9Sstevel@tonic-gate 			for (nop = net_options, op++;
1288*7c478bd9Sstevel@tonic-gate 			    *op != '\0' && *op != '/' && !ISSPACE(*op) &&
1289*7c478bd9Sstevel@tonic-gate 			    nop < &net_options[NCT_BUFSIZE]; nop++, op++)
1290*7c478bd9Sstevel@tonic-gate 				*nop = *op;
1291*7c478bd9Sstevel@tonic-gate 			*nop = '\0';
1292*7c478bd9Sstevel@tonic-gate 		} else
1293*7c478bd9Sstevel@tonic-gate 			net_options[0] = '\0';
1294*7c478bd9Sstevel@tonic-gate 	}
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate #undef	ISSPACE
1297*7c478bd9Sstevel@tonic-gate #else
1298*7c478bd9Sstevel@tonic-gate 	/* i86 */
1299*7c478bd9Sstevel@tonic-gate 	extern struct bootops bootops;
1300*7c478bd9Sstevel@tonic-gate 	extern int bgetprop(struct bootops *, char *, caddr_t, int, phandle_t);
1301*7c478bd9Sstevel@tonic-gate 	char	net_options[MAXNAMELEN];
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 	/*
1304*7c478bd9Sstevel@tonic-gate 	 * Look at net-config-strategy boot property to determine what protocol
1305*7c478bd9Sstevel@tonic-gate 	 * will be used.
1306*7c478bd9Sstevel@tonic-gate 	 */
1307*7c478bd9Sstevel@tonic-gate 	(void) bgetprop(&bootops, "net-config-strategy", net_options,
1308*7c478bd9Sstevel@tonic-gate 	    sizeof (net_options), 0);
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate #endif	/* __i386 */
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nct_entries; i++)
1313*7c478bd9Sstevel@tonic-gate 		if (strcmp(net_options, nct[i].p_name) == 0)
1314*7c478bd9Sstevel@tonic-gate 			return (nct[i].p_id);
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	return (NCT_DEFAULT);
1317*7c478bd9Sstevel@tonic-gate }
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate /* Modified STREAM routines for ease of porting core TCP code. */
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1322*7c478bd9Sstevel@tonic-gate mblk_t *
1323*7c478bd9Sstevel@tonic-gate allocb(size_t size, uint_t pri)
1324*7c478bd9Sstevel@tonic-gate {
1325*7c478bd9Sstevel@tonic-gate 	unsigned char *base;
1326*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	if ((mp = (mblk_t *)bkmem_zalloc(sizeof (mblk_t))) == NULL)
1329*7c478bd9Sstevel@tonic-gate 		return (NULL);
1330*7c478bd9Sstevel@tonic-gate 	if ((base = (unsigned char *)bkmem_zalloc(size)) == NULL)
1331*7c478bd9Sstevel@tonic-gate 		return (NULL);
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 	mp->b_next = mp->b_prev = mp->b_cont = NULL;
1334*7c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr = mp->b_datap = (unsigned char *)base;
1335*7c478bd9Sstevel@tonic-gate 	mp->b_size = size;
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	return (mp);
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate void
1341*7c478bd9Sstevel@tonic-gate freeb(mblk_t *mp)
1342*7c478bd9Sstevel@tonic-gate {
1343*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1344*7c478bd9Sstevel@tonic-gate 	printf("freeb datap %x\n", mp->b_datap);
1345*7c478bd9Sstevel@tonic-gate #endif
1346*7c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)(mp->b_datap), mp->b_size);
1347*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1348*7c478bd9Sstevel@tonic-gate 	printf("freeb mp %x\n", mp);
1349*7c478bd9Sstevel@tonic-gate #endif
1350*7c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)mp, sizeof (mblk_t));
1351*7c478bd9Sstevel@tonic-gate }
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate void
1354*7c478bd9Sstevel@tonic-gate freemsg(mblk_t *mp)
1355*7c478bd9Sstevel@tonic-gate {
1356*7c478bd9Sstevel@tonic-gate 	while (mp) {
1357*7c478bd9Sstevel@tonic-gate 		mblk_t *mp_cont = mp->b_cont;
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate 		freeb(mp);
1360*7c478bd9Sstevel@tonic-gate 		mp = mp_cont;
1361*7c478bd9Sstevel@tonic-gate 	}
1362*7c478bd9Sstevel@tonic-gate }
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate mblk_t *
1365*7c478bd9Sstevel@tonic-gate copyb(mblk_t *bp)
1366*7c478bd9Sstevel@tonic-gate {
1367*7c478bd9Sstevel@tonic-gate 	mblk_t *nbp;
1368*7c478bd9Sstevel@tonic-gate 	unsigned char *ndp;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	assert((uintptr_t)(bp->b_wptr - bp->b_rptr) >= 0);
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	if (!(nbp = allocb(bp->b_size, 0)))
1373*7c478bd9Sstevel@tonic-gate 		return (NULL);
1374*7c478bd9Sstevel@tonic-gate 	nbp->b_cont = NULL;
1375*7c478bd9Sstevel@tonic-gate 	ndp = nbp->b_datap;
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 	nbp->b_rptr = ndp + (bp->b_rptr - bp->b_datap);
1378*7c478bd9Sstevel@tonic-gate 	nbp->b_wptr = nbp->b_rptr + (bp->b_wptr - bp->b_rptr);
1379*7c478bd9Sstevel@tonic-gate 	bcopy(bp->b_datap, nbp->b_datap, bp->b_size);
1380*7c478bd9Sstevel@tonic-gate 	return (nbp);
1381*7c478bd9Sstevel@tonic-gate }
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate /* To simplify things, dupb() is implemented as copyb(). */
1384*7c478bd9Sstevel@tonic-gate mblk_t *
1385*7c478bd9Sstevel@tonic-gate dupb(mblk_t *mp)
1386*7c478bd9Sstevel@tonic-gate {
1387*7c478bd9Sstevel@tonic-gate 	return (copyb(mp));
1388*7c478bd9Sstevel@tonic-gate }
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate /*
1391*7c478bd9Sstevel@tonic-gate  * get number of data bytes in message
1392*7c478bd9Sstevel@tonic-gate  */
1393*7c478bd9Sstevel@tonic-gate size_t
1394*7c478bd9Sstevel@tonic-gate msgdsize(mblk_t *bp)
1395*7c478bd9Sstevel@tonic-gate {
1396*7c478bd9Sstevel@tonic-gate 	size_t count = 0;
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate 	for (; bp != NULL; bp = bp->b_cont) {
1399*7c478bd9Sstevel@tonic-gate 		assert(bp->b_wptr >= bp->b_rptr);
1400*7c478bd9Sstevel@tonic-gate 		count += bp->b_wptr - bp->b_rptr;
1401*7c478bd9Sstevel@tonic-gate 	}
1402*7c478bd9Sstevel@tonic-gate 	return (count);
1403*7c478bd9Sstevel@tonic-gate }
1404