xref: /titanic_44/usr/src/uts/common/fs/sockfs/sockcommon_sops.c (revision 68846fd00135fb0b10944e7806025cbefcfd6546)
10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning  * CDDL HEADER START
30f1702c5SYu Xiangning  *
40f1702c5SYu Xiangning  * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning  * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning  * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning  *
80f1702c5SYu Xiangning  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning  * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning  * See the License for the specific language governing permissions
110f1702c5SYu Xiangning  * and limitations under the License.
120f1702c5SYu Xiangning  *
130f1702c5SYu Xiangning  * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning  * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning  * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning  * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning  *
190f1702c5SYu Xiangning  * CDDL HEADER END
200f1702c5SYu Xiangning  */
210f1702c5SYu Xiangning 
220f1702c5SYu Xiangning /*
23c0dd49bdSEiji Ota  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
240f1702c5SYu Xiangning  */
250f1702c5SYu Xiangning 
26*68846fd0SBryan Cantrill /*
27*68846fd0SBryan Cantrill  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
28*68846fd0SBryan Cantrill  */
29*68846fd0SBryan Cantrill 
300f1702c5SYu Xiangning #include <sys/types.h>
310f1702c5SYu Xiangning #include <sys/param.h>
320f1702c5SYu Xiangning #include <sys/systm.h>
330f1702c5SYu Xiangning #include <sys/sysmacros.h>
340f1702c5SYu Xiangning #include <sys/debug.h>
350f1702c5SYu Xiangning #include <sys/cmn_err.h>
360f1702c5SYu Xiangning 
370f1702c5SYu Xiangning #include <sys/stropts.h>
380f1702c5SYu Xiangning #include <sys/socket.h>
390f1702c5SYu Xiangning #include <sys/socketvar.h>
400f1702c5SYu Xiangning 
410f1702c5SYu Xiangning #define	_SUN_TPI_VERSION	2
420f1702c5SYu Xiangning #include <sys/tihdr.h>
430f1702c5SYu Xiangning #include <sys/sockio.h>
440f1702c5SYu Xiangning #include <sys/kmem_impl.h>
450f1702c5SYu Xiangning 
460f1702c5SYu Xiangning #include <sys/strsubr.h>
470f1702c5SYu Xiangning #include <sys/strsun.h>
480f1702c5SYu Xiangning #include <sys/ddi.h>
490f1702c5SYu Xiangning #include <netinet/in.h>
500f1702c5SYu Xiangning #include <inet/ip.h>
510f1702c5SYu Xiangning 
520f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
533e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h>
540f1702c5SYu Xiangning 
550f1702c5SYu Xiangning #include <sys/socket_proto.h>
560f1702c5SYu Xiangning 
570f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h>
58bbc000e5SAnders Persson #include <fs/sockfs/sodirect.h>
590f1702c5SYu Xiangning #include <sys/tihdr.h>
600f1702c5SYu Xiangning #include <fs/sockfs/nl7c.h>
610f1702c5SYu Xiangning 
620f1702c5SYu Xiangning extern int xnet_skip_checks;
630f1702c5SYu Xiangning extern int xnet_check_print;
640f1702c5SYu Xiangning 
653e95bd4aSAnders Persson static void so_queue_oob(struct sonode *, mblk_t *, size_t);
660f1702c5SYu Xiangning 
670f1702c5SYu Xiangning 
680f1702c5SYu Xiangning /*ARGSUSED*/
690f1702c5SYu Xiangning int
so_accept_notsupp(struct sonode * lso,int fflag,struct cred * cr,struct sonode ** nsop)700f1702c5SYu Xiangning so_accept_notsupp(struct sonode *lso, int fflag,
710f1702c5SYu Xiangning     struct cred *cr, struct sonode **nsop)
720f1702c5SYu Xiangning {
730f1702c5SYu Xiangning 	return (EOPNOTSUPP);
740f1702c5SYu Xiangning }
750f1702c5SYu Xiangning 
760f1702c5SYu Xiangning /*ARGSUSED*/
770f1702c5SYu Xiangning int
so_listen_notsupp(struct sonode * so,int backlog,struct cred * cr)780f1702c5SYu Xiangning so_listen_notsupp(struct sonode *so, int backlog, struct cred *cr)
790f1702c5SYu Xiangning {
800f1702c5SYu Xiangning 	return (EOPNOTSUPP);
810f1702c5SYu Xiangning }
820f1702c5SYu Xiangning 
830f1702c5SYu Xiangning /*ARGSUSED*/
840f1702c5SYu Xiangning int
so_getsockname_notsupp(struct sonode * so,struct sockaddr * sa,socklen_t * len,struct cred * cr)850f1702c5SYu Xiangning so_getsockname_notsupp(struct sonode *so, struct sockaddr *sa,
860f1702c5SYu Xiangning     socklen_t *len, struct cred *cr)
870f1702c5SYu Xiangning {
880f1702c5SYu Xiangning 	return (EOPNOTSUPP);
890f1702c5SYu Xiangning }
900f1702c5SYu Xiangning 
910f1702c5SYu Xiangning /*ARGSUSED*/
920f1702c5SYu Xiangning int
so_getpeername_notsupp(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,boolean_t accept,struct cred * cr)930f1702c5SYu Xiangning so_getpeername_notsupp(struct sonode *so, struct sockaddr *addr,
940f1702c5SYu Xiangning     socklen_t *addrlen, boolean_t accept, struct cred *cr)
950f1702c5SYu Xiangning {
960f1702c5SYu Xiangning 	return (EOPNOTSUPP);
970f1702c5SYu Xiangning }
980f1702c5SYu Xiangning 
990f1702c5SYu Xiangning /*ARGSUSED*/
1000f1702c5SYu Xiangning int
so_shutdown_notsupp(struct sonode * so,int how,struct cred * cr)1010f1702c5SYu Xiangning so_shutdown_notsupp(struct sonode *so, int how, struct cred *cr)
1020f1702c5SYu Xiangning {
1030f1702c5SYu Xiangning 	return (EOPNOTSUPP);
1040f1702c5SYu Xiangning }
1050f1702c5SYu Xiangning 
1060f1702c5SYu Xiangning /*ARGSUSED*/
1070f1702c5SYu Xiangning int
so_sendmblk_notsupp(struct sonode * so,struct msghdr * msg,int fflag,struct cred * cr,mblk_t ** mpp)1080f1702c5SYu Xiangning so_sendmblk_notsupp(struct sonode *so, struct msghdr *msg, int fflag,
1090f1702c5SYu Xiangning     struct cred *cr, mblk_t **mpp)
1100f1702c5SYu Xiangning {
1110f1702c5SYu Xiangning 	return (EOPNOTSUPP);
1120f1702c5SYu Xiangning }
1130f1702c5SYu Xiangning 
1140f1702c5SYu Xiangning /*
1150f1702c5SYu Xiangning  * Generic Socket Ops
1160f1702c5SYu Xiangning  */
1170f1702c5SYu Xiangning 
1180f1702c5SYu Xiangning /* ARGSUSED */
1190f1702c5SYu Xiangning int
so_init(struct sonode * so,struct sonode * pso,struct cred * cr,int flags)1200f1702c5SYu Xiangning so_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1210f1702c5SYu Xiangning {
1220f1702c5SYu Xiangning 	return (socket_init_common(so, pso, flags, cr));
1230f1702c5SYu Xiangning }
1240f1702c5SYu Xiangning 
1250f1702c5SYu Xiangning int
so_bind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int flags,struct cred * cr)1260f1702c5SYu Xiangning so_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
1270f1702c5SYu Xiangning     int flags, struct cred *cr)
1280f1702c5SYu Xiangning {
1290f1702c5SYu Xiangning 	int error;
1300f1702c5SYu Xiangning 
1310f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_BIND(so, name, namelen, flags, cr));
1320f1702c5SYu Xiangning 
1330f1702c5SYu Xiangning 	ASSERT(flags == _SOBIND_XPG4_2 || flags == _SOBIND_SOCKBSD);
1340f1702c5SYu Xiangning 
1350f1702c5SYu Xiangning 	/* X/Open requires this check */
1360f1702c5SYu Xiangning 	if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) {
1370f1702c5SYu Xiangning 		if (xnet_check_print) {
1380f1702c5SYu Xiangning 			printf("sockfs: X/Open bind state check "
1390f1702c5SYu Xiangning 			    "caused EINVAL\n");
1400f1702c5SYu Xiangning 		}
1410f1702c5SYu Xiangning 		error = EINVAL;
1420f1702c5SYu Xiangning 		goto done;
1430f1702c5SYu Xiangning 	}
1440f1702c5SYu Xiangning 
1450f1702c5SYu Xiangning 	/*
1460f1702c5SYu Xiangning 	 * a bind to a NULL address is interpreted as unbind. So just
1470f1702c5SYu Xiangning 	 * do the downcall.
1480f1702c5SYu Xiangning 	 */
1490f1702c5SYu Xiangning 	if (name == NULL)
1500f1702c5SYu Xiangning 		goto dobind;
1510f1702c5SYu Xiangning 
1520f1702c5SYu Xiangning 	switch (so->so_family) {
1530f1702c5SYu Xiangning 	case AF_INET:
1540f1702c5SYu Xiangning 		if ((size_t)namelen != sizeof (sin_t)) {
1550f1702c5SYu Xiangning 			error = name->sa_family != so->so_family ?
1560f1702c5SYu Xiangning 			    EAFNOSUPPORT : EINVAL;
1570f1702c5SYu Xiangning 			eprintsoline(so, error);
1580f1702c5SYu Xiangning 			goto done;
1590f1702c5SYu Xiangning 		}
1600f1702c5SYu Xiangning 
1610f1702c5SYu Xiangning 		if ((flags & _SOBIND_XPG4_2) &&
1620f1702c5SYu Xiangning 		    (name->sa_family != so->so_family)) {
1630f1702c5SYu Xiangning 			/*
1640f1702c5SYu Xiangning 			 * This check has to be made for X/Open
1650f1702c5SYu Xiangning 			 * sockets however application failures have
1660f1702c5SYu Xiangning 			 * been observed when it is applied to
1670f1702c5SYu Xiangning 			 * all sockets.
1680f1702c5SYu Xiangning 			 */
1690f1702c5SYu Xiangning 			error = EAFNOSUPPORT;
1700f1702c5SYu Xiangning 			eprintsoline(so, error);
1710f1702c5SYu Xiangning 			goto done;
1720f1702c5SYu Xiangning 		}
1730f1702c5SYu Xiangning 		/*
1740f1702c5SYu Xiangning 		 * Force a zero sa_family to match so_family.
1750f1702c5SYu Xiangning 		 *
1760f1702c5SYu Xiangning 		 * Some programs like inetd(1M) don't set the
1770f1702c5SYu Xiangning 		 * family field. Other programs leave
1780f1702c5SYu Xiangning 		 * sin_family set to garbage - SunOS 4.X does
1790f1702c5SYu Xiangning 		 * not check the family field on a bind.
1800f1702c5SYu Xiangning 		 * We use the family field that
1810f1702c5SYu Xiangning 		 * was passed in to the socket() call.
1820f1702c5SYu Xiangning 		 */
1830f1702c5SYu Xiangning 		name->sa_family = so->so_family;
1840f1702c5SYu Xiangning 		break;
1850f1702c5SYu Xiangning 
1860f1702c5SYu Xiangning 	case AF_INET6: {
1870f1702c5SYu Xiangning #ifdef DEBUG
1880f1702c5SYu Xiangning 		sin6_t *sin6 = (sin6_t *)name;
1890f1702c5SYu Xiangning #endif
1900f1702c5SYu Xiangning 		if ((size_t)namelen != sizeof (sin6_t)) {
1910f1702c5SYu Xiangning 			error = name->sa_family != so->so_family ?
1920f1702c5SYu Xiangning 			    EAFNOSUPPORT : EINVAL;
1930f1702c5SYu Xiangning 			eprintsoline(so, error);
1940f1702c5SYu Xiangning 			goto done;
1950f1702c5SYu Xiangning 		}
1960f1702c5SYu Xiangning 
1970f1702c5SYu Xiangning 		if (name->sa_family != so->so_family) {
1980f1702c5SYu Xiangning 			/*
1990f1702c5SYu Xiangning 			 * With IPv6 we require the family to match
2000f1702c5SYu Xiangning 			 * unlike in IPv4.
2010f1702c5SYu Xiangning 			 */
2020f1702c5SYu Xiangning 			error = EAFNOSUPPORT;
2030f1702c5SYu Xiangning 			eprintsoline(so, error);
2040f1702c5SYu Xiangning 			goto done;
2050f1702c5SYu Xiangning 		}
2060f1702c5SYu Xiangning #ifdef DEBUG
2070f1702c5SYu Xiangning 		/*
2080f1702c5SYu Xiangning 		 * Verify that apps don't forget to clear
2090f1702c5SYu Xiangning 		 * sin6_scope_id etc
2100f1702c5SYu Xiangning 		 */
2110f1702c5SYu Xiangning 		if (sin6->sin6_scope_id != 0 &&
2120f1702c5SYu Xiangning 		    !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
2130f1702c5SYu Xiangning 			zcmn_err(getzoneid(), CE_WARN,
2140f1702c5SYu Xiangning 			    "bind with uninitialized sin6_scope_id "
2150f1702c5SYu Xiangning 			    "(%d) on socket. Pid = %d\n",
2160f1702c5SYu Xiangning 			    (int)sin6->sin6_scope_id,
2170f1702c5SYu Xiangning 			    (int)curproc->p_pid);
2180f1702c5SYu Xiangning 		}
2190f1702c5SYu Xiangning 		if (sin6->__sin6_src_id != 0) {
2200f1702c5SYu Xiangning 			zcmn_err(getzoneid(), CE_WARN,
2210f1702c5SYu Xiangning 			    "bind with uninitialized __sin6_src_id "
2220f1702c5SYu Xiangning 			    "(%d) on socket. Pid = %d\n",
2230f1702c5SYu Xiangning 			    (int)sin6->__sin6_src_id,
2240f1702c5SYu Xiangning 			    (int)curproc->p_pid);
2250f1702c5SYu Xiangning 		}
2260f1702c5SYu Xiangning #endif /* DEBUG */
2270f1702c5SYu Xiangning 
2280f1702c5SYu Xiangning 		break;
2290f1702c5SYu Xiangning 	}
2300f1702c5SYu Xiangning 	default:
2310f1702c5SYu Xiangning 		/* Just pass the request to the protocol */
2320f1702c5SYu Xiangning 		goto dobind;
2330f1702c5SYu Xiangning 	}
2340f1702c5SYu Xiangning 
2350f1702c5SYu Xiangning 	/*
2360f1702c5SYu Xiangning 	 * First we check if either NCA or KSSL has been enabled for
2370f1702c5SYu Xiangning 	 * the requested address, and if so, we fall back to TPI.
2380f1702c5SYu Xiangning 	 * If neither of those two services are enabled, then we just
2390f1702c5SYu Xiangning 	 * pass the request to the protocol.
2400f1702c5SYu Xiangning 	 *
2410f1702c5SYu Xiangning 	 * Note that KSSL can only be enabled on a socket if NCA is NOT
2420f1702c5SYu Xiangning 	 * enabled for that socket, hence the else-statement below.
2430f1702c5SYu Xiangning 	 */
2440f1702c5SYu Xiangning 	if (nl7c_enabled && ((so->so_family == AF_INET ||
2450f1702c5SYu Xiangning 	    so->so_family == AF_INET6) &&
2460f1702c5SYu Xiangning 	    nl7c_lookup_addr(name, namelen) != NULL)) {
2470f1702c5SYu Xiangning 		/*
2480f1702c5SYu Xiangning 		 * NL7C is not supported in non-global zones,
2490f1702c5SYu Xiangning 		 * we enforce this restriction here.
2500f1702c5SYu Xiangning 		 */
2510f1702c5SYu Xiangning 		if (so->so_zoneid == GLOBAL_ZONEID) {
2520f1702c5SYu Xiangning 			/* NCA should be used, so fall back to TPI */
2530f1702c5SYu Xiangning 			error = so_tpi_fallback(so, cr);
2540f1702c5SYu Xiangning 			SO_UNBLOCK_FALLBACK(so);
2550f1702c5SYu Xiangning 			if (error)
2560f1702c5SYu Xiangning 				return (error);
2570f1702c5SYu Xiangning 			else
2580f1702c5SYu Xiangning 				return (SOP_BIND(so, name, namelen, flags, cr));
2590f1702c5SYu Xiangning 		}
2600f1702c5SYu Xiangning 	}
2610f1702c5SYu Xiangning 
2620f1702c5SYu Xiangning dobind:
2633e95bd4aSAnders Persson 	if (so->so_filter_active == 0 ||
2643e95bd4aSAnders Persson 	    (error = sof_filter_bind(so, name, &namelen, cr)) < 0) {
2650f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_bind)
2660f1702c5SYu Xiangning 		    (so->so_proto_handle, name, namelen, cr);
2673e95bd4aSAnders Persson 	}
2680f1702c5SYu Xiangning done:
2690f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
2700f1702c5SYu Xiangning 
2710f1702c5SYu Xiangning 	return (error);
2720f1702c5SYu Xiangning }
2730f1702c5SYu Xiangning 
2740f1702c5SYu Xiangning int
so_listen(struct sonode * so,int backlog,struct cred * cr)2750f1702c5SYu Xiangning so_listen(struct sonode *so, int backlog, struct cred *cr)
2760f1702c5SYu Xiangning {
2770f1702c5SYu Xiangning 	int	error = 0;
2780f1702c5SYu Xiangning 
2790f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2800f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_LISTEN(so, backlog, cr));
2810f1702c5SYu Xiangning 
2823e95bd4aSAnders Persson 	if ((so)->so_filter_active == 0 ||
2833e95bd4aSAnders Persson 	    (error = sof_filter_listen(so, &backlog, cr)) < 0)
2843e95bd4aSAnders Persson 		error = (*so->so_downcalls->sd_listen)(so->so_proto_handle,
2853e95bd4aSAnders Persson 		    backlog, cr);
2860f1702c5SYu Xiangning 
2870f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
2880f1702c5SYu Xiangning 
2890f1702c5SYu Xiangning 	return (error);
2900f1702c5SYu Xiangning }
2910f1702c5SYu Xiangning 
2920f1702c5SYu Xiangning 
2930f1702c5SYu Xiangning int
so_connect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags,struct cred * cr)2943e95bd4aSAnders Persson so_connect(struct sonode *so, struct sockaddr *name,
2950f1702c5SYu Xiangning     socklen_t namelen, int fflag, int flags, struct cred *cr)
2960f1702c5SYu Xiangning {
2970f1702c5SYu Xiangning 	int error = 0;
2980f1702c5SYu Xiangning 	sock_connid_t id;
2990f1702c5SYu Xiangning 
3000f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3010f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_CONNECT(so, name, namelen, fflag, flags, cr));
3020f1702c5SYu Xiangning 
3030f1702c5SYu Xiangning 	/*
3040f1702c5SYu Xiangning 	 * If there is a pending error, return error
3050f1702c5SYu Xiangning 	 * This can happen if a non blocking operation caused an error.
3060f1702c5SYu Xiangning 	 */
3070f1702c5SYu Xiangning 
3080f1702c5SYu Xiangning 	if (so->so_error != 0) {
3090f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
3100f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
3110f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3120f1702c5SYu Xiangning 		if (error != 0)
3130f1702c5SYu Xiangning 			goto done;
3140f1702c5SYu Xiangning 	}
3150f1702c5SYu Xiangning 
3163e95bd4aSAnders Persson 	if (so->so_filter_active == 0 ||
3173e95bd4aSAnders Persson 	    (error = sof_filter_connect(so, (struct sockaddr *)name,
3183e95bd4aSAnders Persson 	    &namelen, cr)) < 0) {
3190f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_connect)(so->so_proto_handle,
3200f1702c5SYu Xiangning 		    name, namelen, &id, cr);
3210f1702c5SYu Xiangning 
3220f1702c5SYu Xiangning 		if (error == EINPROGRESS)
3233e95bd4aSAnders Persson 			error = so_wait_connected(so,
3243e95bd4aSAnders Persson 			    fflag & (FNONBLOCK|FNDELAY), id);
3253e95bd4aSAnders Persson 	}
3260f1702c5SYu Xiangning done:
3270f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
3280f1702c5SYu Xiangning 	return (error);
3290f1702c5SYu Xiangning }
3300f1702c5SYu Xiangning 
3310f1702c5SYu Xiangning /*ARGSUSED*/
3320f1702c5SYu Xiangning int
so_accept(struct sonode * so,int fflag,struct cred * cr,struct sonode ** nsop)3330f1702c5SYu Xiangning so_accept(struct sonode *so, int fflag, struct cred *cr, struct sonode **nsop)
3340f1702c5SYu Xiangning {
3350f1702c5SYu Xiangning 	int error = 0;
3360f1702c5SYu Xiangning 	struct sonode *nso;
3370f1702c5SYu Xiangning 
3380f1702c5SYu Xiangning 	*nsop = NULL;
3390f1702c5SYu Xiangning 
3400f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_ACCEPT(so, fflag, cr, nsop));
3410f1702c5SYu Xiangning 	if ((so->so_state & SS_ACCEPTCONN) == 0) {
3420f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
3430f1702c5SYu Xiangning 		return ((so->so_type == SOCK_DGRAM || so->so_type == SOCK_RAW) ?
3440f1702c5SYu Xiangning 		    EOPNOTSUPP : EINVAL);
3450f1702c5SYu Xiangning 	}
3460f1702c5SYu Xiangning 
3470f1702c5SYu Xiangning 	if ((error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)),
3480f1702c5SYu Xiangning 	    &nso)) == 0) {
3490f1702c5SYu Xiangning 		ASSERT(nso != NULL);
3500f1702c5SYu Xiangning 
3510f1702c5SYu Xiangning 		/* finish the accept */
3523e95bd4aSAnders Persson 		if ((so->so_filter_active > 0 &&
3533e95bd4aSAnders Persson 		    (error = sof_filter_accept(nso, cr)) > 0) ||
3543e95bd4aSAnders Persson 		    (error = (*so->so_downcalls->sd_accept)(so->so_proto_handle,
3553e95bd4aSAnders Persson 		    nso->so_proto_handle, (sock_upper_handle_t)nso, cr)) != 0) {
3560f1702c5SYu Xiangning 			(void) socket_close(nso, 0, cr);
3570f1702c5SYu Xiangning 			socket_destroy(nso);
3580f1702c5SYu Xiangning 		} else {
3590f1702c5SYu Xiangning 			*nsop = nso;
3600f1702c5SYu Xiangning 		}
3610f1702c5SYu Xiangning 	}
3620f1702c5SYu Xiangning 
3630f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
3640f1702c5SYu Xiangning 	return (error);
3650f1702c5SYu Xiangning }
3660f1702c5SYu Xiangning 
3670f1702c5SYu Xiangning int
so_sendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)3680f1702c5SYu Xiangning so_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
3690f1702c5SYu Xiangning     struct cred *cr)
3700f1702c5SYu Xiangning {
3710f1702c5SYu Xiangning 	int error, flags;
3720f1702c5SYu Xiangning 	boolean_t dontblock;
3730f1702c5SYu Xiangning 	ssize_t orig_resid;
3740f1702c5SYu Xiangning 	mblk_t  *mp;
3750f1702c5SYu Xiangning 
3760f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_SENDMSG(so, msg, uiop, cr));
3770f1702c5SYu Xiangning 
3780f1702c5SYu Xiangning 	flags = msg->msg_flags;
3790f1702c5SYu Xiangning 	error = 0;
3800f1702c5SYu Xiangning 	dontblock = (flags & MSG_DONTWAIT) ||
3810f1702c5SYu Xiangning 	    (uiop->uio_fmode & (FNONBLOCK|FNDELAY));
3820f1702c5SYu Xiangning 
3830f1702c5SYu Xiangning 	if (!(flags & MSG_XPG4_2) && msg->msg_controllen != 0) {
3840f1702c5SYu Xiangning 		/*
3850f1702c5SYu Xiangning 		 * Old way of passing fd's is not supported
3860f1702c5SYu Xiangning 		 */
3870f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
3880f1702c5SYu Xiangning 		return (EOPNOTSUPP);
3890f1702c5SYu Xiangning 	}
3900f1702c5SYu Xiangning 
3910f1702c5SYu Xiangning 	if ((so->so_mode & SM_ATOMIC) &&
3920f1702c5SYu Xiangning 	    uiop->uio_resid > so->so_proto_props.sopp_maxpsz &&
3930f1702c5SYu Xiangning 	    so->so_proto_props.sopp_maxpsz != -1) {
3940f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
3950f1702c5SYu Xiangning 		return (EMSGSIZE);
3960f1702c5SYu Xiangning 	}
3970f1702c5SYu Xiangning 
3980f1702c5SYu Xiangning 	/*
3990f1702c5SYu Xiangning 	 * For atomic sends we will only do one iteration.
4000f1702c5SYu Xiangning 	 */
4010f1702c5SYu Xiangning 	do {
4020f1702c5SYu Xiangning 		if (so->so_state & SS_CANTSENDMORE) {
4030f1702c5SYu Xiangning 			error = EPIPE;
4040f1702c5SYu Xiangning 			break;
4050f1702c5SYu Xiangning 		}
4060f1702c5SYu Xiangning 
4070f1702c5SYu Xiangning 		if (so->so_error != 0) {
4080f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
4090f1702c5SYu Xiangning 			error = sogeterr(so, B_TRUE);
4100f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
4110f1702c5SYu Xiangning 			if (error != 0)
4120f1702c5SYu Xiangning 				break;
4130f1702c5SYu Xiangning 		}
4140f1702c5SYu Xiangning 
4150f1702c5SYu Xiangning 		/*
4160f1702c5SYu Xiangning 		 * Send down OOB messages even if the send path is being
4170f1702c5SYu Xiangning 		 * flow controlled (assuming the protocol supports OOB data).
4180f1702c5SYu Xiangning 		 */
4190f1702c5SYu Xiangning 		if (flags & MSG_OOB) {
4200f1702c5SYu Xiangning 			if ((so->so_mode & SM_EXDATA) == 0) {
4210f1702c5SYu Xiangning 				error = EOPNOTSUPP;
4220f1702c5SYu Xiangning 				break;
4230f1702c5SYu Xiangning 			}
4243e95bd4aSAnders Persson 		} else if (SO_SND_FLOWCTRLD(so)) {
4250f1702c5SYu Xiangning 			/*
4260f1702c5SYu Xiangning 			 * Need to wait until the protocol is ready to receive
4270f1702c5SYu Xiangning 			 * more data for transmission.
4280f1702c5SYu Xiangning 			 */
4290f1702c5SYu Xiangning 			if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0)
4300f1702c5SYu Xiangning 				break;
4310f1702c5SYu Xiangning 		}
4320f1702c5SYu Xiangning 
4330f1702c5SYu Xiangning 		/*
4340f1702c5SYu Xiangning 		 * Time to send data to the protocol. We either copy the
4350f1702c5SYu Xiangning 		 * data into mblks or pass the uio directly to the protocol.
4360f1702c5SYu Xiangning 		 * We decide what to do based on the available down calls.
4370f1702c5SYu Xiangning 		 */
4380f1702c5SYu Xiangning 		if (so->so_downcalls->sd_send_uio != NULL) {
4390f1702c5SYu Xiangning 			error = (*so->so_downcalls->sd_send_uio)
4400f1702c5SYu Xiangning 			    (so->so_proto_handle, uiop, msg, cr);
4410f1702c5SYu Xiangning 			if (error != 0)
4420f1702c5SYu Xiangning 				break;
4430f1702c5SYu Xiangning 		} else {
4440f1702c5SYu Xiangning 			/* save the resid in case of failure */
4450f1702c5SYu Xiangning 			orig_resid = uiop->uio_resid;
4460f1702c5SYu Xiangning 
4470f1702c5SYu Xiangning 			if ((mp = socopyinuio(uiop,
4480f1702c5SYu Xiangning 			    so->so_proto_props.sopp_maxpsz,
4490f1702c5SYu Xiangning 			    so->so_proto_props.sopp_wroff,
4500f1702c5SYu Xiangning 			    so->so_proto_props.sopp_maxblk,
451bd670b35SErik Nordmark 			    so->so_proto_props.sopp_tail, &error)) == NULL) {
4520f1702c5SYu Xiangning 				break;
4530f1702c5SYu Xiangning 			}
4540f1702c5SYu Xiangning 			ASSERT(uiop->uio_resid >= 0);
4550f1702c5SYu Xiangning 
4563e95bd4aSAnders Persson 			if (so->so_filter_active > 0 &&
4573e95bd4aSAnders Persson 			    ((mp = SOF_FILTER_DATA_OUT(so, mp, msg, cr,
4583e95bd4aSAnders Persson 			    &error)) == NULL)) {
4593e95bd4aSAnders Persson 				if (error != 0)
4603e95bd4aSAnders Persson 					break;
4613e95bd4aSAnders Persson 				continue;
4623e95bd4aSAnders Persson 			}
4630f1702c5SYu Xiangning 			error = (*so->so_downcalls->sd_send)
4640f1702c5SYu Xiangning 			    (so->so_proto_handle, mp, msg, cr);
4650f1702c5SYu Xiangning 			if (error != 0) {
4660f1702c5SYu Xiangning 				/*
4670f1702c5SYu Xiangning 				 * The send failed. We do not have to free the
4680f1702c5SYu Xiangning 				 * mblks, because that is the protocol's
4690f1702c5SYu Xiangning 				 * responsibility. However, uio_resid must
4700f1702c5SYu Xiangning 				 * remain accurate, so adjust that here.
4710f1702c5SYu Xiangning 				 */
4720f1702c5SYu Xiangning 				uiop->uio_resid = orig_resid;
4730f1702c5SYu Xiangning 					break;
4740f1702c5SYu Xiangning 			}
4750f1702c5SYu Xiangning 		}
4760f1702c5SYu Xiangning 	} while (uiop->uio_resid > 0);
4770f1702c5SYu Xiangning 
4780f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
4790f1702c5SYu Xiangning 
4800f1702c5SYu Xiangning 	return (error);
4810f1702c5SYu Xiangning }
4820f1702c5SYu Xiangning 
4830f1702c5SYu Xiangning int
so_sendmblk_impl(struct sonode * so,struct nmsghdr * msg,int fflag,struct cred * cr,mblk_t ** mpp,sof_instance_t * fil,boolean_t fil_inject)4843e95bd4aSAnders Persson so_sendmblk_impl(struct sonode *so, struct nmsghdr *msg, int fflag,
4853e95bd4aSAnders Persson     struct cred *cr, mblk_t **mpp, sof_instance_t *fil,
4863e95bd4aSAnders Persson     boolean_t fil_inject)
4870f1702c5SYu Xiangning {
4880f1702c5SYu Xiangning 	int error;
4890f1702c5SYu Xiangning 	boolean_t dontblock;
4900f1702c5SYu Xiangning 	size_t size;
4910f1702c5SYu Xiangning 	mblk_t *mp = *mpp;
4920f1702c5SYu Xiangning 
4933e95bd4aSAnders Persson 	if (so->so_downcalls->sd_send == NULL)
4943e95bd4aSAnders Persson 		return (EOPNOTSUPP);
4950f1702c5SYu Xiangning 
4960f1702c5SYu Xiangning 	error = 0;
4970f1702c5SYu Xiangning 	dontblock = (msg->msg_flags & MSG_DONTWAIT) ||
4980f1702c5SYu Xiangning 	    (fflag & (FNONBLOCK|FNDELAY));
4990f1702c5SYu Xiangning 	size = msgdsize(mp);
5000f1702c5SYu Xiangning 
5010f1702c5SYu Xiangning 	if ((so->so_mode & SM_ATOMIC) &&
5020f1702c5SYu Xiangning 	    size > so->so_proto_props.sopp_maxpsz &&
5030f1702c5SYu Xiangning 	    so->so_proto_props.sopp_maxpsz != -1) {
5040f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
5050f1702c5SYu Xiangning 		return (EMSGSIZE);
5060f1702c5SYu Xiangning 	}
5070f1702c5SYu Xiangning 
5080f1702c5SYu Xiangning 	while (mp != NULL) {
5090f1702c5SYu Xiangning 		mblk_t *nmp, *last_mblk;
5100f1702c5SYu Xiangning 		size_t mlen;
5110f1702c5SYu Xiangning 
5120f1702c5SYu Xiangning 		if (so->so_state & SS_CANTSENDMORE) {
5130f1702c5SYu Xiangning 			error = EPIPE;
5140f1702c5SYu Xiangning 			break;
5150f1702c5SYu Xiangning 		}
5160f1702c5SYu Xiangning 		if (so->so_error != 0) {
5170f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
5180f1702c5SYu Xiangning 			error = sogeterr(so, B_TRUE);
5190f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
5200f1702c5SYu Xiangning 			if (error != 0)
5210f1702c5SYu Xiangning 				break;
5220f1702c5SYu Xiangning 		}
5233e95bd4aSAnders Persson 		/* Socket filters are not flow controlled */
5243e95bd4aSAnders Persson 		if (SO_SND_FLOWCTRLD(so) && !fil_inject) {
5250f1702c5SYu Xiangning 			/*
5260f1702c5SYu Xiangning 			 * Need to wait until the protocol is ready to receive
5270f1702c5SYu Xiangning 			 * more data for transmission.
5280f1702c5SYu Xiangning 			 */
5290f1702c5SYu Xiangning 			if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0)
5300f1702c5SYu Xiangning 				break;
5310f1702c5SYu Xiangning 		}
5320f1702c5SYu Xiangning 
5330f1702c5SYu Xiangning 		/*
5340f1702c5SYu Xiangning 		 * We only allow so_maxpsz of data to be sent down to
5350f1702c5SYu Xiangning 		 * the protocol at time.
5360f1702c5SYu Xiangning 		 */
5370f1702c5SYu Xiangning 		mlen = MBLKL(mp);
5380f1702c5SYu Xiangning 		nmp = mp->b_cont;
5390f1702c5SYu Xiangning 		last_mblk = mp;
5400f1702c5SYu Xiangning 		while (nmp != NULL) {
5410f1702c5SYu Xiangning 			mlen += MBLKL(nmp);
5420f1702c5SYu Xiangning 			if (mlen > so->so_proto_props.sopp_maxpsz) {
5430f1702c5SYu Xiangning 				last_mblk->b_cont = NULL;
5440f1702c5SYu Xiangning 				break;
5450f1702c5SYu Xiangning 			}
5460f1702c5SYu Xiangning 			last_mblk = nmp;
5470f1702c5SYu Xiangning 			nmp = nmp->b_cont;
5480f1702c5SYu Xiangning 		}
5490f1702c5SYu Xiangning 
5503e95bd4aSAnders Persson 		if (so->so_filter_active > 0 &&
5513e95bd4aSAnders Persson 		    (mp = SOF_FILTER_DATA_OUT_FROM(so, fil, mp, msg,
5523e95bd4aSAnders Persson 		    cr, &error)) == NULL) {
5533e95bd4aSAnders Persson 			*mpp = mp = nmp;
5543e95bd4aSAnders Persson 			if (error != 0)
5553e95bd4aSAnders Persson 				break;
5563e95bd4aSAnders Persson 			continue;
5573e95bd4aSAnders Persson 		}
5580f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_send)
5590f1702c5SYu Xiangning 		    (so->so_proto_handle, mp, msg, cr);
5600f1702c5SYu Xiangning 		if (error != 0) {
5610f1702c5SYu Xiangning 			/*
5620f1702c5SYu Xiangning 			 * The send failed. The protocol will free the mblks
5630f1702c5SYu Xiangning 			 * that were sent down. Let the caller deal with the
5640f1702c5SYu Xiangning 			 * rest.
5650f1702c5SYu Xiangning 			 */
5660f1702c5SYu Xiangning 			*mpp = nmp;
5670f1702c5SYu Xiangning 			break;
5680f1702c5SYu Xiangning 		}
5690f1702c5SYu Xiangning 
5700f1702c5SYu Xiangning 		*mpp = mp = nmp;
5710f1702c5SYu Xiangning 	}
5723e95bd4aSAnders Persson 	/* Let the filter know whether the protocol is flow controlled */
5733e95bd4aSAnders Persson 	if (fil_inject && error == 0 && SO_SND_FLOWCTRLD(so))
5743e95bd4aSAnders Persson 		error = ENOSPC;
5753e95bd4aSAnders Persson 
5763e95bd4aSAnders Persson 	return (error);
5773e95bd4aSAnders Persson }
5783e95bd4aSAnders Persson 
5793e95bd4aSAnders Persson #pragma inline(so_sendmblk_impl)
5803e95bd4aSAnders Persson 
5813e95bd4aSAnders Persson int
so_sendmblk(struct sonode * so,struct nmsghdr * msg,int fflag,struct cred * cr,mblk_t ** mpp)5823e95bd4aSAnders Persson so_sendmblk(struct sonode *so, struct nmsghdr *msg, int fflag,
5833e95bd4aSAnders Persson     struct cred *cr, mblk_t **mpp)
5843e95bd4aSAnders Persson {
5853e95bd4aSAnders Persson 	int error;
5863e95bd4aSAnders Persson 
5873e95bd4aSAnders Persson 	SO_BLOCK_FALLBACK(so, SOP_SENDMBLK(so, msg, fflag, cr, mpp));
5883e95bd4aSAnders Persson 
5893e95bd4aSAnders Persson 	if ((so->so_mode & SM_SENDFILESUPP) == 0) {
5903e95bd4aSAnders Persson 		SO_UNBLOCK_FALLBACK(so);
5913e95bd4aSAnders Persson 		return (EOPNOTSUPP);
5923e95bd4aSAnders Persson 	}
5933e95bd4aSAnders Persson 
5943e95bd4aSAnders Persson 	error = so_sendmblk_impl(so, msg, fflag, cr, mpp, so->so_filter_top,
5953e95bd4aSAnders Persson 	    B_FALSE);
5960f1702c5SYu Xiangning 
5970f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
5980f1702c5SYu Xiangning 
5990f1702c5SYu Xiangning 	return (error);
6000f1702c5SYu Xiangning }
6010f1702c5SYu Xiangning 
6020f1702c5SYu Xiangning int
so_shutdown(struct sonode * so,int how,struct cred * cr)6030f1702c5SYu Xiangning so_shutdown(struct sonode *so, int how, struct cred *cr)
6040f1702c5SYu Xiangning {
6050f1702c5SYu Xiangning 	int error;
6060f1702c5SYu Xiangning 
6070f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_SHUTDOWN(so, how, cr));
6080f1702c5SYu Xiangning 
6090f1702c5SYu Xiangning 	/*
6100f1702c5SYu Xiangning 	 * SunOS 4.X has no check for datagram sockets.
6110f1702c5SYu Xiangning 	 * 5.X checks that it is connected (ENOTCONN)
6120f1702c5SYu Xiangning 	 * X/Open requires that we check the connected state.
6130f1702c5SYu Xiangning 	 */
6140f1702c5SYu Xiangning 	if (!(so->so_state & SS_ISCONNECTED)) {
6150f1702c5SYu Xiangning 		if (!xnet_skip_checks) {
6160f1702c5SYu Xiangning 			error = ENOTCONN;
6170f1702c5SYu Xiangning 			if (xnet_check_print) {
6180f1702c5SYu Xiangning 				printf("sockfs: X/Open shutdown check "
6190f1702c5SYu Xiangning 				    "caused ENOTCONN\n");
6200f1702c5SYu Xiangning 			}
6210f1702c5SYu Xiangning 		}
6220f1702c5SYu Xiangning 		goto done;
6230f1702c5SYu Xiangning 	}
6240f1702c5SYu Xiangning 
6253e95bd4aSAnders Persson 	if (so->so_filter_active == 0 ||
6263e95bd4aSAnders Persson 	    (error = sof_filter_shutdown(so, &how, cr)) < 0)
6270f1702c5SYu Xiangning 		error = ((*so->so_downcalls->sd_shutdown)(so->so_proto_handle,
6280f1702c5SYu Xiangning 		    how, cr));
6290f1702c5SYu Xiangning 
6300f1702c5SYu Xiangning 	/*
6310f1702c5SYu Xiangning 	 * Protocol agreed to shutdown. We need to flush the
6320f1702c5SYu Xiangning 	 * receive buffer if the receive side is being shutdown.
6330f1702c5SYu Xiangning 	 */
6340f1702c5SYu Xiangning 	if (error == 0 && how != SHUT_WR) {
6350f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
6360f1702c5SYu Xiangning 		/* wait for active reader to finish */
6370f1702c5SYu Xiangning 		(void) so_lock_read(so, 0);
6380f1702c5SYu Xiangning 
6390f1702c5SYu Xiangning 		so_rcv_flush(so);
6400f1702c5SYu Xiangning 
6410f1702c5SYu Xiangning 		so_unlock_read(so);
6420f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
6430f1702c5SYu Xiangning 	}
6440f1702c5SYu Xiangning 
6450f1702c5SYu Xiangning done:
6460f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
6470f1702c5SYu Xiangning 	return (error);
6480f1702c5SYu Xiangning }
6490f1702c5SYu Xiangning 
6500f1702c5SYu Xiangning int
so_getsockname(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)6510f1702c5SYu Xiangning so_getsockname(struct sonode *so, struct sockaddr *addr,
6520f1702c5SYu Xiangning     socklen_t *addrlen, struct cred *cr)
6530f1702c5SYu Xiangning {
6540f1702c5SYu Xiangning 	int error;
6550f1702c5SYu Xiangning 
6560f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_GETSOCKNAME(so, addr, addrlen, cr));
6570f1702c5SYu Xiangning 
6583e95bd4aSAnders Persson 	if (so->so_filter_active == 0 ||
6593e95bd4aSAnders Persson 	    (error = sof_filter_getsockname(so, addr, addrlen, cr)) < 0)
6600f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_getsockname)
6610f1702c5SYu Xiangning 		    (so->so_proto_handle, addr, addrlen, cr);
6620f1702c5SYu Xiangning 
6630f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
6640f1702c5SYu Xiangning 	return (error);
6650f1702c5SYu Xiangning }
6660f1702c5SYu Xiangning 
6670f1702c5SYu Xiangning int
so_getpeername(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,boolean_t accept,struct cred * cr)6680f1702c5SYu Xiangning so_getpeername(struct sonode *so, struct sockaddr *addr,
6690f1702c5SYu Xiangning     socklen_t *addrlen, boolean_t accept, struct cred *cr)
6700f1702c5SYu Xiangning {
6710f1702c5SYu Xiangning 	int error;
6720f1702c5SYu Xiangning 
6730f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_GETPEERNAME(so, addr, addrlen, accept, cr));
6740f1702c5SYu Xiangning 
6750f1702c5SYu Xiangning 	if (accept) {
6760f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_getpeername)
6770f1702c5SYu Xiangning 		    (so->so_proto_handle, addr, addrlen, cr);
6780f1702c5SYu Xiangning 	} else if (!(so->so_state & SS_ISCONNECTED)) {
6790f1702c5SYu Xiangning 		error = ENOTCONN;
6800f1702c5SYu Xiangning 	} else if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) {
6810f1702c5SYu Xiangning 		/* Added this check for X/Open */
6820f1702c5SYu Xiangning 		error = EINVAL;
6830f1702c5SYu Xiangning 		if (xnet_check_print) {
6840f1702c5SYu Xiangning 			printf("sockfs: X/Open getpeername check => EINVAL\n");
6850f1702c5SYu Xiangning 		}
6863e95bd4aSAnders Persson 	} else if (so->so_filter_active == 0 ||
6873e95bd4aSAnders Persson 	    (error = sof_filter_getpeername(so, addr, addrlen, cr)) < 0) {
6880f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_getpeername)
6890f1702c5SYu Xiangning 		    (so->so_proto_handle, addr, addrlen, cr);
6900f1702c5SYu Xiangning 	}
6910f1702c5SYu Xiangning 
6920f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
6930f1702c5SYu Xiangning 	return (error);
6940f1702c5SYu Xiangning }
6950f1702c5SYu Xiangning 
6960f1702c5SYu Xiangning int
so_getsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags,struct cred * cr)6970f1702c5SYu Xiangning so_getsockopt(struct sonode *so, int level, int option_name,
6980f1702c5SYu Xiangning     void *optval, socklen_t *optlenp, int flags, struct cred *cr)
6990f1702c5SYu Xiangning {
7000f1702c5SYu Xiangning 	int error = 0;
7010f1702c5SYu Xiangning 
7023e95bd4aSAnders Persson 	if (level == SOL_FILTER)
7033e95bd4aSAnders Persson 		return (sof_getsockopt(so, option_name, optval, optlenp, cr));
7043e95bd4aSAnders Persson 
7050f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so,
7060f1702c5SYu Xiangning 	    SOP_GETSOCKOPT(so, level, option_name, optval, optlenp, flags, cr));
7070f1702c5SYu Xiangning 
7083e95bd4aSAnders Persson 	if ((so->so_filter_active == 0 ||
7093e95bd4aSAnders Persson 	    (error = sof_filter_getsockopt(so, level, option_name, optval,
7103e95bd4aSAnders Persson 	    optlenp, cr)) < 0) &&
7113e95bd4aSAnders Persson 	    (error = socket_getopt_common(so, level, option_name, optval,
7123e95bd4aSAnders Persson 	    optlenp, flags)) < 0) {
7130f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_getsockopt)
7140f1702c5SYu Xiangning 		    (so->so_proto_handle, level, option_name, optval, optlenp,
7150f1702c5SYu Xiangning 		    cr);
7160f1702c5SYu Xiangning 		if (error ==  ENOPROTOOPT) {
7170f1702c5SYu Xiangning 			if (level == SOL_SOCKET) {
7180f1702c5SYu Xiangning 				/*
7190f1702c5SYu Xiangning 				 * If a protocol does not support a particular
7200f1702c5SYu Xiangning 				 * socket option, set can fail (not allowed)
7210f1702c5SYu Xiangning 				 * but get can not fail. This is the previous
7220f1702c5SYu Xiangning 				 * sockfs bahvior.
7230f1702c5SYu Xiangning 				 */
7240f1702c5SYu Xiangning 				switch (option_name) {
7250f1702c5SYu Xiangning 				case SO_LINGER:
7260f1702c5SYu Xiangning 					if (*optlenp < (t_uscalar_t)
7270f1702c5SYu Xiangning 					    sizeof (struct linger)) {
7280f1702c5SYu Xiangning 						error = EINVAL;
7290f1702c5SYu Xiangning 						break;
7300f1702c5SYu Xiangning 					}
7310f1702c5SYu Xiangning 					error = 0;
7320f1702c5SYu Xiangning 					bzero(optval, sizeof (struct linger));
7330f1702c5SYu Xiangning 					*optlenp = sizeof (struct linger);
7340f1702c5SYu Xiangning 					break;
7350f1702c5SYu Xiangning 				case SO_RCVTIMEO:
7360f1702c5SYu Xiangning 				case SO_SNDTIMEO:
7370f1702c5SYu Xiangning 					if (*optlenp < (t_uscalar_t)
7380f1702c5SYu Xiangning 					    sizeof (struct timeval)) {
7390f1702c5SYu Xiangning 						error = EINVAL;
7400f1702c5SYu Xiangning 						break;
7410f1702c5SYu Xiangning 					}
7420f1702c5SYu Xiangning 					error = 0;
7430f1702c5SYu Xiangning 					bzero(optval, sizeof (struct timeval));
7440f1702c5SYu Xiangning 					*optlenp = sizeof (struct timeval);
7450f1702c5SYu Xiangning 					break;
7460f1702c5SYu Xiangning 				case SO_SND_BUFINFO:
7470f1702c5SYu Xiangning 					if (*optlenp < (t_uscalar_t)
7480f1702c5SYu Xiangning 					    sizeof (struct so_snd_bufinfo)) {
7490f1702c5SYu Xiangning 						error = EINVAL;
7500f1702c5SYu Xiangning 						break;
7510f1702c5SYu Xiangning 					}
7520f1702c5SYu Xiangning 					error = 0;
7530f1702c5SYu Xiangning 					bzero(optval,
7540f1702c5SYu Xiangning 					    sizeof (struct so_snd_bufinfo));
7550f1702c5SYu Xiangning 					*optlenp =
7560f1702c5SYu Xiangning 					    sizeof (struct so_snd_bufinfo);
7570f1702c5SYu Xiangning 					break;
7580f1702c5SYu Xiangning 				case SO_DEBUG:
7590f1702c5SYu Xiangning 				case SO_REUSEADDR:
7600f1702c5SYu Xiangning 				case SO_KEEPALIVE:
7610f1702c5SYu Xiangning 				case SO_DONTROUTE:
7620f1702c5SYu Xiangning 				case SO_BROADCAST:
7630f1702c5SYu Xiangning 				case SO_USELOOPBACK:
7640f1702c5SYu Xiangning 				case SO_OOBINLINE:
7650f1702c5SYu Xiangning 				case SO_DGRAM_ERRIND:
7660f1702c5SYu Xiangning 				case SO_SNDBUF:
7670f1702c5SYu Xiangning 				case SO_RCVBUF:
7680f1702c5SYu Xiangning 					error = 0;
7690f1702c5SYu Xiangning 					*((int32_t *)optval) = 0;
7700f1702c5SYu Xiangning 					*optlenp = sizeof (int32_t);
7710f1702c5SYu Xiangning 					break;
7720f1702c5SYu Xiangning 				default:
7730f1702c5SYu Xiangning 					break;
7740f1702c5SYu Xiangning 				}
7750f1702c5SYu Xiangning 			}
7760f1702c5SYu Xiangning 		}
7770f1702c5SYu Xiangning 	}
7780f1702c5SYu Xiangning 
7790f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
7800f1702c5SYu Xiangning 	return (error);
7810f1702c5SYu Xiangning }
7820f1702c5SYu Xiangning 
7830f1702c5SYu Xiangning int
so_setsockopt(struct sonode * so,int level,int option_name,const void * optval,socklen_t optlen,struct cred * cr)7840f1702c5SYu Xiangning so_setsockopt(struct sonode *so, int level, int option_name,
7850f1702c5SYu Xiangning     const void *optval, socklen_t optlen, struct cred *cr)
7860f1702c5SYu Xiangning {
7870f1702c5SYu Xiangning 	int error = 0;
7883986c91eSanders 	struct timeval tl;
7893986c91eSanders 	const void *opt = optval;
7900f1702c5SYu Xiangning 
7913e95bd4aSAnders Persson 	if (level == SOL_FILTER)
7923e95bd4aSAnders Persson 		return (sof_setsockopt(so, option_name, optval, optlen, cr));
7933e95bd4aSAnders Persson 
7940f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so,
7950f1702c5SYu Xiangning 	    SOP_SETSOCKOPT(so, level, option_name, optval, optlen, cr));
7960f1702c5SYu Xiangning 
7970f1702c5SYu Xiangning 	/* X/Open requires this check */
7980f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE && !xnet_skip_checks) {
7990f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
8000f1702c5SYu Xiangning 		if (xnet_check_print)
8010f1702c5SYu Xiangning 			printf("sockfs: X/Open setsockopt check => EINVAL\n");
8020f1702c5SYu Xiangning 		return (EINVAL);
8030f1702c5SYu Xiangning 	}
8040f1702c5SYu Xiangning 
8053e95bd4aSAnders Persson 	if (so->so_filter_active > 0 &&
8063e95bd4aSAnders Persson 	    (error = sof_filter_setsockopt(so, level, option_name,
8073e95bd4aSAnders Persson 	    (void *)optval, &optlen, cr)) >= 0)
8083e95bd4aSAnders Persson 		goto done;
8093e95bd4aSAnders Persson 
810a5adac4dSYu Xiangning 	if (level == SOL_SOCKET) {
811a5adac4dSYu Xiangning 		switch (option_name) {
812a5adac4dSYu Xiangning 		case SO_RCVTIMEO:
813a5adac4dSYu Xiangning 		case SO_SNDTIMEO: {
81434dfe683Sshenjian 			/*
81534dfe683Sshenjian 			 * We pass down these two options to protocol in order
81634dfe683Sshenjian 			 * to support some third part protocols which need to
81734dfe683Sshenjian 			 * know them. For those protocols which don't care
81834dfe683Sshenjian 			 * these two options, simply return 0.
81934dfe683Sshenjian 			 */
8200f1702c5SYu Xiangning 			clock_t t_usec;
8210f1702c5SYu Xiangning 
822e5083e81Sshenjian 			if (get_udatamodel() == DATAMODEL_NONE ||
823e5083e81Sshenjian 			    get_udatamodel() == DATAMODEL_NATIVE) {
82422238f73Sshenjian 				if (optlen != sizeof (struct timeval)) {
82522238f73Sshenjian 					error = EINVAL;
82622238f73Sshenjian 					goto done;
8270f1702c5SYu Xiangning 				}
82822238f73Sshenjian 				bcopy((struct timeval *)optval, &tl,
82922238f73Sshenjian 				    sizeof (struct timeval));
83022238f73Sshenjian 			} else {
83122238f73Sshenjian 				if (optlen != sizeof (struct timeval32)) {
83222238f73Sshenjian 					error = EINVAL;
83322238f73Sshenjian 					goto done;
83422238f73Sshenjian 				}
83522238f73Sshenjian 				TIMEVAL32_TO_TIMEVAL(&tl,
83622238f73Sshenjian 				    (struct timeval32 *)optval);
83722238f73Sshenjian 			}
8383986c91eSanders 			opt = &tl;
8393986c91eSanders 			optlen = sizeof (tl);
84022238f73Sshenjian 			t_usec = tl.tv_sec * 1000 * 1000 + tl.tv_usec;
8410f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
8420f1702c5SYu Xiangning 			if (option_name == SO_RCVTIMEO)
8430f1702c5SYu Xiangning 				so->so_rcvtimeo = drv_usectohz(t_usec);
8440f1702c5SYu Xiangning 			else
8450f1702c5SYu Xiangning 				so->so_sndtimeo = drv_usectohz(t_usec);
8460f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
84734dfe683Sshenjian 			break;
8480f1702c5SYu Xiangning 		}
849a5adac4dSYu Xiangning 		case SO_RCVBUF:
850a5adac4dSYu Xiangning 			/*
851a5adac4dSYu Xiangning 			 * XXX XPG 4.2 applications retrieve SO_RCVBUF from
852a5adac4dSYu Xiangning 			 * sockfs since the transport might adjust the value
853a5adac4dSYu Xiangning 			 * and not return exactly what was set by the
854a5adac4dSYu Xiangning 			 * application.
855a5adac4dSYu Xiangning 			 */
856a5adac4dSYu Xiangning 			so->so_xpg_rcvbuf = *(int32_t *)optval;
857a5adac4dSYu Xiangning 			break;
858a5adac4dSYu Xiangning 		}
859a5adac4dSYu Xiangning 	}
8600f1702c5SYu Xiangning 	error = (*so->so_downcalls->sd_setsockopt)
8613986c91eSanders 	    (so->so_proto_handle, level, option_name, opt, optlen, cr);
86222238f73Sshenjian done:
8630f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
8640f1702c5SYu Xiangning 	return (error);
8650f1702c5SYu Xiangning }
8660f1702c5SYu Xiangning 
8670f1702c5SYu Xiangning int
so_ioctl(struct sonode * so,int cmd,intptr_t arg,int mode,struct cred * cr,int32_t * rvalp)8680f1702c5SYu Xiangning so_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
8690f1702c5SYu Xiangning     struct cred *cr, int32_t *rvalp)
8700f1702c5SYu Xiangning {
8710f1702c5SYu Xiangning 	int error = 0;
8720f1702c5SYu Xiangning 
8730f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_IOCTL(so, cmd, arg, mode, cr, rvalp));
8740f1702c5SYu Xiangning 
8750f1702c5SYu Xiangning 	/*
8760f1702c5SYu Xiangning 	 * If there is a pending error, return error
8770f1702c5SYu Xiangning 	 * This can happen if a non blocking operation caused an error.
8780f1702c5SYu Xiangning 	 */
8790f1702c5SYu Xiangning 	if (so->so_error != 0) {
8800f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
8810f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
8820f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
8830f1702c5SYu Xiangning 		if (error != 0)
8840f1702c5SYu Xiangning 			goto done;
8850f1702c5SYu Xiangning 	}
8860f1702c5SYu Xiangning 
8870f1702c5SYu Xiangning 	/*
8880f1702c5SYu Xiangning 	 * calling strioc can result in the socket falling back to TPI,
8890f1702c5SYu Xiangning 	 * if that is supported.
8900f1702c5SYu Xiangning 	 */
8913e95bd4aSAnders Persson 	if ((so->so_filter_active == 0 ||
8923e95bd4aSAnders Persson 	    (error = sof_filter_ioctl(so, cmd, arg, mode,
8933e95bd4aSAnders Persson 	    rvalp, cr)) < 0) &&
8943e95bd4aSAnders Persson 	    (error = socket_ioctl_common(so, cmd, arg, mode, cr, rvalp)) < 0 &&
8950f1702c5SYu Xiangning 	    (error = socket_strioc_common(so, cmd, arg, mode, cr, rvalp)) < 0) {
8960f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_ioctl)(so->so_proto_handle,
8970f1702c5SYu Xiangning 		    cmd, arg, mode, rvalp, cr);
8980f1702c5SYu Xiangning 	}
8990f1702c5SYu Xiangning 
9000f1702c5SYu Xiangning done:
9010f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
9020f1702c5SYu Xiangning 
9030f1702c5SYu Xiangning 	return (error);
9040f1702c5SYu Xiangning }
9050f1702c5SYu Xiangning 
9060f1702c5SYu Xiangning int
so_poll(struct sonode * so,short events,int anyyet,short * reventsp,struct pollhead ** phpp)9070f1702c5SYu Xiangning so_poll(struct sonode *so, short events, int anyyet, short *reventsp,
9080f1702c5SYu Xiangning     struct pollhead **phpp)
9090f1702c5SYu Xiangning {
910*68846fd0SBryan Cantrill 	int state = so->so_state, mask;
9110f1702c5SYu Xiangning 	*reventsp = 0;
9120f1702c5SYu Xiangning 
913af89d820SRao Shoaib 	/*
914af89d820SRao Shoaib 	 * In sockets the errors are represented as input/output events
915af89d820SRao Shoaib 	 */
9160f1702c5SYu Xiangning 	if (so->so_error != 0 &&
9170f1702c5SYu Xiangning 	    ((POLLIN|POLLRDNORM|POLLOUT) & events) != 0) {
9180f1702c5SYu Xiangning 		*reventsp = (POLLIN|POLLRDNORM|POLLOUT) & events;
9190f1702c5SYu Xiangning 		return (0);
9200f1702c5SYu Xiangning 	}
9210f1702c5SYu Xiangning 
9220f1702c5SYu Xiangning 	/*
923af89d820SRao Shoaib 	 * If the socket is in a state where it can send data
924af89d820SRao Shoaib 	 * turn on POLLWRBAND and POLLOUT events.
9250f1702c5SYu Xiangning 	 */
926af89d820SRao Shoaib 	if ((so->so_mode & SM_CONNREQUIRED) == 0 || (state & SS_ISCONNECTED)) {
927af89d820SRao Shoaib 		/*
928af89d820SRao Shoaib 		 * out of band data is allowed even if the connection
929af89d820SRao Shoaib 		 * is flow controlled
930af89d820SRao Shoaib 		 */
931af89d820SRao Shoaib 		*reventsp |= POLLWRBAND & events;
9323e95bd4aSAnders Persson 		if (!SO_SND_FLOWCTRLD(so)) {
933af89d820SRao Shoaib 			/*
934af89d820SRao Shoaib 			 * As long as there is buffer to send data
935af89d820SRao Shoaib 			 * turn on POLLOUT events
936af89d820SRao Shoaib 			 */
9370f1702c5SYu Xiangning 			*reventsp |= POLLOUT & events;
9380f1702c5SYu Xiangning 		}
939af89d820SRao Shoaib 	}
9400f1702c5SYu Xiangning 
9410f1702c5SYu Xiangning 	/*
9420f1702c5SYu Xiangning 	 * Turn on POLLIN whenever there is data on the receive queue,
9430f1702c5SYu Xiangning 	 * or the socket is in a state where no more data will be received.
9440f1702c5SYu Xiangning 	 * Also, if the socket is accepting connections, flip the bit if
9450f1702c5SYu Xiangning 	 * there is something on the queue.
946f0267584Sanders 	 *
947f0267584Sanders 	 * We do an initial check for events without holding locks. However,
948f0267584Sanders 	 * if there are no event available, then we redo the check for POLLIN
949f0267584Sanders 	 * events under the lock.
9500f1702c5SYu Xiangning 	 */
9510f1702c5SYu Xiangning 
9520f1702c5SYu Xiangning 	/* Pending connections */
9533e95bd4aSAnders Persson 	if (!list_is_empty(&so->so_acceptq_list))
9540f1702c5SYu Xiangning 		*reventsp |= (POLLIN|POLLRDNORM) & events;
9550f1702c5SYu Xiangning 
9560f1702c5SYu Xiangning 	/* Data */
9570f1702c5SYu Xiangning 	/* so_downcalls is null for sctp */
9580f1702c5SYu Xiangning 	if (so->so_downcalls != NULL && so->so_downcalls->sd_poll != NULL) {
9590f1702c5SYu Xiangning 		*reventsp |= (*so->so_downcalls->sd_poll)
9600f1702c5SYu Xiangning 		    (so->so_proto_handle, events & SO_PROTO_POLLEV, anyyet,
9610f1702c5SYu Xiangning 		    CRED()) & events;
9620f1702c5SYu Xiangning 		ASSERT((*reventsp & ~events) == 0);
9630f1702c5SYu Xiangning 		/* do not recheck events */
9640f1702c5SYu Xiangning 		events &= ~SO_PROTO_POLLEV;
9650f1702c5SYu Xiangning 	} else {
9660f1702c5SYu Xiangning 		if (SO_HAVE_DATA(so))
9670f1702c5SYu Xiangning 			*reventsp |= (POLLIN|POLLRDNORM) & events;
9680f1702c5SYu Xiangning 
9690f1702c5SYu Xiangning 		/* Urgent data */
970af89d820SRao Shoaib 		if ((state & SS_OOBPEND) != 0) {
971af89d820SRao Shoaib 			*reventsp |= (POLLRDBAND | POLLPRI) & events;
972af89d820SRao Shoaib 		}
973*68846fd0SBryan Cantrill 
974*68846fd0SBryan Cantrill 		/*
975*68846fd0SBryan Cantrill 		 * If the socket has become disconnected, we set POLLHUP.
976*68846fd0SBryan Cantrill 		 * Note that if we are in this state, we will have set POLLIN
977*68846fd0SBryan Cantrill 		 * (SO_HAVE_DATA() is true on a disconnected socket), but not
978*68846fd0SBryan Cantrill 		 * POLLOUT (SS_ISCONNECTED is false).  This is in keeping with
979*68846fd0SBryan Cantrill 		 * the semantics of POLLHUP, which is defined to be mutually
980*68846fd0SBryan Cantrill 		 * exclusive with respect to POLLOUT but not POLLIN.  We are
981*68846fd0SBryan Cantrill 		 * therefore setting POLLHUP primarily for the benefit of
982*68846fd0SBryan Cantrill 		 * those not polling on POLLIN, as they have no other way of
983*68846fd0SBryan Cantrill 		 * knowing that the socket has been disconnected.
984*68846fd0SBryan Cantrill 		 */
985*68846fd0SBryan Cantrill 		mask = SS_SENTLASTREADSIG | SS_SENTLASTWRITESIG;
986*68846fd0SBryan Cantrill 
987*68846fd0SBryan Cantrill 		if ((state & (mask | SS_ISCONNECTED)) == mask)
988*68846fd0SBryan Cantrill 			*reventsp |= POLLHUP;
9890f1702c5SYu Xiangning 	}
9900f1702c5SYu Xiangning 
9910f1702c5SYu Xiangning 	if (!*reventsp && !anyyet) {
9920f1702c5SYu Xiangning 		/* Check for read events again, but this time under lock */
9930f1702c5SYu Xiangning 		if (events & (POLLIN|POLLRDNORM)) {
9940f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
9953e95bd4aSAnders Persson 			if (SO_HAVE_DATA(so) ||
9963e95bd4aSAnders Persson 			    !list_is_empty(&so->so_acceptq_list)) {
9970f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
9980f1702c5SYu Xiangning 				*reventsp |= (POLLIN|POLLRDNORM) & events;
9990f1702c5SYu Xiangning 				return (0);
10000f1702c5SYu Xiangning 			} else {
10010f1702c5SYu Xiangning 				so->so_pollev |= SO_POLLEV_IN;
10020f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
10030f1702c5SYu Xiangning 			}
10040f1702c5SYu Xiangning 		}
10050f1702c5SYu Xiangning 		*phpp = &so->so_poll_list;
10060f1702c5SYu Xiangning 	}
10070f1702c5SYu Xiangning 	return (0);
10080f1702c5SYu Xiangning }
10090f1702c5SYu Xiangning 
10100f1702c5SYu Xiangning /*
10110f1702c5SYu Xiangning  * Generic Upcalls
10120f1702c5SYu Xiangning  */
10130f1702c5SYu Xiangning void
so_connected(sock_upper_handle_t sock_handle,sock_connid_t id,cred_t * peer_cred,pid_t peer_cpid)10140f1702c5SYu Xiangning so_connected(sock_upper_handle_t sock_handle, sock_connid_t id,
10150f1702c5SYu Xiangning     cred_t *peer_cred, pid_t peer_cpid)
10160f1702c5SYu Xiangning {
10170f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
10180f1702c5SYu Xiangning 
10190f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
10200f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle != NULL);
10210f1702c5SYu Xiangning 
10220f1702c5SYu Xiangning 	if (peer_cred != NULL) {
10230f1702c5SYu Xiangning 		if (so->so_peercred != NULL)
10240f1702c5SYu Xiangning 			crfree(so->so_peercred);
10250f1702c5SYu Xiangning 		crhold(peer_cred);
10260f1702c5SYu Xiangning 		so->so_peercred = peer_cred;
10270f1702c5SYu Xiangning 		so->so_cpid = peer_cpid;
10280f1702c5SYu Xiangning 	}
10290f1702c5SYu Xiangning 
10300f1702c5SYu Xiangning 	so->so_proto_connid = id;
10310f1702c5SYu Xiangning 	soisconnected(so);
10320f1702c5SYu Xiangning 	/*
10330f1702c5SYu Xiangning 	 * Wake ones who're waiting for conn to become established.
10340f1702c5SYu Xiangning 	 */
10350f1702c5SYu Xiangning 	so_notify_connected(so);
10360f1702c5SYu Xiangning }
10370f1702c5SYu Xiangning 
10380f1702c5SYu Xiangning int
so_disconnected(sock_upper_handle_t sock_handle,sock_connid_t id,int error)10390f1702c5SYu Xiangning so_disconnected(sock_upper_handle_t sock_handle, sock_connid_t id, int error)
10400f1702c5SYu Xiangning {
10410f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
10423e95bd4aSAnders Persson 	boolean_t connect_failed;
10430f1702c5SYu Xiangning 
10440f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
1045*68846fd0SBryan Cantrill 
1046*68846fd0SBryan Cantrill 	/*
1047*68846fd0SBryan Cantrill 	 * If we aren't currently connected, then this isn't a disconnect but
1048*68846fd0SBryan Cantrill 	 * rather a failure to connect.
1049*68846fd0SBryan Cantrill 	 */
1050*68846fd0SBryan Cantrill 	connect_failed = !(so->so_state & SS_ISCONNECTED);
1051*68846fd0SBryan Cantrill 
10520f1702c5SYu Xiangning 	so->so_proto_connid = id;
10530f1702c5SYu Xiangning 	soisdisconnected(so, error);
10543e95bd4aSAnders Persson 	so_notify_disconnected(so, connect_failed, error);
10550f1702c5SYu Xiangning 
10560f1702c5SYu Xiangning 	return (0);
10570f1702c5SYu Xiangning }
10580f1702c5SYu Xiangning 
10590f1702c5SYu Xiangning void
so_opctl(sock_upper_handle_t sock_handle,sock_opctl_action_t action,uintptr_t arg)10600f1702c5SYu Xiangning so_opctl(sock_upper_handle_t sock_handle, sock_opctl_action_t action,
10610f1702c5SYu Xiangning     uintptr_t arg)
10620f1702c5SYu Xiangning {
10630f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
10640f1702c5SYu Xiangning 
10650f1702c5SYu Xiangning 	switch (action) {
10660f1702c5SYu Xiangning 	case SOCK_OPCTL_SHUT_SEND:
10670f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
10680f1702c5SYu Xiangning 		socantsendmore(so);
10690f1702c5SYu Xiangning 		so_notify_disconnecting(so);
10700f1702c5SYu Xiangning 		break;
10710f1702c5SYu Xiangning 	case SOCK_OPCTL_SHUT_RECV: {
10720f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
10730f1702c5SYu Xiangning 		socantrcvmore(so);
10740f1702c5SYu Xiangning 		so_notify_eof(so);
10750f1702c5SYu Xiangning 		break;
10760f1702c5SYu Xiangning 	}
10770f1702c5SYu Xiangning 	case SOCK_OPCTL_ENAB_ACCEPT:
10780f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
10790f1702c5SYu Xiangning 		so->so_state |= SS_ACCEPTCONN;
10800f1702c5SYu Xiangning 		so->so_backlog = (unsigned int)arg;
10813e95bd4aSAnders Persson 		/*
10823e95bd4aSAnders Persson 		 * The protocol can stop generating newconn upcalls when
10833e95bd4aSAnders Persson 		 * the backlog is full, so to make sure the listener does
10843e95bd4aSAnders Persson 		 * not end up with a queue full of deferred connections
10853e95bd4aSAnders Persson 		 * we reduce the backlog by one. Thus the listener will
10863e95bd4aSAnders Persson 		 * start closing deferred connections before the backlog
10873e95bd4aSAnders Persson 		 * is full.
10883e95bd4aSAnders Persson 		 */
10893e95bd4aSAnders Persson 		if (so->so_filter_active > 0)
10903e95bd4aSAnders Persson 			so->so_backlog = MAX(1, so->so_backlog - 1);
10910f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
10920f1702c5SYu Xiangning 		break;
10930f1702c5SYu Xiangning 	default:
10940f1702c5SYu Xiangning 		ASSERT(0);
10950f1702c5SYu Xiangning 		break;
10960f1702c5SYu Xiangning 	}
10970f1702c5SYu Xiangning }
10980f1702c5SYu Xiangning 
10990f1702c5SYu Xiangning void
so_txq_full(sock_upper_handle_t sock_handle,boolean_t qfull)11000f1702c5SYu Xiangning so_txq_full(sock_upper_handle_t sock_handle, boolean_t qfull)
11010f1702c5SYu Xiangning {
11020f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
11030f1702c5SYu Xiangning 
11040f1702c5SYu Xiangning 	if (qfull) {
11050f1702c5SYu Xiangning 		so_snd_qfull(so);
11060f1702c5SYu Xiangning 	} else {
11070f1702c5SYu Xiangning 		so_snd_qnotfull(so);
11080f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
11093e95bd4aSAnders Persson 		/* so_notify_writable drops so_lock */
11100f1702c5SYu Xiangning 		so_notify_writable(so);
11110f1702c5SYu Xiangning 	}
11120f1702c5SYu Xiangning }
11130f1702c5SYu Xiangning 
11140f1702c5SYu Xiangning sock_upper_handle_t
so_newconn(sock_upper_handle_t parenthandle,sock_lower_handle_t proto_handle,sock_downcalls_t * sock_downcalls,struct cred * peer_cred,pid_t peer_cpid,sock_upcalls_t ** sock_upcallsp)11150f1702c5SYu Xiangning so_newconn(sock_upper_handle_t parenthandle,
11160f1702c5SYu Xiangning     sock_lower_handle_t proto_handle, sock_downcalls_t *sock_downcalls,
11170f1702c5SYu Xiangning     struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **sock_upcallsp)
11180f1702c5SYu Xiangning {
11190f1702c5SYu Xiangning 	struct sonode	*so = (struct sonode *)parenthandle;
11200f1702c5SYu Xiangning 	struct sonode	*nso;
11210f1702c5SYu Xiangning 	int error;
11220f1702c5SYu Xiangning 
11230f1702c5SYu Xiangning 	ASSERT(proto_handle != NULL);
11240f1702c5SYu Xiangning 
11250f1702c5SYu Xiangning 	if ((so->so_state & SS_ACCEPTCONN) == 0 ||
11263e95bd4aSAnders Persson 	    (so->so_acceptq_len >= so->so_backlog &&
11273e95bd4aSAnders Persson 	    (so->so_filter_active == 0 || !sof_sonode_drop_deferred(so)))) {
11280f1702c5SYu Xiangning 			return (NULL);
11293e95bd4aSAnders Persson 	}
11300f1702c5SYu Xiangning 
11310f1702c5SYu Xiangning 	nso = socket_newconn(so, proto_handle, sock_downcalls, SOCKET_NOSLEEP,
11320f1702c5SYu Xiangning 	    &error);
11330f1702c5SYu Xiangning 	if (nso == NULL)
11340f1702c5SYu Xiangning 		return (NULL);
11350f1702c5SYu Xiangning 
11360f1702c5SYu Xiangning 	if (peer_cred != NULL) {
11370f1702c5SYu Xiangning 		crhold(peer_cred);
11380f1702c5SYu Xiangning 		nso->so_peercred = peer_cred;
11390f1702c5SYu Xiangning 		nso->so_cpid = peer_cpid;
11400f1702c5SYu Xiangning 	}
11413e95bd4aSAnders Persson 	nso->so_listener = so;
11420f1702c5SYu Xiangning 
1143d68ef20eSAnders Persson 	/*
1144d68ef20eSAnders Persson 	 * The new socket (nso), proto_handle and sock_upcallsp are all
1145d68ef20eSAnders Persson 	 * valid at this point. But as soon as nso is placed in the accept
1146d68ef20eSAnders Persson 	 * queue that can no longer be assumed (since an accept() thread may
1147d68ef20eSAnders Persson 	 * pull it off the queue and close the socket).
1148d68ef20eSAnders Persson 	 */
1149d68ef20eSAnders Persson 	*sock_upcallsp = &so_upcalls;
1150d68ef20eSAnders Persson 
11513e95bd4aSAnders Persson 	mutex_enter(&so->so_acceptq_lock);
11523e95bd4aSAnders Persson 	if (so->so_state & (SS_CLOSING|SS_FALLBACK_PENDING|SS_FALLBACK_COMP)) {
11533e95bd4aSAnders Persson 		mutex_exit(&so->so_acceptq_lock);
11543e95bd4aSAnders Persson 		ASSERT(nso->so_count == 1);
11553e95bd4aSAnders Persson 		nso->so_count--;
1156b1cd7879SAnders Persson 		nso->so_listener = NULL;
11573e95bd4aSAnders Persson 		/* drop proto ref */
11583e95bd4aSAnders Persson 		VN_RELE(SOTOV(nso));
11593e95bd4aSAnders Persson 		socket_destroy(nso);
11603e95bd4aSAnders Persson 		return (NULL);
11613e95bd4aSAnders Persson 	} else {
11623e95bd4aSAnders Persson 		so->so_acceptq_len++;
11633e95bd4aSAnders Persson 		if (nso->so_state & SS_FIL_DEFER) {
11643e95bd4aSAnders Persson 			list_insert_tail(&so->so_acceptq_defer, nso);
11653e95bd4aSAnders Persson 			mutex_exit(&so->so_acceptq_lock);
11663e95bd4aSAnders Persson 		} else {
11673e95bd4aSAnders Persson 			list_insert_tail(&so->so_acceptq_list, nso);
11683e95bd4aSAnders Persson 			cv_signal(&so->so_acceptq_cv);
11693e95bd4aSAnders Persson 			mutex_exit(&so->so_acceptq_lock);
11700f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
11710f1702c5SYu Xiangning 			so_notify_newconn(so);
11723e95bd4aSAnders Persson 		}
11730f1702c5SYu Xiangning 
11740f1702c5SYu Xiangning 		return ((sock_upper_handle_t)nso);
11750f1702c5SYu Xiangning 	}
11763e95bd4aSAnders Persson }
11770f1702c5SYu Xiangning 
11780f1702c5SYu Xiangning void
so_set_prop(sock_upper_handle_t sock_handle,struct sock_proto_props * soppp)11790f1702c5SYu Xiangning so_set_prop(sock_upper_handle_t sock_handle, struct sock_proto_props *soppp)
11800f1702c5SYu Xiangning {
11810f1702c5SYu Xiangning 	struct sonode *so;
11820f1702c5SYu Xiangning 
11830f1702c5SYu Xiangning 	so = (struct sonode *)sock_handle;
11840f1702c5SYu Xiangning 
11850f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11860f1702c5SYu Xiangning 
11870f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_MAXBLK)
11880f1702c5SYu Xiangning 		so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk;
11890f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_WROFF)
11900f1702c5SYu Xiangning 		so->so_proto_props.sopp_wroff = soppp->sopp_wroff;
11910f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_TAIL)
11920f1702c5SYu Xiangning 		so->so_proto_props.sopp_tail = soppp->sopp_tail;
11930f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_RCVHIWAT)
11940f1702c5SYu Xiangning 		so->so_proto_props.sopp_rxhiwat = soppp->sopp_rxhiwat;
11950f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_RCVLOWAT)
11960f1702c5SYu Xiangning 		so->so_proto_props.sopp_rxlowat = soppp->sopp_rxlowat;
11970f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_MAXPSZ)
11980f1702c5SYu Xiangning 		so->so_proto_props.sopp_maxpsz = soppp->sopp_maxpsz;
11990f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_MINPSZ)
12000f1702c5SYu Xiangning 		so->so_proto_props.sopp_minpsz = soppp->sopp_minpsz;
12010f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_ZCOPY) {
12020f1702c5SYu Xiangning 		if (soppp->sopp_zcopyflag & ZCVMSAFE) {
12030f1702c5SYu Xiangning 			so->so_proto_props.sopp_zcopyflag |= STZCVMSAFE;
12040f1702c5SYu Xiangning 			so->so_proto_props.sopp_zcopyflag &= ~STZCVMUNSAFE;
12050f1702c5SYu Xiangning 		} else if (soppp->sopp_zcopyflag & ZCVMUNSAFE) {
12060f1702c5SYu Xiangning 			so->so_proto_props.sopp_zcopyflag |= STZCVMUNSAFE;
12070f1702c5SYu Xiangning 			so->so_proto_props.sopp_zcopyflag &= ~STZCVMSAFE;
12080f1702c5SYu Xiangning 		}
12090f1702c5SYu Xiangning 
12100f1702c5SYu Xiangning 		if (soppp->sopp_zcopyflag & COPYCACHED) {
12110f1702c5SYu Xiangning 			so->so_proto_props.sopp_zcopyflag |= STRCOPYCACHED;
12120f1702c5SYu Xiangning 		}
12130f1702c5SYu Xiangning 	}
12140f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_OOBINLINE)
12150f1702c5SYu Xiangning 		so->so_proto_props.sopp_oobinline = soppp->sopp_oobinline;
12160f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_RCVTIMER)
12170f1702c5SYu Xiangning 		so->so_proto_props.sopp_rcvtimer = soppp->sopp_rcvtimer;
12180f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_RCVTHRESH)
12190f1702c5SYu Xiangning 		so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh;
12200f1702c5SYu Xiangning 	if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN)
12210f1702c5SYu Xiangning 		so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen;
1222081c0aa8SAnders Persson 	if (soppp->sopp_flags & SOCKOPT_LOOPBACK)
1223081c0aa8SAnders Persson 		so->so_proto_props.sopp_loopback = soppp->sopp_loopback;
12240f1702c5SYu Xiangning 
12250f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
12260f1702c5SYu Xiangning 
12273e95bd4aSAnders Persson 	if (so->so_filter_active > 0) {
12283e95bd4aSAnders Persson 		sof_instance_t *inst;
12293e95bd4aSAnders Persson 		ssize_t maxblk;
12303e95bd4aSAnders Persson 		ushort_t wroff, tail;
12313e95bd4aSAnders Persson 		maxblk = so->so_proto_props.sopp_maxblk;
12323e95bd4aSAnders Persson 		wroff = so->so_proto_props.sopp_wroff;
12333e95bd4aSAnders Persson 		tail = so->so_proto_props.sopp_tail;
12343e95bd4aSAnders Persson 		for (inst = so->so_filter_bottom; inst != NULL;
12353e95bd4aSAnders Persson 		    inst = inst->sofi_prev) {
12363e95bd4aSAnders Persson 			if (SOF_INTERESTED(inst, mblk_prop)) {
12373e95bd4aSAnders Persson 				(*inst->sofi_ops->sofop_mblk_prop)(
12383e95bd4aSAnders Persson 				    (sof_handle_t)inst, inst->sofi_cookie,
12393e95bd4aSAnders Persson 				    &maxblk, &wroff, &tail);
12403e95bd4aSAnders Persson 			}
12413e95bd4aSAnders Persson 		}
12423e95bd4aSAnders Persson 		mutex_enter(&so->so_lock);
12433e95bd4aSAnders Persson 		so->so_proto_props.sopp_maxblk = maxblk;
12443e95bd4aSAnders Persson 		so->so_proto_props.sopp_wroff = wroff;
12453e95bd4aSAnders Persson 		so->so_proto_props.sopp_tail = tail;
12463e95bd4aSAnders Persson 		mutex_exit(&so->so_lock);
12473e95bd4aSAnders Persson 	}
12480f1702c5SYu Xiangning #ifdef DEBUG
12490f1702c5SYu Xiangning 	soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL |
12500f1702c5SYu Xiangning 	    SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ |
12510f1702c5SYu Xiangning 	    SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER |
1252081c0aa8SAnders Persson 	    SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ |
1253081c0aa8SAnders Persson 	    SOCKOPT_LOOPBACK);
12540f1702c5SYu Xiangning 	ASSERT(soppp->sopp_flags == 0);
12550f1702c5SYu Xiangning #endif
12560f1702c5SYu Xiangning }
12570f1702c5SYu Xiangning 
12580f1702c5SYu Xiangning /* ARGSUSED */
12590f1702c5SYu Xiangning ssize_t
so_queue_msg_impl(struct sonode * so,mblk_t * mp,size_t msg_size,int flags,int * errorp,boolean_t * force_pushp,sof_instance_t * filter)12603e95bd4aSAnders Persson so_queue_msg_impl(struct sonode *so, mblk_t *mp,
12613e95bd4aSAnders Persson     size_t msg_size, int flags, int *errorp,  boolean_t *force_pushp,
12623e95bd4aSAnders Persson     sof_instance_t *filter)
12630f1702c5SYu Xiangning {
12640f1702c5SYu Xiangning 	boolean_t force_push = B_TRUE;
12650f1702c5SYu Xiangning 	int space_left;
12660f1702c5SYu Xiangning 	sodirect_t *sodp = so->so_direct;
12670f1702c5SYu Xiangning 
12680f1702c5SYu Xiangning 	ASSERT(errorp != NULL);
12690f1702c5SYu Xiangning 	*errorp = 0;
12700f1702c5SYu Xiangning 	if (mp == NULL) {
1271c0dd49bdSEiji Ota 		if (so->so_downcalls->sd_recv_uio != NULL) {
12720f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
12730f1702c5SYu Xiangning 			/* the notify functions will drop the lock */
12740f1702c5SYu Xiangning 			if (flags & MSG_OOB)
12750f1702c5SYu Xiangning 				so_notify_oobdata(so, IS_SO_OOB_INLINE(so));
12760f1702c5SYu Xiangning 			else
12770f1702c5SYu Xiangning 				so_notify_data(so, msg_size);
12780f1702c5SYu Xiangning 			return (0);
12790f1702c5SYu Xiangning 		}
1280c0dd49bdSEiji Ota 		ASSERT(msg_size == 0);
12810f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
12823e95bd4aSAnders Persson 		goto space_check;
12830f1702c5SYu Xiangning 	}
12840f1702c5SYu Xiangning 
12850f1702c5SYu Xiangning 	ASSERT(mp->b_next == NULL);
12860f1702c5SYu Xiangning 	ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_PROTO);
12870f1702c5SYu Xiangning 	ASSERT(msg_size == msgdsize(mp));
12880f1702c5SYu Xiangning 
12890f1702c5SYu Xiangning 	if (DB_TYPE(mp) == M_PROTO && !__TPI_PRIM_ISALIGNED(mp->b_rptr)) {
12900f1702c5SYu Xiangning 		/* The read pointer is not aligned correctly for TPI */
12910f1702c5SYu Xiangning 		zcmn_err(getzoneid(), CE_WARN,
12920f1702c5SYu Xiangning 		    "sockfs: Unaligned TPI message received. rptr = %p\n",
12930f1702c5SYu Xiangning 		    (void *)mp->b_rptr);
12940f1702c5SYu Xiangning 		freemsg(mp);
1295bbc000e5SAnders Persson 		mutex_enter(&so->so_lock);
1296bbc000e5SAnders Persson 		if (sodp != NULL)
12970f1702c5SYu Xiangning 			SOD_UIOAFINI(sodp);
12983e95bd4aSAnders Persson 		goto space_check;
12990f1702c5SYu Xiangning 	}
13000f1702c5SYu Xiangning 
13013e95bd4aSAnders Persson 	if (so->so_filter_active > 0) {
13023e95bd4aSAnders Persson 		for (; filter != NULL; filter = filter->sofi_prev) {
13033e95bd4aSAnders Persson 			if (!SOF_INTERESTED(filter, data_in))
13043e95bd4aSAnders Persson 				continue;
13053e95bd4aSAnders Persson 			mp = (*filter->sofi_ops->sofop_data_in)(
13063e95bd4aSAnders Persson 			    (sof_handle_t)filter, filter->sofi_cookie, mp,
13073e95bd4aSAnders Persson 			    flags, &msg_size);
13083e95bd4aSAnders Persson 			ASSERT(msgdsize(mp) == msg_size);
13093e95bd4aSAnders Persson 			DTRACE_PROBE2(filter__data, (sof_instance_t), filter,
13103e95bd4aSAnders Persson 			    (mblk_t *), mp);
13113e95bd4aSAnders Persson 			/* Data was consumed/dropped, just do space check */
13123e95bd4aSAnders Persson 			if (msg_size == 0) {
13133e95bd4aSAnders Persson 				mutex_enter(&so->so_lock);
13143e95bd4aSAnders Persson 				goto space_check;
13153e95bd4aSAnders Persson 			}
13163e95bd4aSAnders Persson 		}
13173e95bd4aSAnders Persson 	}
13183e95bd4aSAnders Persson 
13193e95bd4aSAnders Persson 	if (flags & MSG_OOB) {
13203e95bd4aSAnders Persson 		so_queue_oob(so, mp, msg_size);
13213e95bd4aSAnders Persson 		mutex_enter(&so->so_lock);
13223e95bd4aSAnders Persson 		goto space_check;
13233e95bd4aSAnders Persson 	}
13243e95bd4aSAnders Persson 
13253e95bd4aSAnders Persson 	if (force_pushp != NULL)
13263e95bd4aSAnders Persson 		force_push = *force_pushp;
13273e95bd4aSAnders Persson 
13280f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
132941174437SAnders Persson 	if (so->so_state & (SS_FALLBACK_DRAIN | SS_FALLBACK_COMP)) {
1330bbc000e5SAnders Persson 		if (sodp != NULL)
13310f1702c5SYu Xiangning 			SOD_DISABLE(sodp);
13320f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
13330f1702c5SYu Xiangning 		*errorp = EOPNOTSUPP;
13340f1702c5SYu Xiangning 		return (-1);
13350f1702c5SYu Xiangning 	}
13363e95bd4aSAnders Persson 	if (so->so_state & (SS_CANTRCVMORE | SS_CLOSING)) {
13370f1702c5SYu Xiangning 		freemsg(mp);
1338bbc000e5SAnders Persson 		if (sodp != NULL)
13390f1702c5SYu Xiangning 			SOD_DISABLE(sodp);
13400f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
13410f1702c5SYu Xiangning 		return (0);
13420f1702c5SYu Xiangning 	}
13430f1702c5SYu Xiangning 
13440f1702c5SYu Xiangning 	/* process the mblk via I/OAT if capable */
1345bbc000e5SAnders Persson 	if (sodp != NULL && sodp->sod_enabled) {
13460f1702c5SYu Xiangning 		if (DB_TYPE(mp) == M_DATA) {
1347bbc000e5SAnders Persson 			sod_uioa_mblk_init(sodp, mp, msg_size);
13480f1702c5SYu Xiangning 		} else {
13490f1702c5SYu Xiangning 			SOD_UIOAFINI(sodp);
13500f1702c5SYu Xiangning 		}
13510f1702c5SYu Xiangning 	}
13520f1702c5SYu Xiangning 
13530f1702c5SYu Xiangning 	if (mp->b_next == NULL) {
13540f1702c5SYu Xiangning 		so_enqueue_msg(so, mp, msg_size);
13550f1702c5SYu Xiangning 	} else {
13560f1702c5SYu Xiangning 		do {
13570f1702c5SYu Xiangning 			mblk_t *nmp;
13580f1702c5SYu Xiangning 
13590f1702c5SYu Xiangning 			if ((nmp = mp->b_next) != NULL) {
13600f1702c5SYu Xiangning 				mp->b_next = NULL;
13610f1702c5SYu Xiangning 			}
13620f1702c5SYu Xiangning 			so_enqueue_msg(so, mp, msgdsize(mp));
13630f1702c5SYu Xiangning 			mp = nmp;
13640f1702c5SYu Xiangning 		} while (mp != NULL);
13650f1702c5SYu Xiangning 	}
13660f1702c5SYu Xiangning 
13670f1702c5SYu Xiangning 	space_left = so->so_rcvbuf - so->so_rcv_queued;
13680f1702c5SYu Xiangning 	if (space_left <= 0) {
13690f1702c5SYu Xiangning 		so->so_flowctrld = B_TRUE;
13700f1702c5SYu Xiangning 		*errorp = ENOSPC;
13710f1702c5SYu Xiangning 		space_left = -1;
13720f1702c5SYu Xiangning 	}
13730f1702c5SYu Xiangning 
13740f1702c5SYu Xiangning 	if (force_push || so->so_rcv_queued >= so->so_rcv_thresh ||
1375bbc000e5SAnders Persson 	    so->so_rcv_queued >= so->so_rcv_wanted) {
13760f1702c5SYu Xiangning 		SOCKET_TIMER_CANCEL(so);
13770f1702c5SYu Xiangning 		/*
13780f1702c5SYu Xiangning 		 * so_notify_data will release the lock
13790f1702c5SYu Xiangning 		 */
13800f1702c5SYu Xiangning 		so_notify_data(so, so->so_rcv_queued);
13810f1702c5SYu Xiangning 
13820f1702c5SYu Xiangning 		if (force_pushp != NULL)
13830f1702c5SYu Xiangning 			*force_pushp = B_TRUE;
13840f1702c5SYu Xiangning 		goto done;
13850f1702c5SYu Xiangning 	} else if (so->so_rcv_timer_tid == 0) {
13860f1702c5SYu Xiangning 		/* Make sure the recv push timer is running */
13870f1702c5SYu Xiangning 		SOCKET_TIMER_START(so);
13880f1702c5SYu Xiangning 	}
13890f1702c5SYu Xiangning 
13900f1702c5SYu Xiangning done_unlock:
13910f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
13920f1702c5SYu Xiangning done:
13930f1702c5SYu Xiangning 	return (space_left);
13943e95bd4aSAnders Persson 
13953e95bd4aSAnders Persson space_check:
13963e95bd4aSAnders Persson 	space_left = so->so_rcvbuf - so->so_rcv_queued;
13973e95bd4aSAnders Persson 	if (space_left <= 0) {
13983e95bd4aSAnders Persson 		so->so_flowctrld = B_TRUE;
13993e95bd4aSAnders Persson 		*errorp = ENOSPC;
14003e95bd4aSAnders Persson 		space_left = -1;
14013e95bd4aSAnders Persson 	}
14023e95bd4aSAnders Persson 	goto done_unlock;
14033e95bd4aSAnders Persson }
14043e95bd4aSAnders Persson 
14053e95bd4aSAnders Persson #pragma	inline(so_queue_msg_impl)
14063e95bd4aSAnders Persson 
14073e95bd4aSAnders Persson ssize_t
so_queue_msg(sock_upper_handle_t sock_handle,mblk_t * mp,size_t msg_size,int flags,int * errorp,boolean_t * force_pushp)14083e95bd4aSAnders Persson so_queue_msg(sock_upper_handle_t sock_handle, mblk_t *mp,
14093e95bd4aSAnders Persson     size_t msg_size, int flags, int *errorp,  boolean_t *force_pushp)
14103e95bd4aSAnders Persson {
14113e95bd4aSAnders Persson 	struct sonode *so = (struct sonode *)sock_handle;
14123e95bd4aSAnders Persson 
14133e95bd4aSAnders Persson 	return (so_queue_msg_impl(so, mp, msg_size, flags, errorp, force_pushp,
14143e95bd4aSAnders Persson 	    so->so_filter_bottom));
14150f1702c5SYu Xiangning }
14160f1702c5SYu Xiangning 
14170f1702c5SYu Xiangning /*
14180f1702c5SYu Xiangning  * Set the offset of where the oob data is relative to the bytes in
14190f1702c5SYu Xiangning  * queued. Also generate SIGURG
14200f1702c5SYu Xiangning  */
14210f1702c5SYu Xiangning void
so_signal_oob(sock_upper_handle_t sock_handle,ssize_t offset)14220f1702c5SYu Xiangning so_signal_oob(sock_upper_handle_t sock_handle, ssize_t offset)
14230f1702c5SYu Xiangning {
14240f1702c5SYu Xiangning 	struct sonode *so;
14250f1702c5SYu Xiangning 
14260f1702c5SYu Xiangning 	ASSERT(offset >= 0);
14270f1702c5SYu Xiangning 	so = (struct sonode *)sock_handle;
14280f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
1429bbc000e5SAnders Persson 	if (so->so_direct != NULL)
14300f1702c5SYu Xiangning 		SOD_UIOAFINI(so->so_direct);
14310f1702c5SYu Xiangning 
14320f1702c5SYu Xiangning 	/*
14330f1702c5SYu Xiangning 	 * New urgent data on the way so forget about any old
14340f1702c5SYu Xiangning 	 * urgent data.
14350f1702c5SYu Xiangning 	 */
14360f1702c5SYu Xiangning 	so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA);
14370f1702c5SYu Xiangning 
14380f1702c5SYu Xiangning 	/*
14390f1702c5SYu Xiangning 	 * Record that urgent data is pending.
14400f1702c5SYu Xiangning 	 */
14410f1702c5SYu Xiangning 	so->so_state |= SS_OOBPEND;
14420f1702c5SYu Xiangning 
14430f1702c5SYu Xiangning 	if (so->so_oobmsg != NULL) {
14440f1702c5SYu Xiangning 		dprintso(so, 1, ("sock: discarding old oob\n"));
14450f1702c5SYu Xiangning 		freemsg(so->so_oobmsg);
14460f1702c5SYu Xiangning 		so->so_oobmsg = NULL;
14470f1702c5SYu Xiangning 	}
14480f1702c5SYu Xiangning 
14490f1702c5SYu Xiangning 	/*
14500f1702c5SYu Xiangning 	 * set the offset where the urgent byte is
14510f1702c5SYu Xiangning 	 */
14520f1702c5SYu Xiangning 	so->so_oobmark = so->so_rcv_queued + offset;
14530f1702c5SYu Xiangning 	if (so->so_oobmark == 0)
14540f1702c5SYu Xiangning 		so->so_state |= SS_RCVATMARK;
14550f1702c5SYu Xiangning 	else
14560f1702c5SYu Xiangning 		so->so_state &= ~SS_RCVATMARK;
14570f1702c5SYu Xiangning 
14580f1702c5SYu Xiangning 	so_notify_oobsig(so);
14590f1702c5SYu Xiangning }
14600f1702c5SYu Xiangning 
14610f1702c5SYu Xiangning /*
14620f1702c5SYu Xiangning  * Queue the OOB byte
14630f1702c5SYu Xiangning  */
14640f1702c5SYu Xiangning static void
so_queue_oob(struct sonode * so,mblk_t * mp,size_t len)14653e95bd4aSAnders Persson so_queue_oob(struct sonode *so, mblk_t *mp, size_t len)
14660f1702c5SYu Xiangning {
14670f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
1468bbc000e5SAnders Persson 	if (so->so_direct != NULL)
14690f1702c5SYu Xiangning 		SOD_UIOAFINI(so->so_direct);
14700f1702c5SYu Xiangning 
14710f1702c5SYu Xiangning 	ASSERT(mp != NULL);
14720f1702c5SYu Xiangning 	if (!IS_SO_OOB_INLINE(so)) {
14730f1702c5SYu Xiangning 		so->so_oobmsg = mp;
14740f1702c5SYu Xiangning 		so->so_state |= SS_HAVEOOBDATA;
14750f1702c5SYu Xiangning 	} else {
14760f1702c5SYu Xiangning 		so_enqueue_msg(so, mp, len);
14770f1702c5SYu Xiangning 	}
14780f1702c5SYu Xiangning 
14790f1702c5SYu Xiangning 	so_notify_oobdata(so, IS_SO_OOB_INLINE(so));
14800f1702c5SYu Xiangning }
14810f1702c5SYu Xiangning 
14820f1702c5SYu Xiangning int
so_close(struct sonode * so,int flag,struct cred * cr)14830f1702c5SYu Xiangning so_close(struct sonode *so, int flag, struct cred *cr)
14840f1702c5SYu Xiangning {
14850f1702c5SYu Xiangning 	int error;
14860f1702c5SYu Xiangning 
14870f1702c5SYu Xiangning 	/*
14883e95bd4aSAnders Persson 	 * No new data will be enqueued once the CLOSING flag is set.
14890f1702c5SYu Xiangning 	 */
14900f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
14913e95bd4aSAnders Persson 	so->so_state |= SS_CLOSING;
1492d36be52eSRao Shoaib 	ASSERT(so_verify_oobstate(so));
14930f1702c5SYu Xiangning 	so_rcv_flush(so);
14940f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
14950f1702c5SYu Xiangning 
1496e82bc0baSAnders Persson 	if (so->so_filter_active > 0)
1497e82bc0baSAnders Persson 		sof_sonode_closing(so);
1498e82bc0baSAnders Persson 
14993e95bd4aSAnders Persson 	if (so->so_state & SS_ACCEPTCONN) {
15003e95bd4aSAnders Persson 		/*
15013e95bd4aSAnders Persson 		 * We grab and release the accept lock to ensure that any
15023e95bd4aSAnders Persson 		 * thread about to insert a socket in so_newconn completes
15033e95bd4aSAnders Persson 		 * before we flush the queue. Any thread calling so_newconn
15043e95bd4aSAnders Persson 		 * after we drop the lock will observe the SS_CLOSING flag,
15053e95bd4aSAnders Persson 		 * which will stop it from inserting the socket in the queue.
15063e95bd4aSAnders Persson 		 */
15073e95bd4aSAnders Persson 		mutex_enter(&so->so_acceptq_lock);
15083e95bd4aSAnders Persson 		mutex_exit(&so->so_acceptq_lock);
15093e95bd4aSAnders Persson 
15103e95bd4aSAnders Persson 		so_acceptq_flush(so, B_TRUE);
15113e95bd4aSAnders Persson 	}
15123e95bd4aSAnders Persson 
15133e95bd4aSAnders Persson 	error = (*so->so_downcalls->sd_close)(so->so_proto_handle, flag, cr);
15143e95bd4aSAnders Persson 	switch (error) {
15153e95bd4aSAnders Persson 	default:
15163e95bd4aSAnders Persson 		/* Protocol made a synchronous close; remove proto ref */
15173e95bd4aSAnders Persson 		VN_RELE(SOTOV(so));
15183e95bd4aSAnders Persson 		break;
15193e95bd4aSAnders Persson 	case EINPROGRESS:
15203e95bd4aSAnders Persson 		/*
15213e95bd4aSAnders Persson 		 * Protocol is in the process of closing, it will make a
15223e95bd4aSAnders Persson 		 * 'closed' upcall to remove the reference.
15233e95bd4aSAnders Persson 		 */
15243e95bd4aSAnders Persson 		error = 0;
15253e95bd4aSAnders Persson 		break;
15263e95bd4aSAnders Persson 	}
15273e95bd4aSAnders Persson 
15280f1702c5SYu Xiangning 	return (error);
15290f1702c5SYu Xiangning }
15300f1702c5SYu Xiangning 
15313e95bd4aSAnders Persson /*
15323e95bd4aSAnders Persson  * Upcall made by the protocol when it's doing an asynchronous close. It
15333e95bd4aSAnders Persson  * will drop the protocol's reference on the socket.
15343e95bd4aSAnders Persson  */
15353e95bd4aSAnders Persson void
so_closed(sock_upper_handle_t sock_handle)15363e95bd4aSAnders Persson so_closed(sock_upper_handle_t sock_handle)
15373e95bd4aSAnders Persson {
15383e95bd4aSAnders Persson 	struct sonode *so = (struct sonode *)sock_handle;
15393e95bd4aSAnders Persson 
15403e95bd4aSAnders Persson 	VN_RELE(SOTOV(so));
15413e95bd4aSAnders Persson }
15423e95bd4aSAnders Persson 
15430f1702c5SYu Xiangning void
so_zcopy_notify(sock_upper_handle_t sock_handle)15440f1702c5SYu Xiangning so_zcopy_notify(sock_upper_handle_t sock_handle)
15450f1702c5SYu Xiangning {
15460f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
15470f1702c5SYu Xiangning 
15480f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
15490f1702c5SYu Xiangning 	so->so_copyflag |= STZCNOTIFY;
15500f1702c5SYu Xiangning 	cv_broadcast(&so->so_copy_cv);
15510f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
15520f1702c5SYu Xiangning }
15530f1702c5SYu Xiangning 
15540f1702c5SYu Xiangning void
so_set_error(sock_upper_handle_t sock_handle,int error)15550f1702c5SYu Xiangning so_set_error(sock_upper_handle_t sock_handle, int error)
15560f1702c5SYu Xiangning {
15570f1702c5SYu Xiangning 	struct sonode *so = (struct sonode *)sock_handle;
15580f1702c5SYu Xiangning 
15590f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
15600f1702c5SYu Xiangning 
15610f1702c5SYu Xiangning 	soseterror(so, error);
15620f1702c5SYu Xiangning 
15630f1702c5SYu Xiangning 	so_notify_error(so);
15640f1702c5SYu Xiangning }
15650f1702c5SYu Xiangning 
15660f1702c5SYu Xiangning /*
15670f1702c5SYu Xiangning  * so_recvmsg - read data from the socket
15680f1702c5SYu Xiangning  *
15690f1702c5SYu Xiangning  * There are two ways of obtaining data; either we ask the protocol to
15700f1702c5SYu Xiangning  * copy directly into the supplied buffer, or we copy data from the
15710f1702c5SYu Xiangning  * sonode's receive queue. The decision which one to use depends on
15720f1702c5SYu Xiangning  * whether the protocol has a sd_recv_uio down call.
15730f1702c5SYu Xiangning  */
15740f1702c5SYu Xiangning int
so_recvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)15750f1702c5SYu Xiangning so_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
15760f1702c5SYu Xiangning     struct cred *cr)
15770f1702c5SYu Xiangning {
15780f1702c5SYu Xiangning 	rval_t 		rval;
15790f1702c5SYu Xiangning 	int 		flags = 0;
15800f1702c5SYu Xiangning 	t_uscalar_t	controllen, namelen;
15810f1702c5SYu Xiangning 	int 		error = 0;
15820f1702c5SYu Xiangning 	int ret;
15830f1702c5SYu Xiangning 	mblk_t		*mctlp = NULL;
15840f1702c5SYu Xiangning 	union T_primitives *tpr;
15850f1702c5SYu Xiangning 	void		*control;
15860f1702c5SYu Xiangning 	ssize_t		saved_resid;
15870f1702c5SYu Xiangning 	struct uio	*suiop;
15880f1702c5SYu Xiangning 
15890f1702c5SYu Xiangning 	SO_BLOCK_FALLBACK(so, SOP_RECVMSG(so, msg, uiop, cr));
15900f1702c5SYu Xiangning 
15910f1702c5SYu Xiangning 	if ((so->so_state & (SS_ISCONNECTED|SS_CANTRCVMORE)) == 0 &&
15920f1702c5SYu Xiangning 	    (so->so_mode & SM_CONNREQUIRED)) {
15930f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
15940f1702c5SYu Xiangning 		return (ENOTCONN);
15950f1702c5SYu Xiangning 	}
15960f1702c5SYu Xiangning 
15970f1702c5SYu Xiangning 	if (msg->msg_flags & MSG_PEEK)
15980f1702c5SYu Xiangning 		msg->msg_flags &= ~MSG_WAITALL;
15990f1702c5SYu Xiangning 
16000f1702c5SYu Xiangning 	if (so->so_mode & SM_ATOMIC)
16010f1702c5SYu Xiangning 		msg->msg_flags |= MSG_TRUNC;
16020f1702c5SYu Xiangning 
16030f1702c5SYu Xiangning 	if (msg->msg_flags & MSG_OOB) {
16040f1702c5SYu Xiangning 		if ((so->so_mode & SM_EXDATA) == 0) {
16050f1702c5SYu Xiangning 			error = EOPNOTSUPP;
16060f1702c5SYu Xiangning 		} else if (so->so_downcalls->sd_recv_uio != NULL) {
16070f1702c5SYu Xiangning 			error = (*so->so_downcalls->sd_recv_uio)
16080f1702c5SYu Xiangning 			    (so->so_proto_handle, uiop, msg, cr);
16090f1702c5SYu Xiangning 		} else {
16100f1702c5SYu Xiangning 			error = sorecvoob(so, msg, uiop, msg->msg_flags,
16110f1702c5SYu Xiangning 			    IS_SO_OOB_INLINE(so));
16120f1702c5SYu Xiangning 		}
16130f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
16140f1702c5SYu Xiangning 		return (error);
16150f1702c5SYu Xiangning 	}
16160f1702c5SYu Xiangning 
16170f1702c5SYu Xiangning 	/*
16180f1702c5SYu Xiangning 	 * If the protocol has the recv down call, then pass the request
16190f1702c5SYu Xiangning 	 * down.
16200f1702c5SYu Xiangning 	 */
16210f1702c5SYu Xiangning 	if (so->so_downcalls->sd_recv_uio != NULL) {
16220f1702c5SYu Xiangning 		error = (*so->so_downcalls->sd_recv_uio)
16230f1702c5SYu Xiangning 		    (so->so_proto_handle, uiop, msg, cr);
16240f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
16250f1702c5SYu Xiangning 		return (error);
16260f1702c5SYu Xiangning 	}
16270f1702c5SYu Xiangning 
16280f1702c5SYu Xiangning 	/*
16290f1702c5SYu Xiangning 	 * Reading data from the socket buffer
16300f1702c5SYu Xiangning 	 */
16310f1702c5SYu Xiangning 	flags = msg->msg_flags;
16320f1702c5SYu Xiangning 	msg->msg_flags = 0;
16330f1702c5SYu Xiangning 
16340f1702c5SYu Xiangning 	/*
16350f1702c5SYu Xiangning 	 * Set msg_controllen and msg_namelen to zero here to make it
16360f1702c5SYu Xiangning 	 * simpler in the cases that no control or name is returned.
16370f1702c5SYu Xiangning 	 */
16380f1702c5SYu Xiangning 	controllen = msg->msg_controllen;
16390f1702c5SYu Xiangning 	namelen = msg->msg_namelen;
16400f1702c5SYu Xiangning 	msg->msg_controllen = 0;
16410f1702c5SYu Xiangning 	msg->msg_namelen = 0;
16420f1702c5SYu Xiangning 
16430f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
16440f1702c5SYu Xiangning 	/* Set SOREADLOCKED */
16450f1702c5SYu Xiangning 	error = so_lock_read_intr(so,
16460f1702c5SYu Xiangning 	    uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
16470f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
16480f1702c5SYu Xiangning 	if (error) {
16490f1702c5SYu Xiangning 		SO_UNBLOCK_FALLBACK(so);
16500f1702c5SYu Xiangning 		return (error);
16510f1702c5SYu Xiangning 	}
16520f1702c5SYu Xiangning 
16530f1702c5SYu Xiangning 	suiop = sod_rcv_init(so, flags, &uiop);
16540f1702c5SYu Xiangning retry:
16550f1702c5SYu Xiangning 	saved_resid = uiop->uio_resid;
16560f1702c5SYu Xiangning 	error = so_dequeue_msg(so, &mctlp, uiop, &rval, flags);
16570f1702c5SYu Xiangning 	if (error != 0) {
16580f1702c5SYu Xiangning 		goto out;
16590f1702c5SYu Xiangning 	}
16600f1702c5SYu Xiangning 	/*
16610f1702c5SYu Xiangning 	 * For datagrams the MOREDATA flag is used to set MSG_TRUNC.
16620f1702c5SYu Xiangning 	 * For non-datagrams MOREDATA is used to set MSG_EOR.
16630f1702c5SYu Xiangning 	 */
16640f1702c5SYu Xiangning 	ASSERT(!(rval.r_val1 & MORECTL));
16650f1702c5SYu Xiangning 	if ((rval.r_val1 & MOREDATA) && (so->so_mode & SM_ATOMIC))
16660f1702c5SYu Xiangning 		msg->msg_flags |= MSG_TRUNC;
16670f1702c5SYu Xiangning 	if (mctlp == NULL) {
16680f1702c5SYu Xiangning 		dprintso(so, 1, ("so_recvmsg: got M_DATA\n"));
16690f1702c5SYu Xiangning 
16700f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
16710f1702c5SYu Xiangning 		/* Set MSG_EOR based on MOREDATA */
16720f1702c5SYu Xiangning 		if (!(rval.r_val1 & MOREDATA)) {
16730f1702c5SYu Xiangning 			if (so->so_state & SS_SAVEDEOR) {
16740f1702c5SYu Xiangning 				msg->msg_flags |= MSG_EOR;
16750f1702c5SYu Xiangning 				so->so_state &= ~SS_SAVEDEOR;
16760f1702c5SYu Xiangning 			}
16770f1702c5SYu Xiangning 		}
16780f1702c5SYu Xiangning 		/*
16790f1702c5SYu Xiangning 		 * If some data was received (i.e. not EOF) and the
16800f1702c5SYu Xiangning 		 * read/recv* has not been satisfied wait for some more.
16810f1702c5SYu Xiangning 		 */
16820f1702c5SYu Xiangning 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
16830f1702c5SYu Xiangning 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
16840f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
16858591a19aSAnders Persson 			flags |= MSG_NOMARK;
16860f1702c5SYu Xiangning 			goto retry;
16870f1702c5SYu Xiangning 		}
16880f1702c5SYu Xiangning 
16890f1702c5SYu Xiangning 		goto out_locked;
16900f1702c5SYu Xiangning 	}
16918591a19aSAnders Persson 	/* so_queue_msg has already verified length and alignment */
16920f1702c5SYu Xiangning 	tpr = (union T_primitives *)mctlp->b_rptr;
16930f1702c5SYu Xiangning 	dprintso(so, 1, ("so_recvmsg: type %d\n", tpr->type));
16940f1702c5SYu Xiangning 	switch (tpr->type) {
16950f1702c5SYu Xiangning 	case T_DATA_IND: {
16960f1702c5SYu Xiangning 		/*
16970f1702c5SYu Xiangning 		 * Set msg_flags to MSG_EOR based on
16980f1702c5SYu Xiangning 		 * MORE_flag and MOREDATA.
16990f1702c5SYu Xiangning 		 */
17000f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
17010f1702c5SYu Xiangning 		so->so_state &= ~SS_SAVEDEOR;
17020f1702c5SYu Xiangning 		if (!(tpr->data_ind.MORE_flag & 1)) {
17030f1702c5SYu Xiangning 			if (!(rval.r_val1 & MOREDATA))
17040f1702c5SYu Xiangning 				msg->msg_flags |= MSG_EOR;
17050f1702c5SYu Xiangning 			else
17060f1702c5SYu Xiangning 				so->so_state |= SS_SAVEDEOR;
17070f1702c5SYu Xiangning 		}
17080f1702c5SYu Xiangning 		freemsg(mctlp);
17090f1702c5SYu Xiangning 		/*
17100f1702c5SYu Xiangning 		 * If some data was received (i.e. not EOF) and the
17110f1702c5SYu Xiangning 		 * read/recv* has not been satisfied wait for some more.
17120f1702c5SYu Xiangning 		 */
17130f1702c5SYu Xiangning 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
17140f1702c5SYu Xiangning 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
17150f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
17168591a19aSAnders Persson 			flags |= MSG_NOMARK;
17170f1702c5SYu Xiangning 			goto retry;
17180f1702c5SYu Xiangning 		}
17190f1702c5SYu Xiangning 		goto out_locked;
17200f1702c5SYu Xiangning 	}
17210f1702c5SYu Xiangning 	case T_UNITDATA_IND: {
17220f1702c5SYu Xiangning 		void *addr;
17230f1702c5SYu Xiangning 		t_uscalar_t addrlen;
17240f1702c5SYu Xiangning 		void *abuf;
17250f1702c5SYu Xiangning 		t_uscalar_t optlen;
17260f1702c5SYu Xiangning 		void *opt;
17270f1702c5SYu Xiangning 
17280f1702c5SYu Xiangning 		if (namelen != 0) {
17290f1702c5SYu Xiangning 			/* Caller wants source address */
17300f1702c5SYu Xiangning 			addrlen = tpr->unitdata_ind.SRC_length;
17310f1702c5SYu Xiangning 			addr = sogetoff(mctlp, tpr->unitdata_ind.SRC_offset,
17320f1702c5SYu Xiangning 			    addrlen, 1);
17330f1702c5SYu Xiangning 			if (addr == NULL) {
17340f1702c5SYu Xiangning 				freemsg(mctlp);
17350f1702c5SYu Xiangning 				error = EPROTO;
17360f1702c5SYu Xiangning 				eprintsoline(so, error);
17370f1702c5SYu Xiangning 				goto out;
17380f1702c5SYu Xiangning 			}
17390f1702c5SYu Xiangning 			ASSERT(so->so_family != AF_UNIX);
17400f1702c5SYu Xiangning 		}
17410f1702c5SYu Xiangning 		optlen = tpr->unitdata_ind.OPT_length;
17420f1702c5SYu Xiangning 		if (optlen != 0) {
17430f1702c5SYu Xiangning 			t_uscalar_t ncontrollen;
17440f1702c5SYu Xiangning 
17450f1702c5SYu Xiangning 			/*
17460f1702c5SYu Xiangning 			 * Extract any source address option.
17470f1702c5SYu Xiangning 			 * Determine how large cmsg buffer is needed.
17480f1702c5SYu Xiangning 			 */
17490f1702c5SYu Xiangning 			opt = sogetoff(mctlp, tpr->unitdata_ind.OPT_offset,
17500f1702c5SYu Xiangning 			    optlen, __TPI_ALIGN_SIZE);
17510f1702c5SYu Xiangning 
17520f1702c5SYu Xiangning 			if (opt == NULL) {
17530f1702c5SYu Xiangning 				freemsg(mctlp);
17540f1702c5SYu Xiangning 				error = EPROTO;
17550f1702c5SYu Xiangning 				eprintsoline(so, error);
17560f1702c5SYu Xiangning 				goto out;
17570f1702c5SYu Xiangning 			}
17580f1702c5SYu Xiangning 			if (so->so_family == AF_UNIX)
17590f1702c5SYu Xiangning 				so_getopt_srcaddr(opt, optlen, &addr, &addrlen);
17600f1702c5SYu Xiangning 			ncontrollen = so_cmsglen(mctlp, opt, optlen,
17610f1702c5SYu Xiangning 			    !(flags & MSG_XPG4_2));
17620f1702c5SYu Xiangning 			if (controllen != 0)
17630f1702c5SYu Xiangning 				controllen = ncontrollen;
17640f1702c5SYu Xiangning 			else if (ncontrollen != 0)
17650f1702c5SYu Xiangning 				msg->msg_flags |= MSG_CTRUNC;
17660f1702c5SYu Xiangning 		} else {
17670f1702c5SYu Xiangning 			controllen = 0;
17680f1702c5SYu Xiangning 		}
17690f1702c5SYu Xiangning 
17700f1702c5SYu Xiangning 		if (namelen != 0) {
17710f1702c5SYu Xiangning 			/*
17720f1702c5SYu Xiangning 			 * Return address to caller.
17730f1702c5SYu Xiangning 			 * Caller handles truncation if length
17740f1702c5SYu Xiangning 			 * exceeds msg_namelen.
17750f1702c5SYu Xiangning 			 * NOTE: AF_UNIX NUL termination is ensured by
17760f1702c5SYu Xiangning 			 * the sender's copyin_name().
17770f1702c5SYu Xiangning 			 */
17780f1702c5SYu Xiangning 			abuf = kmem_alloc(addrlen, KM_SLEEP);
17790f1702c5SYu Xiangning 
17800f1702c5SYu Xiangning 			bcopy(addr, abuf, addrlen);
17810f1702c5SYu Xiangning 			msg->msg_name = abuf;
17820f1702c5SYu Xiangning 			msg->msg_namelen = addrlen;
17830f1702c5SYu Xiangning 		}
17840f1702c5SYu Xiangning 
17850f1702c5SYu Xiangning 		if (controllen != 0) {
17860f1702c5SYu Xiangning 			/*
17870f1702c5SYu Xiangning 			 * Return control msg to caller.
17880f1702c5SYu Xiangning 			 * Caller handles truncation if length
17890f1702c5SYu Xiangning 			 * exceeds msg_controllen.
17900f1702c5SYu Xiangning 			 */
17910f1702c5SYu Xiangning 			control = kmem_zalloc(controllen, KM_SLEEP);
17920f1702c5SYu Xiangning 
17930f1702c5SYu Xiangning 			error = so_opt2cmsg(mctlp, opt, optlen,
17940f1702c5SYu Xiangning 			    !(flags & MSG_XPG4_2), control, controllen);
17950f1702c5SYu Xiangning 			if (error) {
17960f1702c5SYu Xiangning 				freemsg(mctlp);
17970f1702c5SYu Xiangning 				if (msg->msg_namelen != 0)
17980f1702c5SYu Xiangning 					kmem_free(msg->msg_name,
17990f1702c5SYu Xiangning 					    msg->msg_namelen);
18000f1702c5SYu Xiangning 				kmem_free(control, controllen);
18010f1702c5SYu Xiangning 				eprintsoline(so, error);
18020f1702c5SYu Xiangning 				goto out;
18030f1702c5SYu Xiangning 			}
18040f1702c5SYu Xiangning 			msg->msg_control = control;
18050f1702c5SYu Xiangning 			msg->msg_controllen = controllen;
18060f1702c5SYu Xiangning 		}
18070f1702c5SYu Xiangning 
18080f1702c5SYu Xiangning 		freemsg(mctlp);
18090f1702c5SYu Xiangning 		goto out;
18100f1702c5SYu Xiangning 	}
18110f1702c5SYu Xiangning 	case T_OPTDATA_IND: {
18120f1702c5SYu Xiangning 		struct T_optdata_req *tdr;
18130f1702c5SYu Xiangning 		void *opt;
18140f1702c5SYu Xiangning 		t_uscalar_t optlen;
18150f1702c5SYu Xiangning 
18160f1702c5SYu Xiangning 		tdr = (struct T_optdata_req *)mctlp->b_rptr;
18170f1702c5SYu Xiangning 		optlen = tdr->OPT_length;
18180f1702c5SYu Xiangning 		if (optlen != 0) {
18190f1702c5SYu Xiangning 			t_uscalar_t ncontrollen;
18200f1702c5SYu Xiangning 			/*
18210f1702c5SYu Xiangning 			 * Determine how large cmsg buffer is needed.
18220f1702c5SYu Xiangning 			 */
18230f1702c5SYu Xiangning 			opt = sogetoff(mctlp,
18240f1702c5SYu Xiangning 			    tpr->optdata_ind.OPT_offset, optlen,
18250f1702c5SYu Xiangning 			    __TPI_ALIGN_SIZE);
18260f1702c5SYu Xiangning 
18270f1702c5SYu Xiangning 			if (opt == NULL) {
18280f1702c5SYu Xiangning 				freemsg(mctlp);
18290f1702c5SYu Xiangning 				error = EPROTO;
18300f1702c5SYu Xiangning 				eprintsoline(so, error);
18310f1702c5SYu Xiangning 				goto out;
18320f1702c5SYu Xiangning 			}
18330f1702c5SYu Xiangning 
18340f1702c5SYu Xiangning 			ncontrollen = so_cmsglen(mctlp, opt, optlen,
18350f1702c5SYu Xiangning 			    !(flags & MSG_XPG4_2));
18360f1702c5SYu Xiangning 			if (controllen != 0)
18370f1702c5SYu Xiangning 				controllen = ncontrollen;
18380f1702c5SYu Xiangning 			else if (ncontrollen != 0)
18390f1702c5SYu Xiangning 				msg->msg_flags |= MSG_CTRUNC;
18400f1702c5SYu Xiangning 		} else {
18410f1702c5SYu Xiangning 			controllen = 0;
18420f1702c5SYu Xiangning 		}
18430f1702c5SYu Xiangning 
18440f1702c5SYu Xiangning 		if (controllen != 0) {
18450f1702c5SYu Xiangning 			/*
18460f1702c5SYu Xiangning 			 * Return control msg to caller.
18470f1702c5SYu Xiangning 			 * Caller handles truncation if length
18480f1702c5SYu Xiangning 			 * exceeds msg_controllen.
18490f1702c5SYu Xiangning 			 */
18500f1702c5SYu Xiangning 			control = kmem_zalloc(controllen, KM_SLEEP);
18510f1702c5SYu Xiangning 
18520f1702c5SYu Xiangning 			error = so_opt2cmsg(mctlp, opt, optlen,
18530f1702c5SYu Xiangning 			    !(flags & MSG_XPG4_2), control, controllen);
18540f1702c5SYu Xiangning 			if (error) {
18550f1702c5SYu Xiangning 				freemsg(mctlp);
18560f1702c5SYu Xiangning 				kmem_free(control, controllen);
18570f1702c5SYu Xiangning 				eprintsoline(so, error);
18580f1702c5SYu Xiangning 				goto out;
18590f1702c5SYu Xiangning 			}
18600f1702c5SYu Xiangning 			msg->msg_control = control;
18610f1702c5SYu Xiangning 			msg->msg_controllen = controllen;
18620f1702c5SYu Xiangning 		}
18630f1702c5SYu Xiangning 
18640f1702c5SYu Xiangning 		/*
18650f1702c5SYu Xiangning 		 * Set msg_flags to MSG_EOR based on
18660f1702c5SYu Xiangning 		 * DATA_flag and MOREDATA.
18670f1702c5SYu Xiangning 		 */
18680f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
18690f1702c5SYu Xiangning 		so->so_state &= ~SS_SAVEDEOR;
18700f1702c5SYu Xiangning 		if (!(tpr->data_ind.MORE_flag & 1)) {
18710f1702c5SYu Xiangning 			if (!(rval.r_val1 & MOREDATA))
18720f1702c5SYu Xiangning 				msg->msg_flags |= MSG_EOR;
18730f1702c5SYu Xiangning 			else
18740f1702c5SYu Xiangning 				so->so_state |= SS_SAVEDEOR;
18750f1702c5SYu Xiangning 		}
18760f1702c5SYu Xiangning 		freemsg(mctlp);
18770f1702c5SYu Xiangning 		/*
18780f1702c5SYu Xiangning 		 * If some data was received (i.e. not EOF) and the
18790f1702c5SYu Xiangning 		 * read/recv* has not been satisfied wait for some more.
18800f1702c5SYu Xiangning 		 * Not possible to wait if control info was received.
18810f1702c5SYu Xiangning 		 */
18820f1702c5SYu Xiangning 		if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) &&
18830f1702c5SYu Xiangning 		    controllen == 0 &&
18840f1702c5SYu Xiangning 		    uiop->uio_resid != saved_resid && uiop->uio_resid > 0) {
18850f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
18868591a19aSAnders Persson 			flags |= MSG_NOMARK;
18870f1702c5SYu Xiangning 			goto retry;
18880f1702c5SYu Xiangning 		}
18890f1702c5SYu Xiangning 		goto out_locked;
18900f1702c5SYu Xiangning 	}
18910f1702c5SYu Xiangning 	default:
18920f1702c5SYu Xiangning 		cmn_err(CE_CONT, "so_recvmsg bad type %x \n",
18930f1702c5SYu Xiangning 		    tpr->type);
18940f1702c5SYu Xiangning 		freemsg(mctlp);
18950f1702c5SYu Xiangning 		error = EPROTO;
18960f1702c5SYu Xiangning 		ASSERT(0);
18970f1702c5SYu Xiangning 	}
18980f1702c5SYu Xiangning out:
18990f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
19000f1702c5SYu Xiangning out_locked:
19010f1702c5SYu Xiangning 	ret = sod_rcv_done(so, suiop, uiop);
19020f1702c5SYu Xiangning 	if (ret != 0 && error == 0)
19030f1702c5SYu Xiangning 		error = ret;
19040f1702c5SYu Xiangning 
19050f1702c5SYu Xiangning 	so_unlock_read(so);	/* Clear SOREADLOCKED */
19060f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
19070f1702c5SYu Xiangning 
19080f1702c5SYu Xiangning 	SO_UNBLOCK_FALLBACK(so);
19090f1702c5SYu Xiangning 
19100f1702c5SYu Xiangning 	return (error);
19110f1702c5SYu Xiangning }
19120f1702c5SYu Xiangning 
19130f1702c5SYu Xiangning sonodeops_t so_sonodeops = {
19140f1702c5SYu Xiangning 	so_init,		/* sop_init	*/
19150f1702c5SYu Xiangning 	so_accept,		/* sop_accept   */
19160f1702c5SYu Xiangning 	so_bind,		/* sop_bind	*/
19170f1702c5SYu Xiangning 	so_listen,		/* sop_listen   */
19180f1702c5SYu Xiangning 	so_connect,		/* sop_connect  */
19190f1702c5SYu Xiangning 	so_recvmsg,		/* sop_recvmsg  */
19200f1702c5SYu Xiangning 	so_sendmsg,		/* sop_sendmsg  */
19210f1702c5SYu Xiangning 	so_sendmblk,		/* sop_sendmblk */
19220f1702c5SYu Xiangning 	so_getpeername,		/* sop_getpeername */
19230f1702c5SYu Xiangning 	so_getsockname,		/* sop_getsockname */
19240f1702c5SYu Xiangning 	so_shutdown,		/* sop_shutdown */
19250f1702c5SYu Xiangning 	so_getsockopt,		/* sop_getsockopt */
19260f1702c5SYu Xiangning 	so_setsockopt,		/* sop_setsockopt */
19270f1702c5SYu Xiangning 	so_ioctl,		/* sop_ioctl    */
19280f1702c5SYu Xiangning 	so_poll,		/* sop_poll	*/
19290f1702c5SYu Xiangning 	so_close,		/* sop_close */
19300f1702c5SYu Xiangning };
19310f1702c5SYu Xiangning 
19320f1702c5SYu Xiangning sock_upcalls_t so_upcalls = {
19330f1702c5SYu Xiangning 	so_newconn,
19340f1702c5SYu Xiangning 	so_connected,
19350f1702c5SYu Xiangning 	so_disconnected,
19360f1702c5SYu Xiangning 	so_opctl,
19370f1702c5SYu Xiangning 	so_queue_msg,
19380f1702c5SYu Xiangning 	so_set_prop,
19390f1702c5SYu Xiangning 	so_txq_full,
19400f1702c5SYu Xiangning 	so_signal_oob,
19410f1702c5SYu Xiangning 	so_zcopy_notify,
19423e95bd4aSAnders Persson 	so_set_error,
19433e95bd4aSAnders Persson 	so_closed
19440f1702c5SYu Xiangning };
1945