xref: /onnv-gate/usr/src/uts/common/fs/sockfs/sockcommon_sops.c (revision 12643:044ff822d212)
18348SEric.Yu@Sun.COM /*
28348SEric.Yu@Sun.COM  * CDDL HEADER START
38348SEric.Yu@Sun.COM  *
48348SEric.Yu@Sun.COM  * The contents of this file are subject to the terms of the
58348SEric.Yu@Sun.COM  * Common Development and Distribution License (the "License").
68348SEric.Yu@Sun.COM  * You may not use this file except in compliance with the License.
78348SEric.Yu@Sun.COM  *
88348SEric.Yu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98348SEric.Yu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108348SEric.Yu@Sun.COM  * See the License for the specific language governing permissions
118348SEric.Yu@Sun.COM  * and limitations under the License.
128348SEric.Yu@Sun.COM  *
138348SEric.Yu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148348SEric.Yu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158348SEric.Yu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168348SEric.Yu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178348SEric.Yu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188348SEric.Yu@Sun.COM  *
198348SEric.Yu@Sun.COM  * CDDL HEADER END
208348SEric.Yu@Sun.COM  */
218348SEric.Yu@Sun.COM 
228348SEric.Yu@Sun.COM /*
2312198SEiji.Ota@Sun.COM  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
248348SEric.Yu@Sun.COM  */
258348SEric.Yu@Sun.COM 
268348SEric.Yu@Sun.COM #include <sys/types.h>
278348SEric.Yu@Sun.COM #include <sys/param.h>
288348SEric.Yu@Sun.COM #include <sys/systm.h>
298348SEric.Yu@Sun.COM #include <sys/sysmacros.h>
308348SEric.Yu@Sun.COM #include <sys/debug.h>
318348SEric.Yu@Sun.COM #include <sys/cmn_err.h>
328348SEric.Yu@Sun.COM 
338348SEric.Yu@Sun.COM #include <sys/stropts.h>
348348SEric.Yu@Sun.COM #include <sys/socket.h>
358348SEric.Yu@Sun.COM #include <sys/socketvar.h>
368348SEric.Yu@Sun.COM 
378348SEric.Yu@Sun.COM #define	_SUN_TPI_VERSION	2
388348SEric.Yu@Sun.COM #include <sys/tihdr.h>
398348SEric.Yu@Sun.COM #include <sys/sockio.h>
408348SEric.Yu@Sun.COM #include <sys/kmem_impl.h>
418348SEric.Yu@Sun.COM 
428348SEric.Yu@Sun.COM #include <sys/strsubr.h>
438348SEric.Yu@Sun.COM #include <sys/strsun.h>
448348SEric.Yu@Sun.COM #include <sys/ddi.h>
458348SEric.Yu@Sun.COM #include <netinet/in.h>
468348SEric.Yu@Sun.COM #include <inet/ip.h>
478348SEric.Yu@Sun.COM 
488348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h>
49*12643SAnders.Persson@Sun.COM #include <fs/sockfs/sockfilter_impl.h>
508348SEric.Yu@Sun.COM 
518348SEric.Yu@Sun.COM #include <sys/socket_proto.h>
528348SEric.Yu@Sun.COM 
538348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi_impl.h>
549491SAnders.Persson@Sun.COM #include <fs/sockfs/sodirect.h>
558348SEric.Yu@Sun.COM #include <sys/tihdr.h>
568348SEric.Yu@Sun.COM #include <fs/sockfs/nl7c.h>
578348SEric.Yu@Sun.COM #include <inet/kssl/ksslapi.h>
588348SEric.Yu@Sun.COM 
598348SEric.Yu@Sun.COM 
608348SEric.Yu@Sun.COM extern int xnet_skip_checks;
618348SEric.Yu@Sun.COM extern int xnet_check_print;
628348SEric.Yu@Sun.COM 
63*12643SAnders.Persson@Sun.COM static void so_queue_oob(struct sonode *, mblk_t *, size_t);
648348SEric.Yu@Sun.COM 
658348SEric.Yu@Sun.COM 
668348SEric.Yu@Sun.COM /*ARGSUSED*/
678348SEric.Yu@Sun.COM int
688348SEric.Yu@Sun.COM so_accept_notsupp(struct sonode *lso, int fflag,
698348SEric.Yu@Sun.COM     struct cred *cr, struct sonode **nsop)
708348SEric.Yu@Sun.COM {
718348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
728348SEric.Yu@Sun.COM }
738348SEric.Yu@Sun.COM 
748348SEric.Yu@Sun.COM /*ARGSUSED*/
758348SEric.Yu@Sun.COM int
768348SEric.Yu@Sun.COM so_listen_notsupp(struct sonode *so, int backlog, struct cred *cr)
778348SEric.Yu@Sun.COM {
788348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
798348SEric.Yu@Sun.COM }
808348SEric.Yu@Sun.COM 
818348SEric.Yu@Sun.COM /*ARGSUSED*/
828348SEric.Yu@Sun.COM int
838348SEric.Yu@Sun.COM so_getsockname_notsupp(struct sonode *so, struct sockaddr *sa,
848348SEric.Yu@Sun.COM     socklen_t *len, struct cred *cr)
858348SEric.Yu@Sun.COM {
868348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
878348SEric.Yu@Sun.COM }
888348SEric.Yu@Sun.COM 
898348SEric.Yu@Sun.COM /*ARGSUSED*/
908348SEric.Yu@Sun.COM int
918348SEric.Yu@Sun.COM so_getpeername_notsupp(struct sonode *so, struct sockaddr *addr,
928348SEric.Yu@Sun.COM     socklen_t *addrlen, boolean_t accept, struct cred *cr)
938348SEric.Yu@Sun.COM {
948348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
958348SEric.Yu@Sun.COM }
968348SEric.Yu@Sun.COM 
978348SEric.Yu@Sun.COM /*ARGSUSED*/
988348SEric.Yu@Sun.COM int
998348SEric.Yu@Sun.COM so_shutdown_notsupp(struct sonode *so, int how, struct cred *cr)
1008348SEric.Yu@Sun.COM {
1018348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
1028348SEric.Yu@Sun.COM }
1038348SEric.Yu@Sun.COM 
1048348SEric.Yu@Sun.COM /*ARGSUSED*/
1058348SEric.Yu@Sun.COM int
1068348SEric.Yu@Sun.COM so_sendmblk_notsupp(struct sonode *so, struct msghdr *msg, int fflag,
1078348SEric.Yu@Sun.COM     struct cred *cr, mblk_t **mpp)
1088348SEric.Yu@Sun.COM {
1098348SEric.Yu@Sun.COM 	return (EOPNOTSUPP);
1108348SEric.Yu@Sun.COM }
1118348SEric.Yu@Sun.COM 
1128348SEric.Yu@Sun.COM /*
1138348SEric.Yu@Sun.COM  * Generic Socket Ops
1148348SEric.Yu@Sun.COM  */
1158348SEric.Yu@Sun.COM 
1168348SEric.Yu@Sun.COM /* ARGSUSED */
1178348SEric.Yu@Sun.COM int
1188348SEric.Yu@Sun.COM so_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1198348SEric.Yu@Sun.COM {
1208348SEric.Yu@Sun.COM 	return (socket_init_common(so, pso, flags, cr));
1218348SEric.Yu@Sun.COM }
1228348SEric.Yu@Sun.COM 
1238348SEric.Yu@Sun.COM int
1248348SEric.Yu@Sun.COM so_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
1258348SEric.Yu@Sun.COM     int flags, struct cred *cr)
1268348SEric.Yu@Sun.COM {
1278348SEric.Yu@Sun.COM 	int error;
1288348SEric.Yu@Sun.COM 
1298348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_BIND(so, name, namelen, flags, cr));
1308348SEric.Yu@Sun.COM 
1318348SEric.Yu@Sun.COM 	ASSERT(flags == _SOBIND_XPG4_2 || flags == _SOBIND_SOCKBSD);
1328348SEric.Yu@Sun.COM 
1338348SEric.Yu@Sun.COM 	/* X/Open requires this check */
1348348SEric.Yu@Sun.COM 	if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) {
1358348SEric.Yu@Sun.COM 		if (xnet_check_print) {
1368348SEric.Yu@Sun.COM 			printf("sockfs: X/Open bind state check "
1378348SEric.Yu@Sun.COM 			    "caused EINVAL\n");
1388348SEric.Yu@Sun.COM 		}
1398348SEric.Yu@Sun.COM 		error = EINVAL;
1408348SEric.Yu@Sun.COM 		goto done;
1418348SEric.Yu@Sun.COM 	}
1428348SEric.Yu@Sun.COM 
1438348SEric.Yu@Sun.COM 	/*
1448348SEric.Yu@Sun.COM 	 * a bind to a NULL address is interpreted as unbind. So just
1458348SEric.Yu@Sun.COM 	 * do the downcall.
1468348SEric.Yu@Sun.COM 	 */
1478348SEric.Yu@Sun.COM 	if (name == NULL)
1488348SEric.Yu@Sun.COM 		goto dobind;
1498348SEric.Yu@Sun.COM 
1508348SEric.Yu@Sun.COM 	switch (so->so_family) {
1518348SEric.Yu@Sun.COM 	case AF_INET:
1528348SEric.Yu@Sun.COM 		if ((size_t)namelen != sizeof (sin_t)) {
1538348SEric.Yu@Sun.COM 			error = name->sa_family != so->so_family ?
1548348SEric.Yu@Sun.COM 			    EAFNOSUPPORT : EINVAL;
1558348SEric.Yu@Sun.COM 			eprintsoline(so, error);
1568348SEric.Yu@Sun.COM 			goto done;
1578348SEric.Yu@Sun.COM 		}
1588348SEric.Yu@Sun.COM 
1598348SEric.Yu@Sun.COM 		if ((flags & _SOBIND_XPG4_2) &&
1608348SEric.Yu@Sun.COM 		    (name->sa_family != so->so_family)) {
1618348SEric.Yu@Sun.COM 			/*
1628348SEric.Yu@Sun.COM 			 * This check has to be made for X/Open
1638348SEric.Yu@Sun.COM 			 * sockets however application failures have
1648348SEric.Yu@Sun.COM 			 * been observed when it is applied to
1658348SEric.Yu@Sun.COM 			 * all sockets.
1668348SEric.Yu@Sun.COM 			 */
1678348SEric.Yu@Sun.COM 			error = EAFNOSUPPORT;
1688348SEric.Yu@Sun.COM 			eprintsoline(so, error);
1698348SEric.Yu@Sun.COM 			goto done;
1708348SEric.Yu@Sun.COM 		}
1718348SEric.Yu@Sun.COM 		/*
1728348SEric.Yu@Sun.COM 		 * Force a zero sa_family to match so_family.
1738348SEric.Yu@Sun.COM 		 *
1748348SEric.Yu@Sun.COM 		 * Some programs like inetd(1M) don't set the
1758348SEric.Yu@Sun.COM 		 * family field. Other programs leave
1768348SEric.Yu@Sun.COM 		 * sin_family set to garbage - SunOS 4.X does
1778348SEric.Yu@Sun.COM 		 * not check the family field on a bind.
1788348SEric.Yu@Sun.COM 		 * We use the family field that
1798348SEric.Yu@Sun.COM 		 * was passed in to the socket() call.
1808348SEric.Yu@Sun.COM 		 */
1818348SEric.Yu@Sun.COM 		name->sa_family = so->so_family;
1828348SEric.Yu@Sun.COM 		break;
1838348SEric.Yu@Sun.COM 
1848348SEric.Yu@Sun.COM 	case AF_INET6: {
1858348SEric.Yu@Sun.COM #ifdef DEBUG
1868348SEric.Yu@Sun.COM 		sin6_t *sin6 = (sin6_t *)name;
1878348SEric.Yu@Sun.COM #endif
1888348SEric.Yu@Sun.COM 		if ((size_t)namelen != sizeof (sin6_t)) {
1898348SEric.Yu@Sun.COM 			error = name->sa_family != so->so_family ?
1908348SEric.Yu@Sun.COM 			    EAFNOSUPPORT : EINVAL;
1918348SEric.Yu@Sun.COM 			eprintsoline(so, error);
1928348SEric.Yu@Sun.COM 			goto done;
1938348SEric.Yu@Sun.COM 		}
1948348SEric.Yu@Sun.COM 
1958348SEric.Yu@Sun.COM 		if (name->sa_family != so->so_family) {
1968348SEric.Yu@Sun.COM 			/*
1978348SEric.Yu@Sun.COM 			 * With IPv6 we require the family to match
1988348SEric.Yu@Sun.COM 			 * unlike in IPv4.
1998348SEric.Yu@Sun.COM 			 */
2008348SEric.Yu@Sun.COM 			error = EAFNOSUPPORT;
2018348SEric.Yu@Sun.COM 			eprintsoline(so, error);
2028348SEric.Yu@Sun.COM 			goto done;
2038348SEric.Yu@Sun.COM 		}
2048348SEric.Yu@Sun.COM #ifdef DEBUG
2058348SEric.Yu@Sun.COM 		/*
2068348SEric.Yu@Sun.COM 		 * Verify that apps don't forget to clear
2078348SEric.Yu@Sun.COM 		 * sin6_scope_id etc
2088348SEric.Yu@Sun.COM 		 */
2098348SEric.Yu@Sun.COM 		if (sin6->sin6_scope_id != 0 &&
2108348SEric.Yu@Sun.COM 		    !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
2118348SEric.Yu@Sun.COM 			zcmn_err(getzoneid(), CE_WARN,
2128348SEric.Yu@Sun.COM 			    "bind with uninitialized sin6_scope_id "
2138348SEric.Yu@Sun.COM 			    "(%d) on socket. Pid = %d\n",
2148348SEric.Yu@Sun.COM 			    (int)sin6->sin6_scope_id,
2158348SEric.Yu@Sun.COM 			    (int)curproc->p_pid);
2168348SEric.Yu@Sun.COM 		}
2178348SEric.Yu@Sun.COM 		if (sin6->__sin6_src_id != 0) {
2188348SEric.Yu@Sun.COM 			zcmn_err(getzoneid(), CE_WARN,
2198348SEric.Yu@Sun.COM 			    "bind with uninitialized __sin6_src_id "
2208348SEric.Yu@Sun.COM 			    "(%d) on socket. Pid = %d\n",
2218348SEric.Yu@Sun.COM 			    (int)sin6->__sin6_src_id,
2228348SEric.Yu@Sun.COM 			    (int)curproc->p_pid);
2238348SEric.Yu@Sun.COM 		}
2248348SEric.Yu@Sun.COM #endif /* DEBUG */
2258348SEric.Yu@Sun.COM 
2268348SEric.Yu@Sun.COM 		break;
2278348SEric.Yu@Sun.COM 	}
2288348SEric.Yu@Sun.COM 	default:
2298348SEric.Yu@Sun.COM 		/* Just pass the request to the protocol */
2308348SEric.Yu@Sun.COM 		goto dobind;
2318348SEric.Yu@Sun.COM 	}
2328348SEric.Yu@Sun.COM 
2338348SEric.Yu@Sun.COM 	/*
2348348SEric.Yu@Sun.COM 	 * First we check if either NCA or KSSL has been enabled for
2358348SEric.Yu@Sun.COM 	 * the requested address, and if so, we fall back to TPI.
2368348SEric.Yu@Sun.COM 	 * If neither of those two services are enabled, then we just
2378348SEric.Yu@Sun.COM 	 * pass the request to the protocol.
2388348SEric.Yu@Sun.COM 	 *
2398348SEric.Yu@Sun.COM 	 * Note that KSSL can only be enabled on a socket if NCA is NOT
2408348SEric.Yu@Sun.COM 	 * enabled for that socket, hence the else-statement below.
2418348SEric.Yu@Sun.COM 	 */
2428348SEric.Yu@Sun.COM 	if (nl7c_enabled && ((so->so_family == AF_INET ||
2438348SEric.Yu@Sun.COM 	    so->so_family == AF_INET6) &&
2448348SEric.Yu@Sun.COM 	    nl7c_lookup_addr(name, namelen) != NULL)) {
2458348SEric.Yu@Sun.COM 		/*
2468348SEric.Yu@Sun.COM 		 * NL7C is not supported in non-global zones,
2478348SEric.Yu@Sun.COM 		 * we enforce this restriction here.
2488348SEric.Yu@Sun.COM 		 */
2498348SEric.Yu@Sun.COM 		if (so->so_zoneid == GLOBAL_ZONEID) {
2508348SEric.Yu@Sun.COM 			/* NCA should be used, so fall back to TPI */
2518348SEric.Yu@Sun.COM 			error = so_tpi_fallback(so, cr);
2528348SEric.Yu@Sun.COM 			SO_UNBLOCK_FALLBACK(so);
2538348SEric.Yu@Sun.COM 			if (error)
2548348SEric.Yu@Sun.COM 				return (error);
2558348SEric.Yu@Sun.COM 			else
2568348SEric.Yu@Sun.COM 				return (SOP_BIND(so, name, namelen, flags, cr));
2578348SEric.Yu@Sun.COM 		}
2588348SEric.Yu@Sun.COM 	} else if (so->so_type == SOCK_STREAM) {
2598348SEric.Yu@Sun.COM 		/* Check if KSSL has been configured for this address */
2608348SEric.Yu@Sun.COM 		kssl_ent_t ent;
2618348SEric.Yu@Sun.COM 		kssl_endpt_type_t type;
2628348SEric.Yu@Sun.COM 		struct T_bind_req bind_req;
2638348SEric.Yu@Sun.COM 		mblk_t *mp;
2648348SEric.Yu@Sun.COM 
2658348SEric.Yu@Sun.COM 		/*
2668348SEric.Yu@Sun.COM 		 * TODO: Check with KSSL team if we could add a function call
2678348SEric.Yu@Sun.COM 		 * that only queries whether KSSL is enabled for the given
2688348SEric.Yu@Sun.COM 		 * address.
2698348SEric.Yu@Sun.COM 		 */
2708348SEric.Yu@Sun.COM 		bind_req.PRIM_type = T_BIND_REQ;
2718348SEric.Yu@Sun.COM 		bind_req.ADDR_length = namelen;
2728348SEric.Yu@Sun.COM 		bind_req.ADDR_offset = (t_scalar_t)sizeof (bind_req);
2738348SEric.Yu@Sun.COM 		mp = soallocproto2(&bind_req, sizeof (bind_req),
2748778SErik.Nordmark@Sun.COM 		    name, namelen, 0, _ALLOC_SLEEP, cr);
2758348SEric.Yu@Sun.COM 
2768348SEric.Yu@Sun.COM 		type = kssl_check_proxy(mp, so, &ent);
2778348SEric.Yu@Sun.COM 		freemsg(mp);
2788348SEric.Yu@Sun.COM 
2798348SEric.Yu@Sun.COM 		if (type != KSSL_NO_PROXY) {
2808348SEric.Yu@Sun.COM 			/*
2818348SEric.Yu@Sun.COM 			 * KSSL has been configured for this address, so
2828348SEric.Yu@Sun.COM 			 * we must fall back to TPI.
2838348SEric.Yu@Sun.COM 			 */
2848348SEric.Yu@Sun.COM 			kssl_release_ent(ent, so, type);
2858348SEric.Yu@Sun.COM 			error = so_tpi_fallback(so, cr);
2868348SEric.Yu@Sun.COM 			SO_UNBLOCK_FALLBACK(so);
2878348SEric.Yu@Sun.COM 			if (error)
2888348SEric.Yu@Sun.COM 				return (error);
2898348SEric.Yu@Sun.COM 			else
2908348SEric.Yu@Sun.COM 				return (SOP_BIND(so, name, namelen, flags, cr));
2918348SEric.Yu@Sun.COM 		}
2928348SEric.Yu@Sun.COM 	}
2938348SEric.Yu@Sun.COM 
2948348SEric.Yu@Sun.COM dobind:
295*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active == 0 ||
296*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_bind(so, name, &namelen, cr)) < 0) {
297*12643SAnders.Persson@Sun.COM 		error = (*so->so_downcalls->sd_bind)
298*12643SAnders.Persson@Sun.COM 		    (so->so_proto_handle, name, namelen, cr);
299*12643SAnders.Persson@Sun.COM 	}
3008348SEric.Yu@Sun.COM done:
3018348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
3028348SEric.Yu@Sun.COM 
3038348SEric.Yu@Sun.COM 	return (error);
3048348SEric.Yu@Sun.COM }
3058348SEric.Yu@Sun.COM 
3068348SEric.Yu@Sun.COM int
3078348SEric.Yu@Sun.COM so_listen(struct sonode *so, int backlog, struct cred *cr)
3088348SEric.Yu@Sun.COM {
3098348SEric.Yu@Sun.COM 	int	error = 0;
3108348SEric.Yu@Sun.COM 
3118348SEric.Yu@Sun.COM 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3128348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_LISTEN(so, backlog, cr));
3138348SEric.Yu@Sun.COM 
314*12643SAnders.Persson@Sun.COM 	if ((so)->so_filter_active == 0 ||
315*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_listen(so, &backlog, cr)) < 0)
316*12643SAnders.Persson@Sun.COM 		error = (*so->so_downcalls->sd_listen)(so->so_proto_handle,
317*12643SAnders.Persson@Sun.COM 		    backlog, cr);
3188348SEric.Yu@Sun.COM 
3198348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
3208348SEric.Yu@Sun.COM 
3218348SEric.Yu@Sun.COM 	return (error);
3228348SEric.Yu@Sun.COM }
3238348SEric.Yu@Sun.COM 
3248348SEric.Yu@Sun.COM 
3258348SEric.Yu@Sun.COM int
326*12643SAnders.Persson@Sun.COM so_connect(struct sonode *so, struct sockaddr *name,
3278348SEric.Yu@Sun.COM     socklen_t namelen, int fflag, int flags, struct cred *cr)
3288348SEric.Yu@Sun.COM {
3298348SEric.Yu@Sun.COM 	int error = 0;
3308348SEric.Yu@Sun.COM 	sock_connid_t id;
3318348SEric.Yu@Sun.COM 
3328348SEric.Yu@Sun.COM 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3338348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_CONNECT(so, name, namelen, fflag, flags, cr));
3348348SEric.Yu@Sun.COM 
3358348SEric.Yu@Sun.COM 	/*
3368348SEric.Yu@Sun.COM 	 * If there is a pending error, return error
3378348SEric.Yu@Sun.COM 	 * This can happen if a non blocking operation caused an error.
3388348SEric.Yu@Sun.COM 	 */
3398348SEric.Yu@Sun.COM 
3408348SEric.Yu@Sun.COM 	if (so->so_error != 0) {
3418348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
3428348SEric.Yu@Sun.COM 		error = sogeterr(so, B_TRUE);
3438348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
3448348SEric.Yu@Sun.COM 		if (error != 0)
3458348SEric.Yu@Sun.COM 			goto done;
3468348SEric.Yu@Sun.COM 	}
3478348SEric.Yu@Sun.COM 
348*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active == 0 ||
349*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_connect(so, (struct sockaddr *)name,
350*12643SAnders.Persson@Sun.COM 	    &namelen, cr)) < 0) {
351*12643SAnders.Persson@Sun.COM 		error = (*so->so_downcalls->sd_connect)(so->so_proto_handle,
352*12643SAnders.Persson@Sun.COM 		    name, namelen, &id, cr);
3538348SEric.Yu@Sun.COM 
354*12643SAnders.Persson@Sun.COM 		if (error == EINPROGRESS)
355*12643SAnders.Persson@Sun.COM 			error = so_wait_connected(so,
356*12643SAnders.Persson@Sun.COM 			    fflag & (FNONBLOCK|FNDELAY), id);
357*12643SAnders.Persson@Sun.COM 	}
3588348SEric.Yu@Sun.COM done:
3598348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
3608348SEric.Yu@Sun.COM 	return (error);
3618348SEric.Yu@Sun.COM }
3628348SEric.Yu@Sun.COM 
3638348SEric.Yu@Sun.COM /*ARGSUSED*/
3648348SEric.Yu@Sun.COM int
3658348SEric.Yu@Sun.COM so_accept(struct sonode *so, int fflag, struct cred *cr, struct sonode **nsop)
3668348SEric.Yu@Sun.COM {
3678348SEric.Yu@Sun.COM 	int error = 0;
3688348SEric.Yu@Sun.COM 	struct sonode *nso;
3698348SEric.Yu@Sun.COM 
3708348SEric.Yu@Sun.COM 	*nsop = NULL;
3718348SEric.Yu@Sun.COM 
3728348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_ACCEPT(so, fflag, cr, nsop));
3738348SEric.Yu@Sun.COM 	if ((so->so_state & SS_ACCEPTCONN) == 0) {
3748348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
3758348SEric.Yu@Sun.COM 		return ((so->so_type == SOCK_DGRAM || so->so_type == SOCK_RAW) ?
3768348SEric.Yu@Sun.COM 		    EOPNOTSUPP : EINVAL);
3778348SEric.Yu@Sun.COM 	}
3788348SEric.Yu@Sun.COM 
3798348SEric.Yu@Sun.COM 	if ((error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)),
3808348SEric.Yu@Sun.COM 	    &nso)) == 0) {
3818348SEric.Yu@Sun.COM 		ASSERT(nso != NULL);
3828348SEric.Yu@Sun.COM 
3838348SEric.Yu@Sun.COM 		/* finish the accept */
384*12643SAnders.Persson@Sun.COM 		if ((so->so_filter_active > 0 &&
385*12643SAnders.Persson@Sun.COM 		    (error = sof_filter_accept(nso, cr)) > 0) ||
386*12643SAnders.Persson@Sun.COM 		    (error = (*so->so_downcalls->sd_accept)(so->so_proto_handle,
387*12643SAnders.Persson@Sun.COM 		    nso->so_proto_handle, (sock_upper_handle_t)nso, cr)) != 0) {
3888348SEric.Yu@Sun.COM 			(void) socket_close(nso, 0, cr);
3898348SEric.Yu@Sun.COM 			socket_destroy(nso);
3908348SEric.Yu@Sun.COM 		} else {
3918348SEric.Yu@Sun.COM 			*nsop = nso;
3928348SEric.Yu@Sun.COM 		}
3938348SEric.Yu@Sun.COM 	}
3948348SEric.Yu@Sun.COM 
3958348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
3968348SEric.Yu@Sun.COM 	return (error);
3978348SEric.Yu@Sun.COM }
3988348SEric.Yu@Sun.COM 
3998348SEric.Yu@Sun.COM int
4008348SEric.Yu@Sun.COM so_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4018348SEric.Yu@Sun.COM     struct cred *cr)
4028348SEric.Yu@Sun.COM {
4038348SEric.Yu@Sun.COM 	int error, flags;
4048348SEric.Yu@Sun.COM 	boolean_t dontblock;
4058348SEric.Yu@Sun.COM 	ssize_t orig_resid;
4068348SEric.Yu@Sun.COM 	mblk_t  *mp;
4078348SEric.Yu@Sun.COM 
4088348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_SENDMSG(so, msg, uiop, cr));
4098348SEric.Yu@Sun.COM 
4108348SEric.Yu@Sun.COM 	flags = msg->msg_flags;
4118348SEric.Yu@Sun.COM 	error = 0;
4128348SEric.Yu@Sun.COM 	dontblock = (flags & MSG_DONTWAIT) ||
4138348SEric.Yu@Sun.COM 	    (uiop->uio_fmode & (FNONBLOCK|FNDELAY));
4148348SEric.Yu@Sun.COM 
4158348SEric.Yu@Sun.COM 	if (!(flags & MSG_XPG4_2) && msg->msg_controllen != 0) {
4168348SEric.Yu@Sun.COM 		/*
4178348SEric.Yu@Sun.COM 		 * Old way of passing fd's is not supported
4188348SEric.Yu@Sun.COM 		 */
4198348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
4208348SEric.Yu@Sun.COM 		return (EOPNOTSUPP);
4218348SEric.Yu@Sun.COM 	}
4228348SEric.Yu@Sun.COM 
4238348SEric.Yu@Sun.COM 	if ((so->so_mode & SM_ATOMIC) &&
4248348SEric.Yu@Sun.COM 	    uiop->uio_resid > so->so_proto_props.sopp_maxpsz &&
4258348SEric.Yu@Sun.COM 	    so->so_proto_props.sopp_maxpsz != -1) {
4268348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
4278348SEric.Yu@Sun.COM 		return (EMSGSIZE);
4288348SEric.Yu@Sun.COM 	}
4298348SEric.Yu@Sun.COM 
4308348SEric.Yu@Sun.COM 	/*
4318348SEric.Yu@Sun.COM 	 * For atomic sends we will only do one iteration.
4328348SEric.Yu@Sun.COM 	 */
4338348SEric.Yu@Sun.COM 	do {
4348348SEric.Yu@Sun.COM 		if (so->so_state & SS_CANTSENDMORE) {
4358348SEric.Yu@Sun.COM 			error = EPIPE;
4368348SEric.Yu@Sun.COM 			break;
4378348SEric.Yu@Sun.COM 		}
4388348SEric.Yu@Sun.COM 
4398348SEric.Yu@Sun.COM 		if (so->so_error != 0) {
4408348SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
4418348SEric.Yu@Sun.COM 			error = sogeterr(so, B_TRUE);
4428348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
4438348SEric.Yu@Sun.COM 			if (error != 0)
4448348SEric.Yu@Sun.COM 				break;
4458348SEric.Yu@Sun.COM 		}
4468348SEric.Yu@Sun.COM 
4478348SEric.Yu@Sun.COM 		/*
4488348SEric.Yu@Sun.COM 		 * Send down OOB messages even if the send path is being
4498348SEric.Yu@Sun.COM 		 * flow controlled (assuming the protocol supports OOB data).
4508348SEric.Yu@Sun.COM 		 */
4518348SEric.Yu@Sun.COM 		if (flags & MSG_OOB) {
4528348SEric.Yu@Sun.COM 			if ((so->so_mode & SM_EXDATA) == 0) {
4538348SEric.Yu@Sun.COM 				error = EOPNOTSUPP;
4548348SEric.Yu@Sun.COM 				break;
4558348SEric.Yu@Sun.COM 			}
456*12643SAnders.Persson@Sun.COM 		} else if (SO_SND_FLOWCTRLD(so)) {
4578348SEric.Yu@Sun.COM 			/*
4588348SEric.Yu@Sun.COM 			 * Need to wait until the protocol is ready to receive
4598348SEric.Yu@Sun.COM 			 * more data for transmission.
4608348SEric.Yu@Sun.COM 			 */
4618348SEric.Yu@Sun.COM 			if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0)
4628348SEric.Yu@Sun.COM 				break;
4638348SEric.Yu@Sun.COM 		}
4648348SEric.Yu@Sun.COM 
4658348SEric.Yu@Sun.COM 		/*
4668348SEric.Yu@Sun.COM 		 * Time to send data to the protocol. We either copy the
4678348SEric.Yu@Sun.COM 		 * data into mblks or pass the uio directly to the protocol.
4688348SEric.Yu@Sun.COM 		 * We decide what to do based on the available down calls.
4698348SEric.Yu@Sun.COM 		 */
4708348SEric.Yu@Sun.COM 		if (so->so_downcalls->sd_send_uio != NULL) {
4718348SEric.Yu@Sun.COM 			error = (*so->so_downcalls->sd_send_uio)
4728348SEric.Yu@Sun.COM 			    (so->so_proto_handle, uiop, msg, cr);
4738348SEric.Yu@Sun.COM 			if (error != 0)
4748348SEric.Yu@Sun.COM 				break;
4758348SEric.Yu@Sun.COM 		} else {
4768348SEric.Yu@Sun.COM 			/* save the resid in case of failure */
4778348SEric.Yu@Sun.COM 			orig_resid = uiop->uio_resid;
4788348SEric.Yu@Sun.COM 
4798348SEric.Yu@Sun.COM 			if ((mp = socopyinuio(uiop,
4808348SEric.Yu@Sun.COM 			    so->so_proto_props.sopp_maxpsz,
4818348SEric.Yu@Sun.COM 			    so->so_proto_props.sopp_wroff,
4828348SEric.Yu@Sun.COM 			    so->so_proto_props.sopp_maxblk,
48311042SErik.Nordmark@Sun.COM 			    so->so_proto_props.sopp_tail, &error)) == NULL) {
4848348SEric.Yu@Sun.COM 				break;
4858348SEric.Yu@Sun.COM 			}
4868348SEric.Yu@Sun.COM 			ASSERT(uiop->uio_resid >= 0);
4878348SEric.Yu@Sun.COM 
488*12643SAnders.Persson@Sun.COM 			if (so->so_filter_active > 0 &&
489*12643SAnders.Persson@Sun.COM 			    ((mp = SOF_FILTER_DATA_OUT(so, mp, msg, cr,
490*12643SAnders.Persson@Sun.COM 			    &error)) == NULL)) {
491*12643SAnders.Persson@Sun.COM 				if (error != 0)
492*12643SAnders.Persson@Sun.COM 					break;
493*12643SAnders.Persson@Sun.COM 				continue;
494*12643SAnders.Persson@Sun.COM 			}
4958348SEric.Yu@Sun.COM 			error = (*so->so_downcalls->sd_send)
4968348SEric.Yu@Sun.COM 			    (so->so_proto_handle, mp, msg, cr);
4978348SEric.Yu@Sun.COM 			if (error != 0) {
4988348SEric.Yu@Sun.COM 				/*
4998348SEric.Yu@Sun.COM 				 * The send failed. We do not have to free the
5008348SEric.Yu@Sun.COM 				 * mblks, because that is the protocol's
5018348SEric.Yu@Sun.COM 				 * responsibility. However, uio_resid must
5028348SEric.Yu@Sun.COM 				 * remain accurate, so adjust that here.
5038348SEric.Yu@Sun.COM 				 */
5048348SEric.Yu@Sun.COM 				uiop->uio_resid = orig_resid;
5058348SEric.Yu@Sun.COM 					break;
5068348SEric.Yu@Sun.COM 			}
5078348SEric.Yu@Sun.COM 		}
5088348SEric.Yu@Sun.COM 	} while (uiop->uio_resid > 0);
5098348SEric.Yu@Sun.COM 
5108348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
5118348SEric.Yu@Sun.COM 
5128348SEric.Yu@Sun.COM 	return (error);
5138348SEric.Yu@Sun.COM }
5148348SEric.Yu@Sun.COM 
5158348SEric.Yu@Sun.COM int
516*12643SAnders.Persson@Sun.COM so_sendmblk_impl(struct sonode *so, struct nmsghdr *msg, int fflag,
517*12643SAnders.Persson@Sun.COM     struct cred *cr, mblk_t **mpp, sof_instance_t *fil,
518*12643SAnders.Persson@Sun.COM     boolean_t fil_inject)
5198348SEric.Yu@Sun.COM {
5208348SEric.Yu@Sun.COM 	int error;
5218348SEric.Yu@Sun.COM 	boolean_t dontblock;
5228348SEric.Yu@Sun.COM 	size_t size;
5238348SEric.Yu@Sun.COM 	mblk_t *mp = *mpp;
5248348SEric.Yu@Sun.COM 
525*12643SAnders.Persson@Sun.COM 	if (so->so_downcalls->sd_send == NULL)
526*12643SAnders.Persson@Sun.COM 		return (EOPNOTSUPP);
5278348SEric.Yu@Sun.COM 
5288348SEric.Yu@Sun.COM 	error = 0;
5298348SEric.Yu@Sun.COM 	dontblock = (msg->msg_flags & MSG_DONTWAIT) ||
5308348SEric.Yu@Sun.COM 	    (fflag & (FNONBLOCK|FNDELAY));
5318348SEric.Yu@Sun.COM 	size = msgdsize(mp);
5328348SEric.Yu@Sun.COM 
5338348SEric.Yu@Sun.COM 	if ((so->so_mode & SM_ATOMIC) &&
5348348SEric.Yu@Sun.COM 	    size > so->so_proto_props.sopp_maxpsz &&
5358348SEric.Yu@Sun.COM 	    so->so_proto_props.sopp_maxpsz != -1) {
5368348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
5378348SEric.Yu@Sun.COM 		return (EMSGSIZE);
5388348SEric.Yu@Sun.COM 	}
5398348SEric.Yu@Sun.COM 
5408348SEric.Yu@Sun.COM 	while (mp != NULL) {
5418348SEric.Yu@Sun.COM 		mblk_t *nmp, *last_mblk;
5428348SEric.Yu@Sun.COM 		size_t mlen;
5438348SEric.Yu@Sun.COM 
5448348SEric.Yu@Sun.COM 		if (so->so_state & SS_CANTSENDMORE) {
5458348SEric.Yu@Sun.COM 			error = EPIPE;
5468348SEric.Yu@Sun.COM 			break;
5478348SEric.Yu@Sun.COM 		}
5488348SEric.Yu@Sun.COM 		if (so->so_error != 0) {
5498348SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
5508348SEric.Yu@Sun.COM 			error = sogeterr(so, B_TRUE);
5518348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
5528348SEric.Yu@Sun.COM 			if (error != 0)
5538348SEric.Yu@Sun.COM 				break;
5548348SEric.Yu@Sun.COM 		}
555*12643SAnders.Persson@Sun.COM 		/* Socket filters are not flow controlled */
556*12643SAnders.Persson@Sun.COM 		if (SO_SND_FLOWCTRLD(so) && !fil_inject) {
5578348SEric.Yu@Sun.COM 			/*
5588348SEric.Yu@Sun.COM 			 * Need to wait until the protocol is ready to receive
5598348SEric.Yu@Sun.COM 			 * more data for transmission.
5608348SEric.Yu@Sun.COM 			 */
5618348SEric.Yu@Sun.COM 			if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0)
5628348SEric.Yu@Sun.COM 				break;
5638348SEric.Yu@Sun.COM 		}
5648348SEric.Yu@Sun.COM 
5658348SEric.Yu@Sun.COM 		/*
5668348SEric.Yu@Sun.COM 		 * We only allow so_maxpsz of data to be sent down to
5678348SEric.Yu@Sun.COM 		 * the protocol at time.
5688348SEric.Yu@Sun.COM 		 */
5698348SEric.Yu@Sun.COM 		mlen = MBLKL(mp);
5708348SEric.Yu@Sun.COM 		nmp = mp->b_cont;
5718348SEric.Yu@Sun.COM 		last_mblk = mp;
5728348SEric.Yu@Sun.COM 		while (nmp != NULL) {
5738348SEric.Yu@Sun.COM 			mlen += MBLKL(nmp);
5748348SEric.Yu@Sun.COM 			if (mlen > so->so_proto_props.sopp_maxpsz) {
5758348SEric.Yu@Sun.COM 				last_mblk->b_cont = NULL;
5768348SEric.Yu@Sun.COM 				break;
5778348SEric.Yu@Sun.COM 			}
5788348SEric.Yu@Sun.COM 			last_mblk = nmp;
5798348SEric.Yu@Sun.COM 			nmp = nmp->b_cont;
5808348SEric.Yu@Sun.COM 		}
5818348SEric.Yu@Sun.COM 
582*12643SAnders.Persson@Sun.COM 		if (so->so_filter_active > 0 &&
583*12643SAnders.Persson@Sun.COM 		    (mp = SOF_FILTER_DATA_OUT_FROM(so, fil, mp, msg,
584*12643SAnders.Persson@Sun.COM 		    cr, &error)) == NULL) {
585*12643SAnders.Persson@Sun.COM 			*mpp = mp = nmp;
586*12643SAnders.Persson@Sun.COM 			if (error != 0)
587*12643SAnders.Persson@Sun.COM 				break;
588*12643SAnders.Persson@Sun.COM 			continue;
589*12643SAnders.Persson@Sun.COM 		}
5908348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_send)
5918348SEric.Yu@Sun.COM 		    (so->so_proto_handle, mp, msg, cr);
5928348SEric.Yu@Sun.COM 		if (error != 0) {
5938348SEric.Yu@Sun.COM 			/*
5948348SEric.Yu@Sun.COM 			 * The send failed. The protocol will free the mblks
5958348SEric.Yu@Sun.COM 			 * that were sent down. Let the caller deal with the
5968348SEric.Yu@Sun.COM 			 * rest.
5978348SEric.Yu@Sun.COM 			 */
5988348SEric.Yu@Sun.COM 			*mpp = nmp;
5998348SEric.Yu@Sun.COM 			break;
6008348SEric.Yu@Sun.COM 		}
6018348SEric.Yu@Sun.COM 
6028348SEric.Yu@Sun.COM 		*mpp = mp = nmp;
6038348SEric.Yu@Sun.COM 	}
604*12643SAnders.Persson@Sun.COM 	/* Let the filter know whether the protocol is flow controlled */
605*12643SAnders.Persson@Sun.COM 	if (fil_inject && error == 0 && SO_SND_FLOWCTRLD(so))
606*12643SAnders.Persson@Sun.COM 		error = ENOSPC;
607*12643SAnders.Persson@Sun.COM 
608*12643SAnders.Persson@Sun.COM 	return (error);
609*12643SAnders.Persson@Sun.COM }
610*12643SAnders.Persson@Sun.COM 
611*12643SAnders.Persson@Sun.COM #pragma inline(so_sendmblk_impl)
612*12643SAnders.Persson@Sun.COM 
613*12643SAnders.Persson@Sun.COM int
614*12643SAnders.Persson@Sun.COM so_sendmblk(struct sonode *so, struct nmsghdr *msg, int fflag,
615*12643SAnders.Persson@Sun.COM     struct cred *cr, mblk_t **mpp)
616*12643SAnders.Persson@Sun.COM {
617*12643SAnders.Persson@Sun.COM 	int error;
618*12643SAnders.Persson@Sun.COM 
619*12643SAnders.Persson@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_SENDMBLK(so, msg, fflag, cr, mpp));
620*12643SAnders.Persson@Sun.COM 
621*12643SAnders.Persson@Sun.COM 	if ((so->so_mode & SM_SENDFILESUPP) == 0) {
622*12643SAnders.Persson@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
623*12643SAnders.Persson@Sun.COM 		return (EOPNOTSUPP);
624*12643SAnders.Persson@Sun.COM 	}
625*12643SAnders.Persson@Sun.COM 
626*12643SAnders.Persson@Sun.COM 	error = so_sendmblk_impl(so, msg, fflag, cr, mpp, so->so_filter_top,
627*12643SAnders.Persson@Sun.COM 	    B_FALSE);
6288348SEric.Yu@Sun.COM 
6298348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
6308348SEric.Yu@Sun.COM 
6318348SEric.Yu@Sun.COM 	return (error);
6328348SEric.Yu@Sun.COM }
6338348SEric.Yu@Sun.COM 
6348348SEric.Yu@Sun.COM int
6358348SEric.Yu@Sun.COM so_shutdown(struct sonode *so, int how, struct cred *cr)
6368348SEric.Yu@Sun.COM {
6378348SEric.Yu@Sun.COM 	int error;
6388348SEric.Yu@Sun.COM 
6398348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_SHUTDOWN(so, how, cr));
6408348SEric.Yu@Sun.COM 
6418348SEric.Yu@Sun.COM 	/*
6428348SEric.Yu@Sun.COM 	 * SunOS 4.X has no check for datagram sockets.
6438348SEric.Yu@Sun.COM 	 * 5.X checks that it is connected (ENOTCONN)
6448348SEric.Yu@Sun.COM 	 * X/Open requires that we check the connected state.
6458348SEric.Yu@Sun.COM 	 */
6468348SEric.Yu@Sun.COM 	if (!(so->so_state & SS_ISCONNECTED)) {
6478348SEric.Yu@Sun.COM 		if (!xnet_skip_checks) {
6488348SEric.Yu@Sun.COM 			error = ENOTCONN;
6498348SEric.Yu@Sun.COM 			if (xnet_check_print) {
6508348SEric.Yu@Sun.COM 				printf("sockfs: X/Open shutdown check "
6518348SEric.Yu@Sun.COM 				    "caused ENOTCONN\n");
6528348SEric.Yu@Sun.COM 			}
6538348SEric.Yu@Sun.COM 		}
6548348SEric.Yu@Sun.COM 		goto done;
6558348SEric.Yu@Sun.COM 	}
6568348SEric.Yu@Sun.COM 
657*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active == 0 ||
658*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_shutdown(so, &how, cr)) < 0)
659*12643SAnders.Persson@Sun.COM 		error = ((*so->so_downcalls->sd_shutdown)(so->so_proto_handle,
660*12643SAnders.Persson@Sun.COM 		    how, cr));
6618348SEric.Yu@Sun.COM 
6628348SEric.Yu@Sun.COM 	/*
6638348SEric.Yu@Sun.COM 	 * Protocol agreed to shutdown. We need to flush the
6648348SEric.Yu@Sun.COM 	 * receive buffer if the receive side is being shutdown.
6658348SEric.Yu@Sun.COM 	 */
6668348SEric.Yu@Sun.COM 	if (error == 0 && how != SHUT_WR) {
6678348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
6688348SEric.Yu@Sun.COM 		/* wait for active reader to finish */
6698348SEric.Yu@Sun.COM 		(void) so_lock_read(so, 0);
6708348SEric.Yu@Sun.COM 
6718348SEric.Yu@Sun.COM 		so_rcv_flush(so);
6728348SEric.Yu@Sun.COM 
6738348SEric.Yu@Sun.COM 		so_unlock_read(so);
6748348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
6758348SEric.Yu@Sun.COM 	}
6768348SEric.Yu@Sun.COM 
6778348SEric.Yu@Sun.COM done:
6788348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
6798348SEric.Yu@Sun.COM 	return (error);
6808348SEric.Yu@Sun.COM }
6818348SEric.Yu@Sun.COM 
6828348SEric.Yu@Sun.COM int
6838348SEric.Yu@Sun.COM so_getsockname(struct sonode *so, struct sockaddr *addr,
6848348SEric.Yu@Sun.COM     socklen_t *addrlen, struct cred *cr)
6858348SEric.Yu@Sun.COM {
6868348SEric.Yu@Sun.COM 	int error;
6878348SEric.Yu@Sun.COM 
6888348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_GETSOCKNAME(so, addr, addrlen, cr));
6898348SEric.Yu@Sun.COM 
690*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active == 0 ||
691*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_getsockname(so, addr, addrlen, cr)) < 0)
692*12643SAnders.Persson@Sun.COM 		error = (*so->so_downcalls->sd_getsockname)
693*12643SAnders.Persson@Sun.COM 		    (so->so_proto_handle, addr, addrlen, cr);
6948348SEric.Yu@Sun.COM 
6958348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
6968348SEric.Yu@Sun.COM 	return (error);
6978348SEric.Yu@Sun.COM }
6988348SEric.Yu@Sun.COM 
6998348SEric.Yu@Sun.COM int
7008348SEric.Yu@Sun.COM so_getpeername(struct sonode *so, struct sockaddr *addr,
7018348SEric.Yu@Sun.COM     socklen_t *addrlen, boolean_t accept, struct cred *cr)
7028348SEric.Yu@Sun.COM {
7038348SEric.Yu@Sun.COM 	int error;
7048348SEric.Yu@Sun.COM 
7058348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_GETPEERNAME(so, addr, addrlen, accept, cr));
7068348SEric.Yu@Sun.COM 
7078348SEric.Yu@Sun.COM 	if (accept) {
7088348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_getpeername)
7098348SEric.Yu@Sun.COM 		    (so->so_proto_handle, addr, addrlen, cr);
7108348SEric.Yu@Sun.COM 	} else if (!(so->so_state & SS_ISCONNECTED)) {
7118348SEric.Yu@Sun.COM 		error = ENOTCONN;
7128348SEric.Yu@Sun.COM 	} else if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) {
7138348SEric.Yu@Sun.COM 		/* Added this check for X/Open */
7148348SEric.Yu@Sun.COM 		error = EINVAL;
7158348SEric.Yu@Sun.COM 		if (xnet_check_print) {
7168348SEric.Yu@Sun.COM 			printf("sockfs: X/Open getpeername check => EINVAL\n");
7178348SEric.Yu@Sun.COM 		}
718*12643SAnders.Persson@Sun.COM 	} else if (so->so_filter_active == 0 ||
719*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_getpeername(so, addr, addrlen, cr)) < 0) {
7208348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_getpeername)
7218348SEric.Yu@Sun.COM 		    (so->so_proto_handle, addr, addrlen, cr);
7228348SEric.Yu@Sun.COM 	}
7238348SEric.Yu@Sun.COM 
7248348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
7258348SEric.Yu@Sun.COM 	return (error);
7268348SEric.Yu@Sun.COM }
7278348SEric.Yu@Sun.COM 
7288348SEric.Yu@Sun.COM int
7298348SEric.Yu@Sun.COM so_getsockopt(struct sonode *so, int level, int option_name,
7308348SEric.Yu@Sun.COM     void *optval, socklen_t *optlenp, int flags, struct cred *cr)
7318348SEric.Yu@Sun.COM {
7328348SEric.Yu@Sun.COM 	int error = 0;
7338348SEric.Yu@Sun.COM 
734*12643SAnders.Persson@Sun.COM 	if (level == SOL_FILTER)
735*12643SAnders.Persson@Sun.COM 		return (sof_getsockopt(so, option_name, optval, optlenp, cr));
736*12643SAnders.Persson@Sun.COM 
7378348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so,
7388348SEric.Yu@Sun.COM 	    SOP_GETSOCKOPT(so, level, option_name, optval, optlenp, flags, cr));
7398348SEric.Yu@Sun.COM 
740*12643SAnders.Persson@Sun.COM 	if ((so->so_filter_active == 0 ||
741*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_getsockopt(so, level, option_name, optval,
742*12643SAnders.Persson@Sun.COM 	    optlenp, cr)) < 0) &&
743*12643SAnders.Persson@Sun.COM 	    (error = socket_getopt_common(so, level, option_name, optval,
744*12643SAnders.Persson@Sun.COM 	    optlenp, flags)) < 0) {
7458348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_getsockopt)
7468348SEric.Yu@Sun.COM 		    (so->so_proto_handle, level, option_name, optval, optlenp,
7478348SEric.Yu@Sun.COM 		    cr);
7488348SEric.Yu@Sun.COM 		if (error ==  ENOPROTOOPT) {
7498348SEric.Yu@Sun.COM 			if (level == SOL_SOCKET) {
7508348SEric.Yu@Sun.COM 				/*
7518348SEric.Yu@Sun.COM 				 * If a protocol does not support a particular
7528348SEric.Yu@Sun.COM 				 * socket option, set can fail (not allowed)
7538348SEric.Yu@Sun.COM 				 * but get can not fail. This is the previous
7548348SEric.Yu@Sun.COM 				 * sockfs bahvior.
7558348SEric.Yu@Sun.COM 				 */
7568348SEric.Yu@Sun.COM 				switch (option_name) {
7578348SEric.Yu@Sun.COM 				case SO_LINGER:
7588348SEric.Yu@Sun.COM 					if (*optlenp < (t_uscalar_t)
7598348SEric.Yu@Sun.COM 					    sizeof (struct linger)) {
7608348SEric.Yu@Sun.COM 						error = EINVAL;
7618348SEric.Yu@Sun.COM 						break;
7628348SEric.Yu@Sun.COM 					}
7638348SEric.Yu@Sun.COM 					error = 0;
7648348SEric.Yu@Sun.COM 					bzero(optval, sizeof (struct linger));
7658348SEric.Yu@Sun.COM 					*optlenp = sizeof (struct linger);
7668348SEric.Yu@Sun.COM 					break;
7678348SEric.Yu@Sun.COM 				case SO_RCVTIMEO:
7688348SEric.Yu@Sun.COM 				case SO_SNDTIMEO:
7698348SEric.Yu@Sun.COM 					if (*optlenp < (t_uscalar_t)
7708348SEric.Yu@Sun.COM 					    sizeof (struct timeval)) {
7718348SEric.Yu@Sun.COM 						error = EINVAL;
7728348SEric.Yu@Sun.COM 						break;
7738348SEric.Yu@Sun.COM 					}
7748348SEric.Yu@Sun.COM 					error = 0;
7758348SEric.Yu@Sun.COM 					bzero(optval, sizeof (struct timeval));
7768348SEric.Yu@Sun.COM 					*optlenp = sizeof (struct timeval);
7778348SEric.Yu@Sun.COM 					break;
7788348SEric.Yu@Sun.COM 				case SO_SND_BUFINFO:
7798348SEric.Yu@Sun.COM 					if (*optlenp < (t_uscalar_t)
7808348SEric.Yu@Sun.COM 					    sizeof (struct so_snd_bufinfo)) {
7818348SEric.Yu@Sun.COM 						error = EINVAL;
7828348SEric.Yu@Sun.COM 						break;
7838348SEric.Yu@Sun.COM 					}
7848348SEric.Yu@Sun.COM 					error = 0;
7858348SEric.Yu@Sun.COM 					bzero(optval,
7868348SEric.Yu@Sun.COM 					    sizeof (struct so_snd_bufinfo));
7878348SEric.Yu@Sun.COM 					*optlenp =
7888348SEric.Yu@Sun.COM 					    sizeof (struct so_snd_bufinfo);
7898348SEric.Yu@Sun.COM 					break;
7908348SEric.Yu@Sun.COM 				case SO_DEBUG:
7918348SEric.Yu@Sun.COM 				case SO_REUSEADDR:
7928348SEric.Yu@Sun.COM 				case SO_KEEPALIVE:
7938348SEric.Yu@Sun.COM 				case SO_DONTROUTE:
7948348SEric.Yu@Sun.COM 				case SO_BROADCAST:
7958348SEric.Yu@Sun.COM 				case SO_USELOOPBACK:
7968348SEric.Yu@Sun.COM 				case SO_OOBINLINE:
7978348SEric.Yu@Sun.COM 				case SO_DGRAM_ERRIND:
7988348SEric.Yu@Sun.COM 				case SO_SNDBUF:
7998348SEric.Yu@Sun.COM 				case SO_RCVBUF:
8008348SEric.Yu@Sun.COM 					error = 0;
8018348SEric.Yu@Sun.COM 					*((int32_t *)optval) = 0;
8028348SEric.Yu@Sun.COM 					*optlenp = sizeof (int32_t);
8038348SEric.Yu@Sun.COM 					break;
8048348SEric.Yu@Sun.COM 				default:
8058348SEric.Yu@Sun.COM 					break;
8068348SEric.Yu@Sun.COM 				}
8078348SEric.Yu@Sun.COM 			}
8088348SEric.Yu@Sun.COM 		}
8098348SEric.Yu@Sun.COM 	}
8108348SEric.Yu@Sun.COM 
8118348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
8128348SEric.Yu@Sun.COM 	return (error);
8138348SEric.Yu@Sun.COM }
8148348SEric.Yu@Sun.COM 
8158348SEric.Yu@Sun.COM int
8168348SEric.Yu@Sun.COM so_setsockopt(struct sonode *so, int level, int option_name,
8178348SEric.Yu@Sun.COM     const void *optval, socklen_t optlen, struct cred *cr)
8188348SEric.Yu@Sun.COM {
8198348SEric.Yu@Sun.COM 	int error = 0;
8208612SAnders.Persson@Sun.COM 	struct timeval tl;
8218612SAnders.Persson@Sun.COM 	const void *opt = optval;
8228348SEric.Yu@Sun.COM 
823*12643SAnders.Persson@Sun.COM 	if (level == SOL_FILTER)
824*12643SAnders.Persson@Sun.COM 		return (sof_setsockopt(so, option_name, optval, optlen, cr));
825*12643SAnders.Persson@Sun.COM 
8268348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so,
8278348SEric.Yu@Sun.COM 	    SOP_SETSOCKOPT(so, level, option_name, optval, optlen, cr));
8288348SEric.Yu@Sun.COM 
8298348SEric.Yu@Sun.COM 	/* X/Open requires this check */
8308348SEric.Yu@Sun.COM 	if (so->so_state & SS_CANTSENDMORE && !xnet_skip_checks) {
8318348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
8328348SEric.Yu@Sun.COM 		if (xnet_check_print)
8338348SEric.Yu@Sun.COM 			printf("sockfs: X/Open setsockopt check => EINVAL\n");
8348348SEric.Yu@Sun.COM 		return (EINVAL);
8358348SEric.Yu@Sun.COM 	}
8368348SEric.Yu@Sun.COM 
837*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active > 0 &&
838*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_setsockopt(so, level, option_name,
839*12643SAnders.Persson@Sun.COM 	    (void *)optval, &optlen, cr)) >= 0)
840*12643SAnders.Persson@Sun.COM 		goto done;
841*12643SAnders.Persson@Sun.COM 
8428465SEric.Yu@Sun.COM 	if (level == SOL_SOCKET) {
8438465SEric.Yu@Sun.COM 		switch (option_name) {
8448465SEric.Yu@Sun.COM 		case SO_RCVTIMEO:
8458465SEric.Yu@Sun.COM 		case SO_SNDTIMEO: {
8468586Sshenjian 			/*
8478586Sshenjian 			 * We pass down these two options to protocol in order
8488586Sshenjian 			 * to support some third part protocols which need to
8498586Sshenjian 			 * know them. For those protocols which don't care
8508586Sshenjian 			 * these two options, simply return 0.
8518586Sshenjian 			 */
8528465SEric.Yu@Sun.COM 			clock_t t_usec;
8538348SEric.Yu@Sun.COM 
8548575Sshenjian 			if (get_udatamodel() == DATAMODEL_NONE ||
8558575Sshenjian 			    get_udatamodel() == DATAMODEL_NATIVE) {
8568489Sshenjian 				if (optlen != sizeof (struct timeval)) {
8578489Sshenjian 					error = EINVAL;
8588489Sshenjian 					goto done;
8598489Sshenjian 				}
8608489Sshenjian 				bcopy((struct timeval *)optval, &tl,
8618489Sshenjian 				    sizeof (struct timeval));
8628489Sshenjian 			} else {
8638489Sshenjian 				if (optlen != sizeof (struct timeval32)) {
8648489Sshenjian 					error = EINVAL;
8658489Sshenjian 					goto done;
8668489Sshenjian 				}
8678489Sshenjian 				TIMEVAL32_TO_TIMEVAL(&tl,
8688489Sshenjian 				    (struct timeval32 *)optval);
8698465SEric.Yu@Sun.COM 			}
8708612SAnders.Persson@Sun.COM 			opt = &tl;
8718612SAnders.Persson@Sun.COM 			optlen = sizeof (tl);
8728489Sshenjian 			t_usec = tl.tv_sec * 1000 * 1000 + tl.tv_usec;
8738465SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
8748465SEric.Yu@Sun.COM 			if (option_name == SO_RCVTIMEO)
8758465SEric.Yu@Sun.COM 				so->so_rcvtimeo = drv_usectohz(t_usec);
8768465SEric.Yu@Sun.COM 			else
8778465SEric.Yu@Sun.COM 				so->so_sndtimeo = drv_usectohz(t_usec);
8788465SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
8798586Sshenjian 			break;
8808348SEric.Yu@Sun.COM 		}
8818465SEric.Yu@Sun.COM 		case SO_RCVBUF:
8828465SEric.Yu@Sun.COM 			/*
8838465SEric.Yu@Sun.COM 			 * XXX XPG 4.2 applications retrieve SO_RCVBUF from
8848465SEric.Yu@Sun.COM 			 * sockfs since the transport might adjust the value
8858465SEric.Yu@Sun.COM 			 * and not return exactly what was set by the
8868465SEric.Yu@Sun.COM 			 * application.
8878465SEric.Yu@Sun.COM 			 */
8888465SEric.Yu@Sun.COM 			so->so_xpg_rcvbuf = *(int32_t *)optval;
8898465SEric.Yu@Sun.COM 			break;
8908465SEric.Yu@Sun.COM 		}
8918348SEric.Yu@Sun.COM 	}
8928348SEric.Yu@Sun.COM 	error = (*so->so_downcalls->sd_setsockopt)
8938612SAnders.Persson@Sun.COM 	    (so->so_proto_handle, level, option_name, opt, optlen, cr);
8948489Sshenjian done:
8958348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
8968348SEric.Yu@Sun.COM 	return (error);
8978348SEric.Yu@Sun.COM }
8988348SEric.Yu@Sun.COM 
8998348SEric.Yu@Sun.COM int
9008348SEric.Yu@Sun.COM so_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
9018348SEric.Yu@Sun.COM     struct cred *cr, int32_t *rvalp)
9028348SEric.Yu@Sun.COM {
9038348SEric.Yu@Sun.COM 	int error = 0;
9048348SEric.Yu@Sun.COM 
9058348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_IOCTL(so, cmd, arg, mode, cr, rvalp));
9068348SEric.Yu@Sun.COM 
9078348SEric.Yu@Sun.COM 	/*
9088348SEric.Yu@Sun.COM 	 * If there is a pending error, return error
9098348SEric.Yu@Sun.COM 	 * This can happen if a non blocking operation caused an error.
9108348SEric.Yu@Sun.COM 	 */
9118348SEric.Yu@Sun.COM 	if (so->so_error != 0) {
9128348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
9138348SEric.Yu@Sun.COM 		error = sogeterr(so, B_TRUE);
9148348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
9158348SEric.Yu@Sun.COM 		if (error != 0)
9168348SEric.Yu@Sun.COM 			goto done;
9178348SEric.Yu@Sun.COM 	}
9188348SEric.Yu@Sun.COM 
9198348SEric.Yu@Sun.COM 	/*
9208348SEric.Yu@Sun.COM 	 * calling strioc can result in the socket falling back to TPI,
9218348SEric.Yu@Sun.COM 	 * if that is supported.
9228348SEric.Yu@Sun.COM 	 */
923*12643SAnders.Persson@Sun.COM 	if ((so->so_filter_active == 0 ||
924*12643SAnders.Persson@Sun.COM 	    (error = sof_filter_ioctl(so, cmd, arg, mode,
925*12643SAnders.Persson@Sun.COM 	    rvalp, cr)) < 0) &&
926*12643SAnders.Persson@Sun.COM 	    (error = socket_ioctl_common(so, cmd, arg, mode, cr, rvalp)) < 0 &&
9278348SEric.Yu@Sun.COM 	    (error = socket_strioc_common(so, cmd, arg, mode, cr, rvalp)) < 0) {
9288348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_ioctl)(so->so_proto_handle,
9298348SEric.Yu@Sun.COM 		    cmd, arg, mode, rvalp, cr);
9308348SEric.Yu@Sun.COM 	}
9318348SEric.Yu@Sun.COM 
9328348SEric.Yu@Sun.COM done:
9338348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
9348348SEric.Yu@Sun.COM 
9358348SEric.Yu@Sun.COM 	return (error);
9368348SEric.Yu@Sun.COM }
9378348SEric.Yu@Sun.COM 
9388348SEric.Yu@Sun.COM int
9398348SEric.Yu@Sun.COM so_poll(struct sonode *so, short events, int anyyet, short *reventsp,
9408348SEric.Yu@Sun.COM     struct pollhead **phpp)
9418348SEric.Yu@Sun.COM {
9428348SEric.Yu@Sun.COM 	int state = so->so_state;
9438348SEric.Yu@Sun.COM 	*reventsp = 0;
9448348SEric.Yu@Sun.COM 
9458861SRao.Shoaib@Sun.COM 	/*
9468861SRao.Shoaib@Sun.COM 	 * In sockets the errors are represented as input/output events
9478861SRao.Shoaib@Sun.COM 	 */
9488348SEric.Yu@Sun.COM 	if (so->so_error != 0 &&
9498861SRao.Shoaib@Sun.COM 	    ((POLLIN|POLLRDNORM|POLLOUT) & events) != 0) {
9508348SEric.Yu@Sun.COM 		*reventsp = (POLLIN|POLLRDNORM|POLLOUT) & events;
9518348SEric.Yu@Sun.COM 		return (0);
9528348SEric.Yu@Sun.COM 	}
9538348SEric.Yu@Sun.COM 
9548348SEric.Yu@Sun.COM 	/*
9558861SRao.Shoaib@Sun.COM 	 * If the socket is in a state where it can send data
9568861SRao.Shoaib@Sun.COM 	 * turn on POLLWRBAND and POLLOUT events.
9578348SEric.Yu@Sun.COM 	 */
9588861SRao.Shoaib@Sun.COM 	if ((so->so_mode & SM_CONNREQUIRED) == 0 || (state & SS_ISCONNECTED)) {
9598861SRao.Shoaib@Sun.COM 		/*
9608861SRao.Shoaib@Sun.COM 		 * out of band data is allowed even if the connection
9618861SRao.Shoaib@Sun.COM 		 * is flow controlled
9628861SRao.Shoaib@Sun.COM 		 */
9638861SRao.Shoaib@Sun.COM 		*reventsp |= POLLWRBAND & events;
964*12643SAnders.Persson@Sun.COM 		if (!SO_SND_FLOWCTRLD(so)) {
9658861SRao.Shoaib@Sun.COM 			/*
9668861SRao.Shoaib@Sun.COM 			 * As long as there is buffer to send data
9678861SRao.Shoaib@Sun.COM 			 * turn on POLLOUT events
9688861SRao.Shoaib@Sun.COM 			 */
9698861SRao.Shoaib@Sun.COM 			*reventsp |= POLLOUT & events;
9708861SRao.Shoaib@Sun.COM 		}
9718348SEric.Yu@Sun.COM 	}
9728348SEric.Yu@Sun.COM 
9738348SEric.Yu@Sun.COM 	/*
9748348SEric.Yu@Sun.COM 	 * Turn on POLLIN whenever there is data on the receive queue,
9758348SEric.Yu@Sun.COM 	 * or the socket is in a state where no more data will be received.
9768348SEric.Yu@Sun.COM 	 * Also, if the socket is accepting connections, flip the bit if
9778348SEric.Yu@Sun.COM 	 * there is something on the queue.
9788427SAnders.Persson@Sun.COM 	 *
9798427SAnders.Persson@Sun.COM 	 * We do an initial check for events without holding locks. However,
9808427SAnders.Persson@Sun.COM 	 * if there are no event available, then we redo the check for POLLIN
9818427SAnders.Persson@Sun.COM 	 * events under the lock.
9828348SEric.Yu@Sun.COM 	 */
9838348SEric.Yu@Sun.COM 
9848348SEric.Yu@Sun.COM 	/* Pending connections */
985*12643SAnders.Persson@Sun.COM 	if (!list_is_empty(&so->so_acceptq_list))
9868348SEric.Yu@Sun.COM 		*reventsp |= (POLLIN|POLLRDNORM) & events;
9878348SEric.Yu@Sun.COM 
9888348SEric.Yu@Sun.COM 	/* Data */
9898348SEric.Yu@Sun.COM 	/* so_downcalls is null for sctp */
9908348SEric.Yu@Sun.COM 	if (so->so_downcalls != NULL && so->so_downcalls->sd_poll != NULL) {
9918348SEric.Yu@Sun.COM 		*reventsp |= (*so->so_downcalls->sd_poll)
9928348SEric.Yu@Sun.COM 		    (so->so_proto_handle, events & SO_PROTO_POLLEV, anyyet,
9938348SEric.Yu@Sun.COM 		    CRED()) & events;
9948348SEric.Yu@Sun.COM 		ASSERT((*reventsp & ~events) == 0);
9958348SEric.Yu@Sun.COM 		/* do not recheck events */
9968348SEric.Yu@Sun.COM 		events &= ~SO_PROTO_POLLEV;
9978348SEric.Yu@Sun.COM 	} else {
9988348SEric.Yu@Sun.COM 		if (SO_HAVE_DATA(so))
9998348SEric.Yu@Sun.COM 			*reventsp |= (POLLIN|POLLRDNORM) & events;
10008348SEric.Yu@Sun.COM 
10018348SEric.Yu@Sun.COM 		/* Urgent data */
10028861SRao.Shoaib@Sun.COM 		if ((state & SS_OOBPEND) != 0) {
10038861SRao.Shoaib@Sun.COM 			*reventsp |= (POLLRDBAND | POLLPRI) & events;
10048861SRao.Shoaib@Sun.COM 		}
10058348SEric.Yu@Sun.COM 	}
10068348SEric.Yu@Sun.COM 
10078348SEric.Yu@Sun.COM 	if (!*reventsp && !anyyet) {
10088348SEric.Yu@Sun.COM 		/* Check for read events again, but this time under lock */
10098348SEric.Yu@Sun.COM 		if (events & (POLLIN|POLLRDNORM)) {
10108348SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
1011*12643SAnders.Persson@Sun.COM 			if (SO_HAVE_DATA(so) ||
1012*12643SAnders.Persson@Sun.COM 			    !list_is_empty(&so->so_acceptq_list)) {
10138348SEric.Yu@Sun.COM 				mutex_exit(&so->so_lock);
10148348SEric.Yu@Sun.COM 				*reventsp |= (POLLIN|POLLRDNORM) & events;
10158348SEric.Yu@Sun.COM 				return (0);
10168348SEric.Yu@Sun.COM 			} else {
10178348SEric.Yu@Sun.COM 				so->so_pollev |= SO_POLLEV_IN;
10188348SEric.Yu@Sun.COM 				mutex_exit(&so->so_lock);
10198348SEric.Yu@Sun.COM 			}
10208348SEric.Yu@Sun.COM 		}
10218348SEric.Yu@Sun.COM 		*phpp = &so->so_poll_list;
10228348SEric.Yu@Sun.COM 	}
10238348SEric.Yu@Sun.COM 	return (0);
10248348SEric.Yu@Sun.COM }
10258348SEric.Yu@Sun.COM 
10268348SEric.Yu@Sun.COM /*
10278348SEric.Yu@Sun.COM  * Generic Upcalls
10288348SEric.Yu@Sun.COM  */
10298348SEric.Yu@Sun.COM void
10308348SEric.Yu@Sun.COM so_connected(sock_upper_handle_t sock_handle, sock_connid_t id,
10318348SEric.Yu@Sun.COM     cred_t *peer_cred, pid_t peer_cpid)
10328348SEric.Yu@Sun.COM {
10338348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
10348348SEric.Yu@Sun.COM 
10358348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
10368348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle != NULL);
10378348SEric.Yu@Sun.COM 
10388348SEric.Yu@Sun.COM 	if (peer_cred != NULL) {
10398348SEric.Yu@Sun.COM 		if (so->so_peercred != NULL)
10408348SEric.Yu@Sun.COM 			crfree(so->so_peercred);
10418348SEric.Yu@Sun.COM 		crhold(peer_cred);
10428348SEric.Yu@Sun.COM 		so->so_peercred = peer_cred;
10438348SEric.Yu@Sun.COM 		so->so_cpid = peer_cpid;
10448348SEric.Yu@Sun.COM 	}
10458348SEric.Yu@Sun.COM 
10468348SEric.Yu@Sun.COM 	so->so_proto_connid = id;
10478348SEric.Yu@Sun.COM 	soisconnected(so);
10488348SEric.Yu@Sun.COM 	/*
10498348SEric.Yu@Sun.COM 	 * Wake ones who're waiting for conn to become established.
10508348SEric.Yu@Sun.COM 	 */
10518348SEric.Yu@Sun.COM 	so_notify_connected(so);
10528348SEric.Yu@Sun.COM }
10538348SEric.Yu@Sun.COM 
10548348SEric.Yu@Sun.COM int
10558348SEric.Yu@Sun.COM so_disconnected(sock_upper_handle_t sock_handle, sock_connid_t id, int error)
10568348SEric.Yu@Sun.COM {
10578348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
1058*12643SAnders.Persson@Sun.COM 	boolean_t connect_failed;
10598348SEric.Yu@Sun.COM 
10608348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
1061*12643SAnders.Persson@Sun.COM 	connect_failed = so->so_state & SS_ISCONNECTED;
10628348SEric.Yu@Sun.COM 	so->so_proto_connid = id;
10638348SEric.Yu@Sun.COM 	soisdisconnected(so, error);
1064*12643SAnders.Persson@Sun.COM 	so_notify_disconnected(so, connect_failed, error);
10658348SEric.Yu@Sun.COM 
10668348SEric.Yu@Sun.COM 	return (0);
10678348SEric.Yu@Sun.COM }
10688348SEric.Yu@Sun.COM 
10698348SEric.Yu@Sun.COM void
10708348SEric.Yu@Sun.COM so_opctl(sock_upper_handle_t sock_handle, sock_opctl_action_t action,
10718348SEric.Yu@Sun.COM     uintptr_t arg)
10728348SEric.Yu@Sun.COM {
10738348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
10748348SEric.Yu@Sun.COM 
10758348SEric.Yu@Sun.COM 	switch (action) {
10768348SEric.Yu@Sun.COM 	case SOCK_OPCTL_SHUT_SEND:
10778348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
10788348SEric.Yu@Sun.COM 		socantsendmore(so);
10798348SEric.Yu@Sun.COM 		so_notify_disconnecting(so);
10808348SEric.Yu@Sun.COM 		break;
10818348SEric.Yu@Sun.COM 	case SOCK_OPCTL_SHUT_RECV: {
10828348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
10838348SEric.Yu@Sun.COM 		socantrcvmore(so);
10848348SEric.Yu@Sun.COM 		so_notify_eof(so);
10858348SEric.Yu@Sun.COM 		break;
10868348SEric.Yu@Sun.COM 	}
10878348SEric.Yu@Sun.COM 	case SOCK_OPCTL_ENAB_ACCEPT:
10888348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
10898348SEric.Yu@Sun.COM 		so->so_state |= SS_ACCEPTCONN;
10908348SEric.Yu@Sun.COM 		so->so_backlog = (unsigned int)arg;
1091*12643SAnders.Persson@Sun.COM 		/*
1092*12643SAnders.Persson@Sun.COM 		 * The protocol can stop generating newconn upcalls when
1093*12643SAnders.Persson@Sun.COM 		 * the backlog is full, so to make sure the listener does
1094*12643SAnders.Persson@Sun.COM 		 * not end up with a queue full of deferred connections
1095*12643SAnders.Persson@Sun.COM 		 * we reduce the backlog by one. Thus the listener will
1096*12643SAnders.Persson@Sun.COM 		 * start closing deferred connections before the backlog
1097*12643SAnders.Persson@Sun.COM 		 * is full.
1098*12643SAnders.Persson@Sun.COM 		 */
1099*12643SAnders.Persson@Sun.COM 		if (so->so_filter_active > 0)
1100*12643SAnders.Persson@Sun.COM 			so->so_backlog = MAX(1, so->so_backlog - 1);
11018348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
11028348SEric.Yu@Sun.COM 		break;
11038348SEric.Yu@Sun.COM 	default:
11048348SEric.Yu@Sun.COM 		ASSERT(0);
11058348SEric.Yu@Sun.COM 		break;
11068348SEric.Yu@Sun.COM 	}
11078348SEric.Yu@Sun.COM }
11088348SEric.Yu@Sun.COM 
11098348SEric.Yu@Sun.COM void
11108348SEric.Yu@Sun.COM so_txq_full(sock_upper_handle_t sock_handle, boolean_t qfull)
11118348SEric.Yu@Sun.COM {
11128348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
11138348SEric.Yu@Sun.COM 
11148348SEric.Yu@Sun.COM 	if (qfull) {
11158348SEric.Yu@Sun.COM 		so_snd_qfull(so);
11168348SEric.Yu@Sun.COM 	} else {
11178348SEric.Yu@Sun.COM 		so_snd_qnotfull(so);
11188348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
1119*12643SAnders.Persson@Sun.COM 		/* so_notify_writable drops so_lock */
11208348SEric.Yu@Sun.COM 		so_notify_writable(so);
11218348SEric.Yu@Sun.COM 	}
11228348SEric.Yu@Sun.COM }
11238348SEric.Yu@Sun.COM 
11248348SEric.Yu@Sun.COM sock_upper_handle_t
11258348SEric.Yu@Sun.COM so_newconn(sock_upper_handle_t parenthandle,
11268348SEric.Yu@Sun.COM     sock_lower_handle_t proto_handle, sock_downcalls_t *sock_downcalls,
11278348SEric.Yu@Sun.COM     struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **sock_upcallsp)
11288348SEric.Yu@Sun.COM {
11298348SEric.Yu@Sun.COM 	struct sonode	*so = (struct sonode *)parenthandle;
11308348SEric.Yu@Sun.COM 	struct sonode	*nso;
11318348SEric.Yu@Sun.COM 	int error;
11328348SEric.Yu@Sun.COM 
11338348SEric.Yu@Sun.COM 	ASSERT(proto_handle != NULL);
11348348SEric.Yu@Sun.COM 
11358348SEric.Yu@Sun.COM 	if ((so->so_state & SS_ACCEPTCONN) == 0 ||
1136*12643SAnders.Persson@Sun.COM 	    (so->so_acceptq_len >= so->so_backlog &&
1137*12643SAnders.Persson@Sun.COM 	    (so->so_filter_active == 0 || !sof_sonode_drop_deferred(so)))) {
1138*12643SAnders.Persson@Sun.COM 			return (NULL);
1139*12643SAnders.Persson@Sun.COM 	}
11408348SEric.Yu@Sun.COM 
11418348SEric.Yu@Sun.COM 	nso = socket_newconn(so, proto_handle, sock_downcalls, SOCKET_NOSLEEP,
11428348SEric.Yu@Sun.COM 	    &error);
11438348SEric.Yu@Sun.COM 	if (nso == NULL)
11448348SEric.Yu@Sun.COM 		return (NULL);
11458348SEric.Yu@Sun.COM 
11468348SEric.Yu@Sun.COM 	if (peer_cred != NULL) {
11478348SEric.Yu@Sun.COM 		crhold(peer_cred);
11488348SEric.Yu@Sun.COM 		nso->so_peercred = peer_cred;
11498348SEric.Yu@Sun.COM 		nso->so_cpid = peer_cpid;
11508348SEric.Yu@Sun.COM 	}
1151*12643SAnders.Persson@Sun.COM 	nso->so_listener = so;
11528348SEric.Yu@Sun.COM 
11538820SAnders.Persson@Sun.COM 	/*
11548820SAnders.Persson@Sun.COM 	 * The new socket (nso), proto_handle and sock_upcallsp are all
11558820SAnders.Persson@Sun.COM 	 * valid at this point. But as soon as nso is placed in the accept
11568820SAnders.Persson@Sun.COM 	 * queue that can no longer be assumed (since an accept() thread may
11578820SAnders.Persson@Sun.COM 	 * pull it off the queue and close the socket).
11588820SAnders.Persson@Sun.COM 	 */
11598820SAnders.Persson@Sun.COM 	*sock_upcallsp = &so_upcalls;
11608820SAnders.Persson@Sun.COM 
1161*12643SAnders.Persson@Sun.COM 	mutex_enter(&so->so_acceptq_lock);
1162*12643SAnders.Persson@Sun.COM 	if (so->so_state & (SS_CLOSING|SS_FALLBACK_PENDING|SS_FALLBACK_COMP)) {
1163*12643SAnders.Persson@Sun.COM 		mutex_exit(&so->so_acceptq_lock);
1164*12643SAnders.Persson@Sun.COM 		ASSERT(nso->so_count == 1);
1165*12643SAnders.Persson@Sun.COM 		nso->so_count--;
1166*12643SAnders.Persson@Sun.COM 		/* drop proto ref */
1167*12643SAnders.Persson@Sun.COM 		VN_RELE(SOTOV(nso));
1168*12643SAnders.Persson@Sun.COM 		socket_destroy(nso);
1169*12643SAnders.Persson@Sun.COM 		return (NULL);
1170*12643SAnders.Persson@Sun.COM 	} else {
1171*12643SAnders.Persson@Sun.COM 		so->so_acceptq_len++;
1172*12643SAnders.Persson@Sun.COM 		if (nso->so_state & SS_FIL_DEFER) {
1173*12643SAnders.Persson@Sun.COM 			list_insert_tail(&so->so_acceptq_defer, nso);
1174*12643SAnders.Persson@Sun.COM 			mutex_exit(&so->so_acceptq_lock);
1175*12643SAnders.Persson@Sun.COM 		} else {
1176*12643SAnders.Persson@Sun.COM 			list_insert_tail(&so->so_acceptq_list, nso);
1177*12643SAnders.Persson@Sun.COM 			cv_signal(&so->so_acceptq_cv);
1178*12643SAnders.Persson@Sun.COM 			mutex_exit(&so->so_acceptq_lock);
1179*12643SAnders.Persson@Sun.COM 			mutex_enter(&so->so_lock);
1180*12643SAnders.Persson@Sun.COM 			so_notify_newconn(so);
1181*12643SAnders.Persson@Sun.COM 		}
11828820SAnders.Persson@Sun.COM 
1183*12643SAnders.Persson@Sun.COM 		return ((sock_upper_handle_t)nso);
1184*12643SAnders.Persson@Sun.COM 	}
11858348SEric.Yu@Sun.COM }
11868348SEric.Yu@Sun.COM 
11878348SEric.Yu@Sun.COM void
11888348SEric.Yu@Sun.COM so_set_prop(sock_upper_handle_t sock_handle, struct sock_proto_props *soppp)
11898348SEric.Yu@Sun.COM {
11908348SEric.Yu@Sun.COM 	struct sonode *so;
11918348SEric.Yu@Sun.COM 
11928348SEric.Yu@Sun.COM 	so = (struct sonode *)sock_handle;
11938348SEric.Yu@Sun.COM 
11948348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
11958348SEric.Yu@Sun.COM 
11968348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_MAXBLK)
11978348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk;
11988348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_WROFF)
11998348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_wroff = soppp->sopp_wroff;
12008348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_TAIL)
12018348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_tail = soppp->sopp_tail;
12028348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_RCVHIWAT)
12038348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_rxhiwat = soppp->sopp_rxhiwat;
12048348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_RCVLOWAT)
12058348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_rxlowat = soppp->sopp_rxlowat;
12068348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_MAXPSZ)
12078348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_maxpsz = soppp->sopp_maxpsz;
12088348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_MINPSZ)
12098348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_minpsz = soppp->sopp_minpsz;
12108348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_ZCOPY) {
12118348SEric.Yu@Sun.COM 		if (soppp->sopp_zcopyflag & ZCVMSAFE) {
12128348SEric.Yu@Sun.COM 			so->so_proto_props.sopp_zcopyflag |= STZCVMSAFE;
12138348SEric.Yu@Sun.COM 			so->so_proto_props.sopp_zcopyflag &= ~STZCVMUNSAFE;
12148348SEric.Yu@Sun.COM 		} else if (soppp->sopp_zcopyflag & ZCVMUNSAFE) {
12158348SEric.Yu@Sun.COM 			so->so_proto_props.sopp_zcopyflag |= STZCVMUNSAFE;
12168348SEric.Yu@Sun.COM 			so->so_proto_props.sopp_zcopyflag &= ~STZCVMSAFE;
12178348SEric.Yu@Sun.COM 		}
12188348SEric.Yu@Sun.COM 
12198348SEric.Yu@Sun.COM 		if (soppp->sopp_zcopyflag & COPYCACHED) {
12208348SEric.Yu@Sun.COM 			so->so_proto_props.sopp_zcopyflag |= STRCOPYCACHED;
12218348SEric.Yu@Sun.COM 		}
12228348SEric.Yu@Sun.COM 	}
12238348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_OOBINLINE)
12248348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_oobinline = soppp->sopp_oobinline;
12258348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_RCVTIMER)
12268348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_rcvtimer = soppp->sopp_rcvtimer;
12278348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_RCVTHRESH)
12288348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh;
12298348SEric.Yu@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN)
12308348SEric.Yu@Sun.COM 		so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen;
123110103SAnders.Persson@Sun.COM 	if (soppp->sopp_flags & SOCKOPT_LOOPBACK)
123210103SAnders.Persson@Sun.COM 		so->so_proto_props.sopp_loopback = soppp->sopp_loopback;
12338348SEric.Yu@Sun.COM 
12348348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
12358348SEric.Yu@Sun.COM 
1236*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active > 0) {
1237*12643SAnders.Persson@Sun.COM 		sof_instance_t *inst;
1238*12643SAnders.Persson@Sun.COM 		ssize_t maxblk;
1239*12643SAnders.Persson@Sun.COM 		ushort_t wroff, tail;
1240*12643SAnders.Persson@Sun.COM 		maxblk = so->so_proto_props.sopp_maxblk;
1241*12643SAnders.Persson@Sun.COM 		wroff = so->so_proto_props.sopp_wroff;
1242*12643SAnders.Persson@Sun.COM 		tail = so->so_proto_props.sopp_tail;
1243*12643SAnders.Persson@Sun.COM 		for (inst = so->so_filter_bottom; inst != NULL;
1244*12643SAnders.Persson@Sun.COM 		    inst = inst->sofi_prev) {
1245*12643SAnders.Persson@Sun.COM 			if (SOF_INTERESTED(inst, mblk_prop)) {
1246*12643SAnders.Persson@Sun.COM 				(*inst->sofi_ops->sofop_mblk_prop)(
1247*12643SAnders.Persson@Sun.COM 				    (sof_handle_t)inst, inst->sofi_cookie,
1248*12643SAnders.Persson@Sun.COM 				    &maxblk, &wroff, &tail);
1249*12643SAnders.Persson@Sun.COM 			}
1250*12643SAnders.Persson@Sun.COM 		}
1251*12643SAnders.Persson@Sun.COM 		mutex_enter(&so->so_lock);
1252*12643SAnders.Persson@Sun.COM 		so->so_proto_props.sopp_maxblk = maxblk;
1253*12643SAnders.Persson@Sun.COM 		so->so_proto_props.sopp_wroff = wroff;
1254*12643SAnders.Persson@Sun.COM 		so->so_proto_props.sopp_tail = tail;
1255*12643SAnders.Persson@Sun.COM 		mutex_exit(&so->so_lock);
1256*12643SAnders.Persson@Sun.COM 	}
12578348SEric.Yu@Sun.COM #ifdef DEBUG
12588348SEric.Yu@Sun.COM 	soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL |
12598348SEric.Yu@Sun.COM 	    SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ |
12608348SEric.Yu@Sun.COM 	    SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER |
126110103SAnders.Persson@Sun.COM 	    SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ |
126210103SAnders.Persson@Sun.COM 	    SOCKOPT_LOOPBACK);
12638348SEric.Yu@Sun.COM 	ASSERT(soppp->sopp_flags == 0);
12648348SEric.Yu@Sun.COM #endif
12658348SEric.Yu@Sun.COM }
12668348SEric.Yu@Sun.COM 
12678348SEric.Yu@Sun.COM /* ARGSUSED */
12688348SEric.Yu@Sun.COM ssize_t
1269*12643SAnders.Persson@Sun.COM so_queue_msg_impl(struct sonode *so, mblk_t *mp,
1270*12643SAnders.Persson@Sun.COM     size_t msg_size, int flags, int *errorp,  boolean_t *force_pushp,
1271*12643SAnders.Persson@Sun.COM     sof_instance_t *filter)
12728348SEric.Yu@Sun.COM {
12738348SEric.Yu@Sun.COM 	boolean_t force_push = B_TRUE;
12748348SEric.Yu@Sun.COM 	int space_left;
12758348SEric.Yu@Sun.COM 	sodirect_t *sodp = so->so_direct;
12768348SEric.Yu@Sun.COM 
12778348SEric.Yu@Sun.COM 	ASSERT(errorp != NULL);
12788348SEric.Yu@Sun.COM 	*errorp = 0;
12798348SEric.Yu@Sun.COM 	if (mp == NULL) {
128012198SEiji.Ota@Sun.COM 		if (so->so_downcalls->sd_recv_uio != NULL) {
12818348SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
12828348SEric.Yu@Sun.COM 			/* the notify functions will drop the lock */
12838348SEric.Yu@Sun.COM 			if (flags & MSG_OOB)
12848348SEric.Yu@Sun.COM 				so_notify_oobdata(so, IS_SO_OOB_INLINE(so));
12858348SEric.Yu@Sun.COM 			else
12868348SEric.Yu@Sun.COM 				so_notify_data(so, msg_size);
12878348SEric.Yu@Sun.COM 			return (0);
12888348SEric.Yu@Sun.COM 		}
128912198SEiji.Ota@Sun.COM 		ASSERT(msg_size == 0);
12908348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
1291*12643SAnders.Persson@Sun.COM 		goto space_check;
12928348SEric.Yu@Sun.COM 	}
12938348SEric.Yu@Sun.COM 
12948348SEric.Yu@Sun.COM 	ASSERT(mp->b_next == NULL);
12958348SEric.Yu@Sun.COM 	ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_PROTO);
12968348SEric.Yu@Sun.COM 	ASSERT(msg_size == msgdsize(mp));
12978348SEric.Yu@Sun.COM 
12988348SEric.Yu@Sun.COM 	if (DB_TYPE(mp) == M_PROTO && !__TPI_PRIM_ISALIGNED(mp->b_rptr)) {
12998348SEric.Yu@Sun.COM 		/* The read pointer is not aligned correctly for TPI */
13008348SEric.Yu@Sun.COM 		zcmn_err(getzoneid(), CE_WARN,
13018348SEric.Yu@Sun.COM 		    "sockfs: Unaligned TPI message received. rptr = %p\n",
13028348SEric.Yu@Sun.COM 		    (void *)mp->b_rptr);
13038348SEric.Yu@Sun.COM 		freemsg(mp);
13049491SAnders.Persson@Sun.COM 		mutex_enter(&so->so_lock);
13059491SAnders.Persson@Sun.COM 		if (sodp != NULL)
13069491SAnders.Persson@Sun.COM 			SOD_UIOAFINI(sodp);
1307*12643SAnders.Persson@Sun.COM 		goto space_check;
1308*12643SAnders.Persson@Sun.COM 	}
13098348SEric.Yu@Sun.COM 
1310*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active > 0) {
1311*12643SAnders.Persson@Sun.COM 		for (; filter != NULL; filter = filter->sofi_prev) {
1312*12643SAnders.Persson@Sun.COM 			if (!SOF_INTERESTED(filter, data_in))
1313*12643SAnders.Persson@Sun.COM 				continue;
1314*12643SAnders.Persson@Sun.COM 			mp = (*filter->sofi_ops->sofop_data_in)(
1315*12643SAnders.Persson@Sun.COM 			    (sof_handle_t)filter, filter->sofi_cookie, mp,
1316*12643SAnders.Persson@Sun.COM 			    flags, &msg_size);
1317*12643SAnders.Persson@Sun.COM 			ASSERT(msgdsize(mp) == msg_size);
1318*12643SAnders.Persson@Sun.COM 			DTRACE_PROBE2(filter__data, (sof_instance_t), filter,
1319*12643SAnders.Persson@Sun.COM 			    (mblk_t *), mp);
1320*12643SAnders.Persson@Sun.COM 			/* Data was consumed/dropped, just do space check */
1321*12643SAnders.Persson@Sun.COM 			if (msg_size == 0) {
1322*12643SAnders.Persson@Sun.COM 				mutex_enter(&so->so_lock);
1323*12643SAnders.Persson@Sun.COM 				goto space_check;
1324*12643SAnders.Persson@Sun.COM 			}
1325*12643SAnders.Persson@Sun.COM 		}
13268348SEric.Yu@Sun.COM 	}
13278348SEric.Yu@Sun.COM 
1328*12643SAnders.Persson@Sun.COM 	if (flags & MSG_OOB) {
1329*12643SAnders.Persson@Sun.COM 		so_queue_oob(so, mp, msg_size);
1330*12643SAnders.Persson@Sun.COM 		mutex_enter(&so->so_lock);
1331*12643SAnders.Persson@Sun.COM 		goto space_check;
1332*12643SAnders.Persson@Sun.COM 	}
1333*12643SAnders.Persson@Sun.COM 
1334*12643SAnders.Persson@Sun.COM 	if (force_pushp != NULL)
1335*12643SAnders.Persson@Sun.COM 		force_push = *force_pushp;
1336*12643SAnders.Persson@Sun.COM 
13378348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
13388963SAnders.Persson@Sun.COM 	if (so->so_state & (SS_FALLBACK_DRAIN | SS_FALLBACK_COMP)) {
13399491SAnders.Persson@Sun.COM 		if (sodp != NULL)
13409491SAnders.Persson@Sun.COM 			SOD_DISABLE(sodp);
13418348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
13428348SEric.Yu@Sun.COM 		*errorp = EOPNOTSUPP;
13438348SEric.Yu@Sun.COM 		return (-1);
13448348SEric.Yu@Sun.COM 	}
1345*12643SAnders.Persson@Sun.COM 	if (so->so_state & (SS_CANTRCVMORE | SS_CLOSING)) {
13468348SEric.Yu@Sun.COM 		freemsg(mp);
13479491SAnders.Persson@Sun.COM 		if (sodp != NULL)
13489491SAnders.Persson@Sun.COM 			SOD_DISABLE(sodp);
13498348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
13508348SEric.Yu@Sun.COM 		return (0);
13518348SEric.Yu@Sun.COM 	}
13528348SEric.Yu@Sun.COM 
13538348SEric.Yu@Sun.COM 	/* process the mblk via I/OAT if capable */
13549491SAnders.Persson@Sun.COM 	if (sodp != NULL && sodp->sod_enabled) {
13558348SEric.Yu@Sun.COM 		if (DB_TYPE(mp) == M_DATA) {
13569491SAnders.Persson@Sun.COM 			sod_uioa_mblk_init(sodp, mp, msg_size);
13578348SEric.Yu@Sun.COM 		} else {
13588348SEric.Yu@Sun.COM 			SOD_UIOAFINI(sodp);
13598348SEric.Yu@Sun.COM 		}
13608348SEric.Yu@Sun.COM 	}
13618348SEric.Yu@Sun.COM 
13628348SEric.Yu@Sun.COM 	if (mp->b_next == NULL) {
13638348SEric.Yu@Sun.COM 		so_enqueue_msg(so, mp, msg_size);
13648348SEric.Yu@Sun.COM 	} else {
13658348SEric.Yu@Sun.COM 		do {
13668348SEric.Yu@Sun.COM 			mblk_t *nmp;
13678348SEric.Yu@Sun.COM 
13688348SEric.Yu@Sun.COM 			if ((nmp = mp->b_next) != NULL) {
13698348SEric.Yu@Sun.COM 				mp->b_next = NULL;
13708348SEric.Yu@Sun.COM 			}
13718348SEric.Yu@Sun.COM 			so_enqueue_msg(so, mp, msgdsize(mp));
13728348SEric.Yu@Sun.COM 			mp = nmp;
13738348SEric.Yu@Sun.COM 		} while (mp != NULL);
13748348SEric.Yu@Sun.COM 	}
13758348SEric.Yu@Sun.COM 
13768348SEric.Yu@Sun.COM 	space_left = so->so_rcvbuf - so->so_rcv_queued;
13778348SEric.Yu@Sun.COM 	if (space_left <= 0) {
13788348SEric.Yu@Sun.COM 		so->so_flowctrld = B_TRUE;
13798348SEric.Yu@Sun.COM 		*errorp = ENOSPC;
13808348SEric.Yu@Sun.COM 		space_left = -1;
13818348SEric.Yu@Sun.COM 	}
13828348SEric.Yu@Sun.COM 
13838348SEric.Yu@Sun.COM 	if (force_push || so->so_rcv_queued >= so->so_rcv_thresh ||
13849491SAnders.Persson@Sun.COM 	    so->so_rcv_queued >= so->so_rcv_wanted) {
13858348SEric.Yu@Sun.COM 		SOCKET_TIMER_CANCEL(so);
13868348SEric.Yu@Sun.COM 		/*
13878348SEric.Yu@Sun.COM 		 * so_notify_data will release the lock
13888348SEric.Yu@Sun.COM 		 */
13898348SEric.Yu@Sun.COM 		so_notify_data(so, so->so_rcv_queued);
13908348SEric.Yu@Sun.COM 
13918348SEric.Yu@Sun.COM 		if (force_pushp != NULL)
13928348SEric.Yu@Sun.COM 			*force_pushp = B_TRUE;
13938348SEric.Yu@Sun.COM 		goto done;
13948348SEric.Yu@Sun.COM 	} else if (so->so_rcv_timer_tid == 0) {
13958348SEric.Yu@Sun.COM 		/* Make sure the recv push timer is running */
13968348SEric.Yu@Sun.COM 		SOCKET_TIMER_START(so);
13978348SEric.Yu@Sun.COM 	}
13988348SEric.Yu@Sun.COM 
13998348SEric.Yu@Sun.COM done_unlock:
14008348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
14018348SEric.Yu@Sun.COM done:
14028348SEric.Yu@Sun.COM 	return (space_left);
1403*12643SAnders.Persson@Sun.COM 
1404*12643SAnders.Persson@Sun.COM space_check:
1405*12643SAnders.Persson@Sun.COM 	space_left = so->so_rcvbuf - so->so_rcv_queued;
1406*12643SAnders.Persson@Sun.COM 	if (space_left <= 0) {
1407*12643SAnders.Persson@Sun.COM 		so->so_flowctrld = B_TRUE;
1408*12643SAnders.Persson@Sun.COM 		*errorp = ENOSPC;
1409*12643SAnders.Persson@Sun.COM 		space_left = -1;
1410*12643SAnders.Persson@Sun.COM 	}
1411*12643SAnders.Persson@Sun.COM 	goto done_unlock;
1412*12643SAnders.Persson@Sun.COM }
1413*12643SAnders.Persson@Sun.COM 
1414*12643SAnders.Persson@Sun.COM #pragma	inline(so_queue_msg_impl)
1415*12643SAnders.Persson@Sun.COM 
1416*12643SAnders.Persson@Sun.COM ssize_t
1417*12643SAnders.Persson@Sun.COM so_queue_msg(sock_upper_handle_t sock_handle, mblk_t *mp,
1418*12643SAnders.Persson@Sun.COM     size_t msg_size, int flags, int *errorp,  boolean_t *force_pushp)
1419*12643SAnders.Persson@Sun.COM {
1420*12643SAnders.Persson@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
1421*12643SAnders.Persson@Sun.COM 
1422*12643SAnders.Persson@Sun.COM 	return (so_queue_msg_impl(so, mp, msg_size, flags, errorp, force_pushp,
1423*12643SAnders.Persson@Sun.COM 	    so->so_filter_bottom));
14248348SEric.Yu@Sun.COM }
14258348SEric.Yu@Sun.COM 
14268348SEric.Yu@Sun.COM /*
14278348SEric.Yu@Sun.COM  * Set the offset of where the oob data is relative to the bytes in
14288348SEric.Yu@Sun.COM  * queued. Also generate SIGURG
14298348SEric.Yu@Sun.COM  */
14308348SEric.Yu@Sun.COM void
14318348SEric.Yu@Sun.COM so_signal_oob(sock_upper_handle_t sock_handle, ssize_t offset)
14328348SEric.Yu@Sun.COM {
14338348SEric.Yu@Sun.COM 	struct sonode *so;
14348348SEric.Yu@Sun.COM 
14358348SEric.Yu@Sun.COM 	ASSERT(offset >= 0);
14368348SEric.Yu@Sun.COM 	so = (struct sonode *)sock_handle;
14378348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
14389491SAnders.Persson@Sun.COM 	if (so->so_direct != NULL)
14399491SAnders.Persson@Sun.COM 		SOD_UIOAFINI(so->so_direct);
14408348SEric.Yu@Sun.COM 
14418348SEric.Yu@Sun.COM 	/*
14428348SEric.Yu@Sun.COM 	 * New urgent data on the way so forget about any old
14438348SEric.Yu@Sun.COM 	 * urgent data.
14448348SEric.Yu@Sun.COM 	 */
14458348SEric.Yu@Sun.COM 	so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA);
14468348SEric.Yu@Sun.COM 
14478348SEric.Yu@Sun.COM 	/*
14488348SEric.Yu@Sun.COM 	 * Record that urgent data is pending.
14498348SEric.Yu@Sun.COM 	 */
14508348SEric.Yu@Sun.COM 	so->so_state |= SS_OOBPEND;
14518348SEric.Yu@Sun.COM 
14528348SEric.Yu@Sun.COM 	if (so->so_oobmsg != NULL) {
14538348SEric.Yu@Sun.COM 		dprintso(so, 1, ("sock: discarding old oob\n"));
14548348SEric.Yu@Sun.COM 		freemsg(so->so_oobmsg);
14558348SEric.Yu@Sun.COM 		so->so_oobmsg = NULL;
14568348SEric.Yu@Sun.COM 	}
14578348SEric.Yu@Sun.COM 
14588348SEric.Yu@Sun.COM 	/*
14598348SEric.Yu@Sun.COM 	 * set the offset where the urgent byte is
14608348SEric.Yu@Sun.COM 	 */
14618348SEric.Yu@Sun.COM 	so->so_oobmark = so->so_rcv_queued + offset;
14628348SEric.Yu@Sun.COM 	if (so->so_oobmark == 0)
14638348SEric.Yu@Sun.COM 		so->so_state |= SS_RCVATMARK;
14648348SEric.Yu@Sun.COM 	else
14658348SEric.Yu@Sun.COM 		so->so_state &= ~SS_RCVATMARK;
14668348SEric.Yu@Sun.COM 
14678348SEric.Yu@Sun.COM 	so_notify_oobsig(so);
14688348SEric.Yu@Sun.COM }
14698348SEric.Yu@Sun.COM 
14708348SEric.Yu@Sun.COM /*
14718348SEric.Yu@Sun.COM  * Queue the OOB byte
14728348SEric.Yu@Sun.COM  */
14738348SEric.Yu@Sun.COM static void
1474*12643SAnders.Persson@Sun.COM so_queue_oob(struct sonode *so, mblk_t *mp, size_t len)
14758348SEric.Yu@Sun.COM {
14768348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
14779491SAnders.Persson@Sun.COM 	if (so->so_direct != NULL)
14789491SAnders.Persson@Sun.COM 		SOD_UIOAFINI(so->so_direct);
14798348SEric.Yu@Sun.COM 
14808348SEric.Yu@Sun.COM 	ASSERT(mp != NULL);
14818348SEric.Yu@Sun.COM 	if (!IS_SO_OOB_INLINE(so)) {
14828348SEric.Yu@Sun.COM 		so->so_oobmsg = mp;
14838348SEric.Yu@Sun.COM 		so->so_state |= SS_HAVEOOBDATA;
14848348SEric.Yu@Sun.COM 	} else {
14858348SEric.Yu@Sun.COM 		so_enqueue_msg(so, mp, len);
14868348SEric.Yu@Sun.COM 	}
14878348SEric.Yu@Sun.COM 
14888348SEric.Yu@Sun.COM 	so_notify_oobdata(so, IS_SO_OOB_INLINE(so));
14898348SEric.Yu@Sun.COM }
14908348SEric.Yu@Sun.COM 
14918348SEric.Yu@Sun.COM int
14928348SEric.Yu@Sun.COM so_close(struct sonode *so, int flag, struct cred *cr)
14938348SEric.Yu@Sun.COM {
14948348SEric.Yu@Sun.COM 	int error;
14958348SEric.Yu@Sun.COM 
14968348SEric.Yu@Sun.COM 	/*
1497*12643SAnders.Persson@Sun.COM 	 * No new data will be enqueued once the CLOSING flag is set.
14988348SEric.Yu@Sun.COM 	 */
14998348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
1500*12643SAnders.Persson@Sun.COM 	so->so_state |= SS_CLOSING;
15018399SRao.Shoaib@Sun.COM 	ASSERT(so_verify_oobstate(so));
15028348SEric.Yu@Sun.COM 	so_rcv_flush(so);
15038348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
15048348SEric.Yu@Sun.COM 
1505*12643SAnders.Persson@Sun.COM 	if (so->so_state & SS_ACCEPTCONN) {
1506*12643SAnders.Persson@Sun.COM 		/*
1507*12643SAnders.Persson@Sun.COM 		 * We grab and release the accept lock to ensure that any
1508*12643SAnders.Persson@Sun.COM 		 * thread about to insert a socket in so_newconn completes
1509*12643SAnders.Persson@Sun.COM 		 * before we flush the queue. Any thread calling so_newconn
1510*12643SAnders.Persson@Sun.COM 		 * after we drop the lock will observe the SS_CLOSING flag,
1511*12643SAnders.Persson@Sun.COM 		 * which will stop it from inserting the socket in the queue.
1512*12643SAnders.Persson@Sun.COM 		 */
1513*12643SAnders.Persson@Sun.COM 		mutex_enter(&so->so_acceptq_lock);
1514*12643SAnders.Persson@Sun.COM 		mutex_exit(&so->so_acceptq_lock);
1515*12643SAnders.Persson@Sun.COM 
1516*12643SAnders.Persson@Sun.COM 		so_acceptq_flush(so, B_TRUE);
1517*12643SAnders.Persson@Sun.COM 	}
1518*12643SAnders.Persson@Sun.COM 
1519*12643SAnders.Persson@Sun.COM 	if (so->so_filter_active > 0)
1520*12643SAnders.Persson@Sun.COM 		sof_sonode_closing(so);
1521*12643SAnders.Persson@Sun.COM 
1522*12643SAnders.Persson@Sun.COM 	error = (*so->so_downcalls->sd_close)(so->so_proto_handle, flag, cr);
1523*12643SAnders.Persson@Sun.COM 	switch (error) {
1524*12643SAnders.Persson@Sun.COM 	default:
1525*12643SAnders.Persson@Sun.COM 		/* Protocol made a synchronous close; remove proto ref */
1526*12643SAnders.Persson@Sun.COM 		VN_RELE(SOTOV(so));
1527*12643SAnders.Persson@Sun.COM 		break;
1528*12643SAnders.Persson@Sun.COM 	case EINPROGRESS:
1529*12643SAnders.Persson@Sun.COM 		/*
1530*12643SAnders.Persson@Sun.COM 		 * Protocol is in the process of closing, it will make a
1531*12643SAnders.Persson@Sun.COM 		 * 'closed' upcall to remove the reference.
1532*12643SAnders.Persson@Sun.COM 		 */
1533*12643SAnders.Persson@Sun.COM 		error = 0;
1534*12643SAnders.Persson@Sun.COM 		break;
1535*12643SAnders.Persson@Sun.COM 	}
1536*12643SAnders.Persson@Sun.COM 
15378348SEric.Yu@Sun.COM 	return (error);
15388348SEric.Yu@Sun.COM }
15398348SEric.Yu@Sun.COM 
1540*12643SAnders.Persson@Sun.COM /*
1541*12643SAnders.Persson@Sun.COM  * Upcall made by the protocol when it's doing an asynchronous close. It
1542*12643SAnders.Persson@Sun.COM  * will drop the protocol's reference on the socket.
1543*12643SAnders.Persson@Sun.COM  */
1544*12643SAnders.Persson@Sun.COM void
1545*12643SAnders.Persson@Sun.COM so_closed(sock_upper_handle_t sock_handle)
1546*12643SAnders.Persson@Sun.COM {
1547*12643SAnders.Persson@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
1548*12643SAnders.Persson@Sun.COM 
1549*12643SAnders.Persson@Sun.COM 	VN_RELE(SOTOV(so));
1550*12643SAnders.Persson@Sun.COM }
1551*12643SAnders.Persson@Sun.COM 
15528348SEric.Yu@Sun.COM void
15538348SEric.Yu@Sun.COM so_zcopy_notify(sock_upper_handle_t sock_handle)
15548348SEric.Yu@Sun.COM {
15558348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
15568348SEric.Yu@Sun.COM 
15578348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
15588348SEric.Yu@Sun.COM 	so->so_copyflag |= STZCNOTIFY;
15598348SEric.Yu@Sun.COM 	cv_broadcast(&so->so_copy_cv);
15608348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
15618348SEric.Yu@Sun.COM }
15628348SEric.Yu@Sun.COM 
15638348SEric.Yu@Sun.COM void
15648348SEric.Yu@Sun.COM so_set_error(sock_upper_handle_t sock_handle, int error)
15658348SEric.Yu@Sun.COM {
15668348SEric.Yu@Sun.COM 	struct sonode *so = (struct sonode *)sock_handle;
15678348SEric.Yu@Sun.COM 
15688348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
15698348SEric.Yu@Sun.COM 
15708348SEric.Yu@Sun.COM 	soseterror(so, error);
15718348SEric.Yu@Sun.COM 
15728348SEric.Yu@Sun.COM 	so_notify_error(so);
15738348SEric.Yu@Sun.COM }
15748348SEric.Yu@Sun.COM 
15758348SEric.Yu@Sun.COM /*
15768348SEric.Yu@Sun.COM  * so_recvmsg - read data from the socket
15778348SEric.Yu@Sun.COM  *
15788348SEric.Yu@Sun.COM  * There are two ways of obtaining data; either we ask the protocol to
15798348SEric.Yu@Sun.COM  * copy directly into the supplied buffer, or we copy data from the
15808348SEric.Yu@Sun.COM  * sonode's receive queue. The decision which one to use depends on
15818348SEric.Yu@Sun.COM  * whether the protocol has a sd_recv_uio down call.
15828348SEric.Yu@Sun.COM  */
15838348SEric.Yu@Sun.COM int
15848348SEric.Yu@Sun.COM so_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
15858348SEric.Yu@Sun.COM     struct cred *cr)
15868348SEric.Yu@Sun.COM {
15878348SEric.Yu@Sun.COM 	rval_t 		rval;
15888348SEric.Yu@Sun.COM 	int 		flags = 0;
15898348SEric.Yu@Sun.COM 	t_uscalar_t	controllen, namelen;
15908348SEric.Yu@Sun.COM 	int 		error = 0;
15918348SEric.Yu@Sun.COM 	int ret;
15928348SEric.Yu@Sun.COM 	mblk_t		*mctlp = NULL;
15938348SEric.Yu@Sun.COM 	union T_primitives *tpr;
15948348SEric.Yu@Sun.COM 	void		*control;
15958348SEric.Yu@Sun.COM 	ssize_t		saved_resid;
15968348SEric.Yu@Sun.COM 	struct uio	*suiop;
15978348SEric.Yu@Sun.COM 
15988348SEric.Yu@Sun.COM 	SO_BLOCK_FALLBACK(so, SOP_RECVMSG(so, msg, uiop, cr));
15998348SEric.Yu@Sun.COM 
16008348SEric.Yu@Sun.COM 	if ((so->so_state & (SS_ISCONNECTED|SS_CANTRCVMORE)) == 0 &&
16018348SEric.Yu@Sun.COM 	    (so->so_mode & SM_CONNREQUIRED)) {
16028348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
16038348SEric.Yu@Sun.COM 		return (ENOTCONN);
16048348SEric.Yu@Sun.COM 	}
16058348SEric.Yu@Sun.COM 
16068348SEric.Yu@Sun.COM 	if (msg->msg_flags & MSG_PEEK)
16078348SEric.Yu@Sun.COM 		msg->msg_flags &= ~MSG_WAITALL;
16088348SEric.Yu@Sun.COM 
16098348SEric.Yu@Sun.COM 	if (so->so_mode & SM_ATOMIC)
16108348SEric.Yu@Sun.COM 		msg->msg_flags |= MSG_TRUNC;
16118348SEric.Yu@Sun.COM 
16128348SEric.Yu@Sun.COM 	if (msg->msg_flags & MSG_OOB) {
16138348SEric.Yu@Sun.COM 		if ((so->so_mode & SM_EXDATA) == 0) {
16148348SEric.Yu@Sun.COM 			error = EOPNOTSUPP;
16158348SEric.Yu@Sun.COM 		} else if (so->so_downcalls->sd_recv_uio != NULL) {
16168348SEric.Yu@Sun.COM 			error = (*so->so_downcalls->sd_recv_uio)
16178348SEric.Yu@Sun.COM 			    (so->so_proto_handle, uiop, msg, cr);
16188348SEric.Yu@Sun.COM 		} else {
16198348SEric.Yu@Sun.COM 			error = sorecvoob(so, msg, uiop, msg->msg_flags,
16208348SEric.Yu@Sun.COM 			    IS_SO_OOB_INLINE(so));
16218348SEric.Yu@Sun.COM 		}
16228348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
16238348SEric.Yu@Sun.COM 		return (error);
16248348SEric.Yu@Sun.COM 	}
16258348SEric.Yu@Sun.COM 
16268348SEric.Yu@Sun.COM 	/*
16278348SEric.Yu@Sun.COM 	 * If the protocol has the recv down call, then pass the request
16288348SEric.Yu@Sun.COM 	 * down.
16298348SEric.Yu@Sun.COM 	 */
16308348SEric.Yu@Sun.COM 	if (so->so_downcalls->sd_recv_uio != NULL) {
16318348SEric.Yu@Sun.COM 		error = (*so->so_downcalls->sd_recv_uio)
16328348SEric.Yu@Sun.COM 		    (so->so_proto_handle, uiop, msg, cr);
16338348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
16348348SEric.Yu@Sun.COM 		return (error);
16358348SEric.Yu@Sun.COM 	}
16368348SEric.Yu@Sun.COM 
16378348SEric.Yu@Sun.COM 	/*
16388348SEric.Yu@Sun.COM 	 * Reading data from the socket buffer
16398348SEric.Yu@Sun.COM 	 */
16408348SEric.Yu@Sun.COM 	flags = msg->msg_flags;
16418348SEric.Yu@Sun.COM 	msg->msg_flags = 0;
16428348SEric.Yu@Sun.COM 
16438348SEric.Yu@Sun.COM 	/*
16448348SEric.Yu@Sun.COM 	 * Set msg_controllen and msg_namelen to zero here to make it
16458348SEric.Yu@Sun.COM 	 * simpler in the cases that no control or name is returned.
16468348SEric.Yu@Sun.COM 	 */
16478348SEric.Yu@Sun.COM 	controllen = msg->msg_controllen;
16488348SEric.Yu@Sun.COM 	namelen = msg->msg_namelen;
16498348SEric.Yu@Sun.COM 	msg->msg_controllen = 0;
16508348SEric.Yu@Sun.COM 	msg->msg_namelen = 0;
16518348SEric.Yu@Sun.COM 
16528348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
16538348SEric.Yu@Sun.COM 	/* Set SOREADLOCKED */
16548348SEric.Yu@Sun.COM 	error = so_lock_read_intr(so,
16558348SEric.Yu@Sun.COM 	    uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
16568348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
16578348SEric.Yu@Sun.COM 	if (error) {
16588348SEric.Yu@Sun.COM 		SO_UNBLOCK_FALLBACK(so);
16598348SEric.Yu@Sun.COM 		return (error);
16608348SEric.Yu@Sun.COM 	}
16618348SEric.Yu@Sun.COM 
16628348SEric.Yu@Sun.COM 	suiop = sod_rcv_init(so, flags, &uiop);
16638348SEric.Yu@Sun.COM retry:
16648348SEric.Yu@Sun.COM 	saved_resid = uiop->uio_resid;
16658348SEric.Yu@Sun.COM 	error = so_dequeue_msg(so, &mctlp, uiop, &rval, flags);
16668348SEric.Yu@Sun.COM 	if (error != 0) {
16678348SEric.Yu@Sun.COM 		goto out;
16688348SEric.Yu@Sun.COM 	}
16698348SEric.Yu@Sun.COM 	/*
16708348SEric.Yu@Sun.COM 	 * For datagrams the MOREDATA flag is used to set MSG_TRUNC.
16718348SEric.Yu@Sun.COM 	 * For non-datagrams MOREDATA is used to set MSG_EOR.
16728348SEric.Yu@Sun.COM 	 */
16738348SEric.Yu@Sun.COM 	ASSERT(!(rval.r_val1 & MORECTL));
16748348SEric.Yu@Sun.COM 	if ((rval.r_val1 & MOREDATA) && (so->so_mode & SM_ATOMIC))
16758348SEric.Yu@Sun.COM 		msg->msg_flags |= MSG_TRUNC;
16768348SEric.Yu@Sun.COM 	if (mctlp == NULL) {
16778348SEric.Yu@Sun.COM 		dprintso(so, 1, ("so_recvmsg: got M_DATA\n"));
16788348SEric.Yu@Sun.COM 
16798348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
16808348SEric.Yu@Sun.COM 		/* Set MSG_EOR based on MOREDATA */
16818348SEric.Yu@Sun.COM 		if (!(rval.r_val1 & MOREDATA)) {
16828348SEric.Yu@Sun.COM 			if (so->so_state & SS_SAVEDEOR) {
16838348SEric.Yu@Sun.COM 				msg->msg_flags |= MSG_EOR;
16848348SEric.Yu@Sun.COM 				so->so_state &= ~SS_SAVEDEOR;
16858348SEric.Yu@Sun.COM 			}
16868348SEric.Yu@Sun.COM 		}
16878348SEric.Yu@Sun.COM 		/*
16888348SEric.Yu@Sun.COM 		 * If some data was received (i.e. not EOF) and the
16898348SEric.Yu@Sun.COM 		 * read/recv* has not been satisfied wait for some more.
16908348SEric.Yu@Sun.COM 		 */
16918348SEric.Yu@Sun.COM 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
16928348SEric.Yu@Sun.COM 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
16938348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
16949752SAnders.Persson@Sun.COM 			flags |= MSG_NOMARK;
16958348SEric.Yu@Sun.COM 			goto retry;
16968348SEric.Yu@Sun.COM 		}
16978348SEric.Yu@Sun.COM 
16988348SEric.Yu@Sun.COM 		goto out_locked;
16998348SEric.Yu@Sun.COM 	}
17009752SAnders.Persson@Sun.COM 	/* so_queue_msg has already verified length and alignment */
17018348SEric.Yu@Sun.COM 	tpr = (union T_primitives *)mctlp->b_rptr;
17028348SEric.Yu@Sun.COM 	dprintso(so, 1, ("so_recvmsg: type %d\n", tpr->type));
17038348SEric.Yu@Sun.COM 	switch (tpr->type) {
17048348SEric.Yu@Sun.COM 	case T_DATA_IND: {
17058348SEric.Yu@Sun.COM 		/*
17068348SEric.Yu@Sun.COM 		 * Set msg_flags to MSG_EOR based on
17078348SEric.Yu@Sun.COM 		 * MORE_flag and MOREDATA.
17088348SEric.Yu@Sun.COM 		 */
17098348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
17108348SEric.Yu@Sun.COM 		so->so_state &= ~SS_SAVEDEOR;
17118348SEric.Yu@Sun.COM 		if (!(tpr->data_ind.MORE_flag & 1)) {
17128348SEric.Yu@Sun.COM 			if (!(rval.r_val1 & MOREDATA))
17138348SEric.Yu@Sun.COM 				msg->msg_flags |= MSG_EOR;
17148348SEric.Yu@Sun.COM 			else
17158348SEric.Yu@Sun.COM 				so->so_state |= SS_SAVEDEOR;
17168348SEric.Yu@Sun.COM 		}
17178348SEric.Yu@Sun.COM 		freemsg(mctlp);
17188348SEric.Yu@Sun.COM 		/*
17198348SEric.Yu@Sun.COM 		 * If some data was received (i.e. not EOF) and the
17208348SEric.Yu@Sun.COM 		 * read/recv* has not been satisfied wait for some more.
17218348SEric.Yu@Sun.COM 		 */
17228348SEric.Yu@Sun.COM 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
17238348SEric.Yu@Sun.COM 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
17248348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
17259752SAnders.Persson@Sun.COM 			flags |= MSG_NOMARK;
17268348SEric.Yu@Sun.COM 			goto retry;
17278348SEric.Yu@Sun.COM 		}
17288348SEric.Yu@Sun.COM 		goto out_locked;
17298348SEric.Yu@Sun.COM 	}
17308348SEric.Yu@Sun.COM 	case T_UNITDATA_IND: {
17318348SEric.Yu@Sun.COM 		void *addr;
17328348SEric.Yu@Sun.COM 		t_uscalar_t addrlen;
17338348SEric.Yu@Sun.COM 		void *abuf;
17348348SEric.Yu@Sun.COM 		t_uscalar_t optlen;
17358348SEric.Yu@Sun.COM 		void *opt;
17368348SEric.Yu@Sun.COM 
17378348SEric.Yu@Sun.COM 		if (namelen != 0) {
17388348SEric.Yu@Sun.COM 			/* Caller wants source address */
17398348SEric.Yu@Sun.COM 			addrlen = tpr->unitdata_ind.SRC_length;
17408348SEric.Yu@Sun.COM 			addr = sogetoff(mctlp, tpr->unitdata_ind.SRC_offset,
17418348SEric.Yu@Sun.COM 			    addrlen, 1);
17428348SEric.Yu@Sun.COM 			if (addr == NULL) {
17438348SEric.Yu@Sun.COM 				freemsg(mctlp);
17448348SEric.Yu@Sun.COM 				error = EPROTO;
17458348SEric.Yu@Sun.COM 				eprintsoline(so, error);
17468348SEric.Yu@Sun.COM 				goto out;
17478348SEric.Yu@Sun.COM 			}
17488348SEric.Yu@Sun.COM 			ASSERT(so->so_family != AF_UNIX);
17498348SEric.Yu@Sun.COM 		}
17508348SEric.Yu@Sun.COM 		optlen = tpr->unitdata_ind.OPT_length;
17518348SEric.Yu@Sun.COM 		if (optlen != 0) {
17528348SEric.Yu@Sun.COM 			t_uscalar_t ncontrollen;
17538348SEric.Yu@Sun.COM 
17548348SEric.Yu@Sun.COM 			/*
17558348SEric.Yu@Sun.COM 			 * Extract any source address option.
17568348SEric.Yu@Sun.COM 			 * Determine how large cmsg buffer is needed.
17578348SEric.Yu@Sun.COM 			 */
17588348SEric.Yu@Sun.COM 			opt = sogetoff(mctlp, tpr->unitdata_ind.OPT_offset,
17598348SEric.Yu@Sun.COM 			    optlen, __TPI_ALIGN_SIZE);
17608348SEric.Yu@Sun.COM 
17618348SEric.Yu@Sun.COM 			if (opt == NULL) {
17628348SEric.Yu@Sun.COM 				freemsg(mctlp);
17638348SEric.Yu@Sun.COM 				error = EPROTO;
17648348SEric.Yu@Sun.COM 				eprintsoline(so, error);
17658348SEric.Yu@Sun.COM 				goto out;
17668348SEric.Yu@Sun.COM 			}
17678348SEric.Yu@Sun.COM 			if (so->so_family == AF_UNIX)
17688348SEric.Yu@Sun.COM 				so_getopt_srcaddr(opt, optlen, &addr, &addrlen);
17698348SEric.Yu@Sun.COM 			ncontrollen = so_cmsglen(mctlp, opt, optlen,
17708348SEric.Yu@Sun.COM 			    !(flags & MSG_XPG4_2));
17718348SEric.Yu@Sun.COM 			if (controllen != 0)
17728348SEric.Yu@Sun.COM 				controllen = ncontrollen;
17738348SEric.Yu@Sun.COM 			else if (ncontrollen != 0)
17748348SEric.Yu@Sun.COM 				msg->msg_flags |= MSG_CTRUNC;
17758348SEric.Yu@Sun.COM 		} else {
17768348SEric.Yu@Sun.COM 			controllen = 0;
17778348SEric.Yu@Sun.COM 		}
17788348SEric.Yu@Sun.COM 
17798348SEric.Yu@Sun.COM 		if (namelen != 0) {
17808348SEric.Yu@Sun.COM 			/*
17818348SEric.Yu@Sun.COM 			 * Return address to caller.
17828348SEric.Yu@Sun.COM 			 * Caller handles truncation if length
17838348SEric.Yu@Sun.COM 			 * exceeds msg_namelen.
17848348SEric.Yu@Sun.COM 			 * NOTE: AF_UNIX NUL termination is ensured by
17858348SEric.Yu@Sun.COM 			 * the sender's copyin_name().
17868348SEric.Yu@Sun.COM 			 */
17878348SEric.Yu@Sun.COM 			abuf = kmem_alloc(addrlen, KM_SLEEP);
17888348SEric.Yu@Sun.COM 
17898348SEric.Yu@Sun.COM 			bcopy(addr, abuf, addrlen);
17908348SEric.Yu@Sun.COM 			msg->msg_name = abuf;
17918348SEric.Yu@Sun.COM 			msg->msg_namelen = addrlen;
17928348SEric.Yu@Sun.COM 		}
17938348SEric.Yu@Sun.COM 
17948348SEric.Yu@Sun.COM 		if (controllen != 0) {
17958348SEric.Yu@Sun.COM 			/*
17968348SEric.Yu@Sun.COM 			 * Return control msg to caller.
17978348SEric.Yu@Sun.COM 			 * Caller handles truncation if length
17988348SEric.Yu@Sun.COM 			 * exceeds msg_controllen.
17998348SEric.Yu@Sun.COM 			 */
18008348SEric.Yu@Sun.COM 			control = kmem_zalloc(controllen, KM_SLEEP);
18018348SEric.Yu@Sun.COM 
18028348SEric.Yu@Sun.COM 			error = so_opt2cmsg(mctlp, opt, optlen,
18038348SEric.Yu@Sun.COM 			    !(flags & MSG_XPG4_2), control, controllen);
18048348SEric.Yu@Sun.COM 			if (error) {
18058348SEric.Yu@Sun.COM 				freemsg(mctlp);
18068348SEric.Yu@Sun.COM 				if (msg->msg_namelen != 0)
18078348SEric.Yu@Sun.COM 					kmem_free(msg->msg_name,
18088348SEric.Yu@Sun.COM 					    msg->msg_namelen);
18098348SEric.Yu@Sun.COM 				kmem_free(control, controllen);
18108348SEric.Yu@Sun.COM 				eprintsoline(so, error);
18118348SEric.Yu@Sun.COM 				goto out;
18128348SEric.Yu@Sun.COM 			}
18138348SEric.Yu@Sun.COM 			msg->msg_control = control;
18148348SEric.Yu@Sun.COM 			msg->msg_controllen = controllen;
18158348SEric.Yu@Sun.COM 		}
18168348SEric.Yu@Sun.COM 
18178348SEric.Yu@Sun.COM 		freemsg(mctlp);
18188348SEric.Yu@Sun.COM 		goto out;
18198348SEric.Yu@Sun.COM 	}
18208348SEric.Yu@Sun.COM 	case T_OPTDATA_IND: {
18218348SEric.Yu@Sun.COM 		struct T_optdata_req *tdr;
18228348SEric.Yu@Sun.COM 		void *opt;
18238348SEric.Yu@Sun.COM 		t_uscalar_t optlen;
18248348SEric.Yu@Sun.COM 
18258348SEric.Yu@Sun.COM 		tdr = (struct T_optdata_req *)mctlp->b_rptr;
18268348SEric.Yu@Sun.COM 		optlen = tdr->OPT_length;
18278348SEric.Yu@Sun.COM 		if (optlen != 0) {
18288348SEric.Yu@Sun.COM 			t_uscalar_t ncontrollen;
18298348SEric.Yu@Sun.COM 			/*
18308348SEric.Yu@Sun.COM 			 * Determine how large cmsg buffer is needed.
18318348SEric.Yu@Sun.COM 			 */
18328348SEric.Yu@Sun.COM 			opt = sogetoff(mctlp,
18338348SEric.Yu@Sun.COM 			    tpr->optdata_ind.OPT_offset, optlen,
18348348SEric.Yu@Sun.COM 			    __TPI_ALIGN_SIZE);
18358348SEric.Yu@Sun.COM 
18368348SEric.Yu@Sun.COM 			if (opt == NULL) {
18378348SEric.Yu@Sun.COM 				freemsg(mctlp);
18388348SEric.Yu@Sun.COM 				error = EPROTO;
18398348SEric.Yu@Sun.COM 				eprintsoline(so, error);
18408348SEric.Yu@Sun.COM 				goto out;
18418348SEric.Yu@Sun.COM 			}
18428348SEric.Yu@Sun.COM 
18438348SEric.Yu@Sun.COM 			ncontrollen = so_cmsglen(mctlp, opt, optlen,
18448348SEric.Yu@Sun.COM 			    !(flags & MSG_XPG4_2));
18458348SEric.Yu@Sun.COM 			if (controllen != 0)
18468348SEric.Yu@Sun.COM 				controllen = ncontrollen;
18478348SEric.Yu@Sun.COM 			else if (ncontrollen != 0)
18488348SEric.Yu@Sun.COM 				msg->msg_flags |= MSG_CTRUNC;
18498348SEric.Yu@Sun.COM 		} else {
18508348SEric.Yu@Sun.COM 			controllen = 0;
18518348SEric.Yu@Sun.COM 		}
18528348SEric.Yu@Sun.COM 
18538348SEric.Yu@Sun.COM 		if (controllen != 0) {
18548348SEric.Yu@Sun.COM 			/*
18558348SEric.Yu@Sun.COM 			 * Return control msg to caller.
18568348SEric.Yu@Sun.COM 			 * Caller handles truncation if length
18578348SEric.Yu@Sun.COM 			 * exceeds msg_controllen.
18588348SEric.Yu@Sun.COM 			 */
18598348SEric.Yu@Sun.COM 			control = kmem_zalloc(controllen, KM_SLEEP);
18608348SEric.Yu@Sun.COM 
18618348SEric.Yu@Sun.COM 			error = so_opt2cmsg(mctlp, opt, optlen,
18628348SEric.Yu@Sun.COM 			    !(flags & MSG_XPG4_2), control, controllen);
18638348SEric.Yu@Sun.COM 			if (error) {
18648348SEric.Yu@Sun.COM 				freemsg(mctlp);
18658348SEric.Yu@Sun.COM 				kmem_free(control, controllen);
18668348SEric.Yu@Sun.COM 				eprintsoline(so, error);
18678348SEric.Yu@Sun.COM 				goto out;
18688348SEric.Yu@Sun.COM 			}
18698348SEric.Yu@Sun.COM 			msg->msg_control = control;
18708348SEric.Yu@Sun.COM 			msg->msg_controllen = controllen;
18718348SEric.Yu@Sun.COM 		}
18728348SEric.Yu@Sun.COM 
18738348SEric.Yu@Sun.COM 		/*
18748348SEric.Yu@Sun.COM 		 * Set msg_flags to MSG_EOR based on
18758348SEric.Yu@Sun.COM 		 * DATA_flag and MOREDATA.
18768348SEric.Yu@Sun.COM 		 */
18778348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
18788348SEric.Yu@Sun.COM 		so->so_state &= ~SS_SAVEDEOR;
18798348SEric.Yu@Sun.COM 		if (!(tpr->data_ind.MORE_flag & 1)) {
18808348SEric.Yu@Sun.COM 			if (!(rval.r_val1 & MOREDATA))
18818348SEric.Yu@Sun.COM 				msg->msg_flags |= MSG_EOR;
18828348SEric.Yu@Sun.COM 			else
18838348SEric.Yu@Sun.COM 				so->so_state |= SS_SAVEDEOR;
18848348SEric.Yu@Sun.COM 		}
18858348SEric.Yu@Sun.COM 		freemsg(mctlp);
18868348SEric.Yu@Sun.COM 		/*
18878348SEric.Yu@Sun.COM 		 * If some data was received (i.e. not EOF) and the
18888348SEric.Yu@Sun.COM 		 * read/recv* has not been satisfied wait for some more.
18898348SEric.Yu@Sun.COM 		 * Not possible to wait if control info was received.
18908348SEric.Yu@Sun.COM 		 */
18918348SEric.Yu@Sun.COM 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
18928348SEric.Yu@Sun.COM 		    controllen == 0 &&
18938348SEric.Yu@Sun.COM 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
18948348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
18959752SAnders.Persson@Sun.COM 			flags |= MSG_NOMARK;
18968348SEric.Yu@Sun.COM 			goto retry;
18978348SEric.Yu@Sun.COM 		}
18988348SEric.Yu@Sun.COM 		goto out_locked;
18998348SEric.Yu@Sun.COM 	}
19008348SEric.Yu@Sun.COM 	default:
19018348SEric.Yu@Sun.COM 		cmn_err(CE_CONT, "so_recvmsg bad type %x \n",
19028348SEric.Yu@Sun.COM 		    tpr->type);
19038348SEric.Yu@Sun.COM 		freemsg(mctlp);
19048348SEric.Yu@Sun.COM 		error = EPROTO;
19058348SEric.Yu@Sun.COM 		ASSERT(0);
19068348SEric.Yu@Sun.COM 	}
19078348SEric.Yu@Sun.COM out:
19088348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
19098348SEric.Yu@Sun.COM out_locked:
19108348SEric.Yu@Sun.COM 	ret = sod_rcv_done(so, suiop, uiop);
19118348SEric.Yu@Sun.COM 	if (ret != 0 && error == 0)
19128348SEric.Yu@Sun.COM 		error = ret;
19138348SEric.Yu@Sun.COM 
19148348SEric.Yu@Sun.COM 	so_unlock_read(so);	/* Clear SOREADLOCKED */
19158348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
19168348SEric.Yu@Sun.COM 
19178348SEric.Yu@Sun.COM 	SO_UNBLOCK_FALLBACK(so);
19188348SEric.Yu@Sun.COM 
19198348SEric.Yu@Sun.COM 	return (error);
19208348SEric.Yu@Sun.COM }
19218348SEric.Yu@Sun.COM 
19228348SEric.Yu@Sun.COM sonodeops_t so_sonodeops = {
19238348SEric.Yu@Sun.COM 	so_init,		/* sop_init	*/
19248348SEric.Yu@Sun.COM 	so_accept,		/* sop_accept   */
19258348SEric.Yu@Sun.COM 	so_bind,		/* sop_bind	*/
19268348SEric.Yu@Sun.COM 	so_listen,		/* sop_listen   */
19278348SEric.Yu@Sun.COM 	so_connect,		/* sop_connect  */
19288348SEric.Yu@Sun.COM 	so_recvmsg,		/* sop_recvmsg  */
19298348SEric.Yu@Sun.COM 	so_sendmsg,		/* sop_sendmsg  */
19308348SEric.Yu@Sun.COM 	so_sendmblk,		/* sop_sendmblk */
19318348SEric.Yu@Sun.COM 	so_getpeername,		/* sop_getpeername */
19328348SEric.Yu@Sun.COM 	so_getsockname,		/* sop_getsockname */
19338348SEric.Yu@Sun.COM 	so_shutdown,		/* sop_shutdown */
19348348SEric.Yu@Sun.COM 	so_getsockopt,		/* sop_getsockopt */
19358348SEric.Yu@Sun.COM 	so_setsockopt,		/* sop_setsockopt */
19368348SEric.Yu@Sun.COM 	so_ioctl,		/* sop_ioctl    */
19378348SEric.Yu@Sun.COM 	so_poll,		/* sop_poll	*/
19388348SEric.Yu@Sun.COM 	so_close,		/* sop_close */
19398348SEric.Yu@Sun.COM };
19408348SEric.Yu@Sun.COM 
19418348SEric.Yu@Sun.COM sock_upcalls_t so_upcalls = {
19428348SEric.Yu@Sun.COM 	so_newconn,
19438348SEric.Yu@Sun.COM 	so_connected,
19448348SEric.Yu@Sun.COM 	so_disconnected,
19458348SEric.Yu@Sun.COM 	so_opctl,
19468348SEric.Yu@Sun.COM 	so_queue_msg,
19478348SEric.Yu@Sun.COM 	so_set_prop,
19488348SEric.Yu@Sun.COM 	so_txq_full,
19498348SEric.Yu@Sun.COM 	so_signal_oob,
19508348SEric.Yu@Sun.COM 	so_zcopy_notify,
1951*12643SAnders.Persson@Sun.COM 	so_set_error,
1952*12643SAnders.Persson@Sun.COM 	so_closed
19538348SEric.Yu@Sun.COM };
1954