xref: /titanic_51/usr/src/uts/common/inet/sockmods/socksdp.c (revision 3e95bd4ab92abca814bd28e854607d1975c7dc88)
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 /*
23*3e95bd4aSAnders Persson  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
240f1702c5SYu Xiangning  */
250f1702c5SYu Xiangning 
260f1702c5SYu Xiangning #include <sys/types.h>
270f1702c5SYu Xiangning #include <sys/t_lock.h>
280f1702c5SYu Xiangning #include <sys/param.h>
290f1702c5SYu Xiangning #include <sys/systm.h>
300f1702c5SYu Xiangning #include <sys/buf.h>
310f1702c5SYu Xiangning #include <sys/vfs.h>
320f1702c5SYu Xiangning #include <sys/vnode.h>
330f1702c5SYu Xiangning #include <sys/debug.h>
340f1702c5SYu Xiangning #include <sys/errno.h>
350f1702c5SYu Xiangning #include <sys/stropts.h>
360f1702c5SYu Xiangning #include <sys/cmn_err.h>
370f1702c5SYu Xiangning #include <sys/sysmacros.h>
38634e26ecSCasper H.S. Dik #include <sys/policy.h>
390f1702c5SYu Xiangning 
400f1702c5SYu Xiangning #include <sys/filio.h>
410f1702c5SYu Xiangning #include <sys/sockio.h>
420f1702c5SYu Xiangning 
430f1702c5SYu Xiangning #include <sys/project.h>
440f1702c5SYu Xiangning #include <sys/tihdr.h>
450f1702c5SYu Xiangning #include <sys/strsubr.h>
460f1702c5SYu Xiangning 
470f1702c5SYu Xiangning #include <sys/socket.h>
480f1702c5SYu Xiangning #include <sys/socketvar.h>
490f1702c5SYu Xiangning #include <sys/strsun.h>
500f1702c5SYu Xiangning 
510f1702c5SYu Xiangning #include <sys/tsol/label.h>
520f1702c5SYu Xiangning 
530f1702c5SYu Xiangning #include <inet/sdp_itf.h>
540f1702c5SYu Xiangning #include "socksdp.h"
550f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
560f1702c5SYu Xiangning 
570f1702c5SYu Xiangning /*
580f1702c5SYu Xiangning  * SDP sockfs sonode operations
590f1702c5SYu Xiangning  */
600f1702c5SYu Xiangning static int sosdp_init(struct sonode *, struct sonode *, struct cred *, int);
610f1702c5SYu Xiangning static int sosdp_accept(struct sonode *, int, struct cred *, struct sonode **);
620f1702c5SYu Xiangning static int sosdp_bind(struct sonode *, struct sockaddr *, socklen_t, int,
630f1702c5SYu Xiangning     struct cred *);
640f1702c5SYu Xiangning static int sosdp_listen(struct sonode *, int, struct cred *);
65*3e95bd4aSAnders Persson static int sosdp_connect(struct sonode *, struct sockaddr *, socklen_t,
660f1702c5SYu Xiangning     int, int, struct cred *);
670f1702c5SYu Xiangning static int sosdp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *,
680f1702c5SYu Xiangning     struct cred *);
690f1702c5SYu Xiangning static int sosdp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
700f1702c5SYu Xiangning     struct cred *);
710f1702c5SYu Xiangning static int sosdp_getpeername(struct sonode *, struct sockaddr *, socklen_t *,
720f1702c5SYu Xiangning     boolean_t, struct cred *);
730f1702c5SYu Xiangning static int sosdp_getsockname(struct sonode *, struct sockaddr *, socklen_t *,
740f1702c5SYu Xiangning     struct cred *);
750f1702c5SYu Xiangning static int sosdp_shutdown(struct sonode *, int, struct cred *);
760f1702c5SYu Xiangning static int sosdp_getsockopt(struct sonode *, int, int, void *, socklen_t *,
770f1702c5SYu Xiangning     int, struct cred *);
780f1702c5SYu Xiangning static int sosdp_setsockopt(struct sonode *, int, int, const void *,
790f1702c5SYu Xiangning     socklen_t, struct cred *);
800f1702c5SYu Xiangning static int sosdp_ioctl(struct sonode *, int, intptr_t, int, struct cred *,
810f1702c5SYu Xiangning     int32_t *);
820f1702c5SYu Xiangning static int sosdp_poll(struct sonode *, short, int, short *,
830f1702c5SYu Xiangning     struct pollhead **);
840f1702c5SYu Xiangning static int sosdp_close(struct sonode *, int, struct cred *);
850f1702c5SYu Xiangning void sosdp_fini(struct sonode *, struct cred *);
860f1702c5SYu Xiangning 
870f1702c5SYu Xiangning 
880f1702c5SYu Xiangning /*
890f1702c5SYu Xiangning  * Socket upcalls
900f1702c5SYu Xiangning  */
910f1702c5SYu Xiangning static void *sdp_sock_newconn(void *parenthandle, void *connind);
920f1702c5SYu Xiangning static void sdp_sock_connected(void *handle);
930f1702c5SYu Xiangning static void sdp_sock_disconnected(void *handle, int error);
940f1702c5SYu Xiangning static void sdp_sock_connfail(void *handle, int error);
950f1702c5SYu Xiangning static int sdp_sock_recv(void *handle, mblk_t *mp, int flags);
960f1702c5SYu Xiangning static void sdp_sock_xmitted(void *handle, int txqueued);
970f1702c5SYu Xiangning static void sdp_sock_urgdata(void *handle);
980f1702c5SYu Xiangning static void sdp_sock_ordrel(void *handle);
990f1702c5SYu Xiangning 
1000f1702c5SYu Xiangning sonodeops_t sosdp_sonodeops = {
1010f1702c5SYu Xiangning 	sosdp_init,			/* sop_init	*/
1020f1702c5SYu Xiangning 	sosdp_accept,			/* sop_accept	*/
1030f1702c5SYu Xiangning 	sosdp_bind,			/* sop_bind	*/
1040f1702c5SYu Xiangning 	sosdp_listen,			/* sop_listen	*/
1050f1702c5SYu Xiangning 	sosdp_connect,			/* sop_connect	*/
1060f1702c5SYu Xiangning 	sosdp_recvmsg,			/* sop_recvmsg	*/
1070f1702c5SYu Xiangning 	sosdp_sendmsg,			/* sop_sendmsg	*/
1080f1702c5SYu Xiangning 	so_sendmblk_notsupp,		/* sop_sendmblk */
1090f1702c5SYu Xiangning 	sosdp_getpeername,		/* sop_getpeername */
1100f1702c5SYu Xiangning 	sosdp_getsockname,		/* sop_getsockname */
1110f1702c5SYu Xiangning 	sosdp_shutdown,			/* sop_shutdown */
1120f1702c5SYu Xiangning 	sosdp_getsockopt,		/* sop_getsockopt */
1130f1702c5SYu Xiangning 	sosdp_setsockopt,		/* sop_setsockopt */
1140f1702c5SYu Xiangning 	sosdp_ioctl,			/* sop_ioctl	*/
1150f1702c5SYu Xiangning 	sosdp_poll,			/* sop_poll	*/
1160f1702c5SYu Xiangning 	sosdp_close,			/* sop_close	*/
1170f1702c5SYu Xiangning };
1180f1702c5SYu Xiangning 
1190f1702c5SYu Xiangning sdp_upcalls_t sosdp_sock_upcalls = {
1200f1702c5SYu Xiangning 	sdp_sock_newconn,
1210f1702c5SYu Xiangning 	sdp_sock_connected,
1220f1702c5SYu Xiangning 	sdp_sock_disconnected,
1230f1702c5SYu Xiangning 	sdp_sock_connfail,
1240f1702c5SYu Xiangning 	sdp_sock_recv,
1250f1702c5SYu Xiangning 	sdp_sock_xmitted,
1260f1702c5SYu Xiangning 	sdp_sock_urgdata,
1270f1702c5SYu Xiangning 	sdp_sock_ordrel,
1280f1702c5SYu Xiangning };
1290f1702c5SYu Xiangning 
1300f1702c5SYu Xiangning /* ARGSUSED */
1310f1702c5SYu Xiangning static int
1320f1702c5SYu Xiangning sosdp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1330f1702c5SYu Xiangning {
1340f1702c5SYu Xiangning 	int error = 0;
1350f1702c5SYu Xiangning 	sdp_sockbuf_limits_t sbl;
1360f1702c5SYu Xiangning 	sdp_upcalls_t *upcalls;
1370f1702c5SYu Xiangning 
1380f1702c5SYu Xiangning 	if (pso != NULL) {
1390f1702c5SYu Xiangning 		/* passive open, just inherit settings from parent */
1400f1702c5SYu Xiangning 
1410f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
1420f1702c5SYu Xiangning 
1430f1702c5SYu Xiangning 		so->so_state |= (SS_ISBOUND | SS_ISCONNECTED |
1440f1702c5SYu Xiangning 		    (pso->so_state & SS_ASYNC));
1450f1702c5SYu Xiangning 		sosdp_so_inherit(pso, so);
1460f1702c5SYu Xiangning 		so->so_proto_props = pso->so_proto_props;
1470f1702c5SYu Xiangning 
1480f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1490f1702c5SYu Xiangning 
1500f1702c5SYu Xiangning 		return (0);
1510f1702c5SYu Xiangning 	}
1520f1702c5SYu Xiangning 
153634e26ecSCasper H.S. Dik 	if ((error = secpolicy_basic_net_access(cr)) != 0)
154634e26ecSCasper H.S. Dik 		return (error);
155634e26ecSCasper H.S. Dik 
1560f1702c5SYu Xiangning 	upcalls = &sosdp_sock_upcalls;
1570f1702c5SYu Xiangning 
1580f1702c5SYu Xiangning 	so->so_proto_handle = (sock_lower_handle_t)sdp_create(so, NULL,
1590f1702c5SYu Xiangning 	    so->so_family, SDP_CAN_BLOCK, upcalls, &sbl, cr, &error);
1600f1702c5SYu Xiangning 	if (so->so_proto_handle == NULL)
1610f1702c5SYu Xiangning 		return (ENOMEM);
1620f1702c5SYu Xiangning 
1630f1702c5SYu Xiangning 	so->so_rcvbuf = sbl.sbl_rxbuf;
1640f1702c5SYu Xiangning 	so->so_rcvlowat = sbl.sbl_rxlowat;
1650f1702c5SYu Xiangning 	so->so_sndbuf = sbl.sbl_txbuf;
1660f1702c5SYu Xiangning 	so->so_sndlowat = sbl.sbl_txlowat;
1670f1702c5SYu Xiangning 
1680f1702c5SYu Xiangning 	return (error);
1690f1702c5SYu Xiangning }
1700f1702c5SYu Xiangning 
1710f1702c5SYu Xiangning /*
1720f1702c5SYu Xiangning  * Accept incoming connection.
1730f1702c5SYu Xiangning  */
1740f1702c5SYu Xiangning /* ARGSUSED */
1750f1702c5SYu Xiangning static int
1760f1702c5SYu Xiangning sosdp_accept(struct sonode *lso, int fflag, struct cred *cr,
1770f1702c5SYu Xiangning     struct sonode **nsop)
1780f1702c5SYu Xiangning {
1790f1702c5SYu Xiangning 	int error = 0;
1800f1702c5SYu Xiangning 	struct sonode *nso;
1810f1702c5SYu Xiangning 
1820f1702c5SYu Xiangning 	dprint(3, ("sosdp_accept: so:%p so_proto_handle:%p", (void *)lso,
1830f1702c5SYu Xiangning 	    (void *)lso->so_proto_handle));
1840f1702c5SYu Xiangning 
1850f1702c5SYu Xiangning 	if (!(lso->so_state & SS_ACCEPTCONN)) {
1860f1702c5SYu Xiangning 		/*
1870f1702c5SYu Xiangning 		 * Not a listen socket.
1880f1702c5SYu Xiangning 		 */
1890f1702c5SYu Xiangning 		eprintsoline(lso, EINVAL);
1900f1702c5SYu Xiangning 		return (EINVAL);
1910f1702c5SYu Xiangning 	}
1920f1702c5SYu Xiangning 	/*
1930f1702c5SYu Xiangning 	 * Returns right away if socket is nonblocking.
1940f1702c5SYu Xiangning 	 */
1950f1702c5SYu Xiangning 	error = so_acceptq_dequeue(lso, (fflag & (FNONBLOCK|FNDELAY)), &nso);
1960f1702c5SYu Xiangning 	if (error != 0) {
1970f1702c5SYu Xiangning 		eprintsoline(lso, error);
1980f1702c5SYu Xiangning 		dprint(4, ("sosdp_accept: failed %d:lso:%p so_proto_handle:%p",
1990f1702c5SYu Xiangning 		    error, (void *)lso, (void *)lso->so_proto_handle));
2000f1702c5SYu Xiangning 		return (error);
2010f1702c5SYu Xiangning 	}
2020f1702c5SYu Xiangning 
2030f1702c5SYu Xiangning 	dprint(2, ("sosdp_accept: new %p\n", (void *)nso));
2040f1702c5SYu Xiangning 	*nsop = nso;
2050f1702c5SYu Xiangning 
2060f1702c5SYu Xiangning 	return (0);
2070f1702c5SYu Xiangning }
2080f1702c5SYu Xiangning 
2090f1702c5SYu Xiangning /*
2100f1702c5SYu Xiangning  * Bind local endpoint.
2110f1702c5SYu Xiangning  */
2120f1702c5SYu Xiangning /* ARGSUSED */
2130f1702c5SYu Xiangning int
2140f1702c5SYu Xiangning sosdp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
2150f1702c5SYu Xiangning     int flags, struct cred *cr)
2160f1702c5SYu Xiangning {
2170f1702c5SYu Xiangning 	int	error = 0;
2180f1702c5SYu Xiangning 
2190f1702c5SYu Xiangning 	if (!(flags & _SOBIND_LOCK_HELD)) {
2200f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
2210f1702c5SYu Xiangning 		so_lock_single(so);	/* Set SOLOCKED */
2220f1702c5SYu Xiangning 	} else {
2230f1702c5SYu Xiangning 		ASSERT(MUTEX_HELD(&so->so_lock));
2240f1702c5SYu Xiangning 		ASSERT(so->so_flag & SOLOCKED);
2250f1702c5SYu Xiangning 	}
2260f1702c5SYu Xiangning 
2270f1702c5SYu Xiangning 	if ((so->so_state & SS_ISBOUND) || name == NULL || namelen == 0) {
2280f1702c5SYu Xiangning 		/*
2290f1702c5SYu Xiangning 		 * Multiple binds not allowed for any SDP socket.
2300f1702c5SYu Xiangning 		 * Also binding with null address is not supported.
2310f1702c5SYu Xiangning 		 */
2320f1702c5SYu Xiangning 		error = EINVAL;
2330f1702c5SYu Xiangning 		eprintsoline(so, error);
2340f1702c5SYu Xiangning 		goto done;
2350f1702c5SYu Xiangning 	}
2360f1702c5SYu Xiangning 
2370f1702c5SYu Xiangning 	/*
2380f1702c5SYu Xiangning 	 * X/Open requires this check
2390f1702c5SYu Xiangning 	 */
2400f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE) {
2410f1702c5SYu Xiangning 		error = EINVAL;
2420f1702c5SYu Xiangning 		goto done;
2430f1702c5SYu Xiangning 	}
2440f1702c5SYu Xiangning 
2450f1702c5SYu Xiangning 	/*
2460f1702c5SYu Xiangning 	 * Protocol module does address family checks
2470f1702c5SYu Xiangning 	 */
2480f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
2490f1702c5SYu Xiangning 
2500f1702c5SYu Xiangning 	error = sdp_bind((struct sdp_conn_struct_t *)so->so_proto_handle,
2510f1702c5SYu Xiangning 	    name, namelen);
2520f1702c5SYu Xiangning 
2530f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
2540f1702c5SYu Xiangning 
2550f1702c5SYu Xiangning 	if (error == 0) {
2560f1702c5SYu Xiangning 		so->so_state |= SS_ISBOUND;
2570f1702c5SYu Xiangning 	} else {
2580f1702c5SYu Xiangning 		eprintsoline(so, error);
2590f1702c5SYu Xiangning 	}
2600f1702c5SYu Xiangning done:
2610f1702c5SYu Xiangning 	if (!(flags & _SOBIND_LOCK_HELD)) {
2620f1702c5SYu Xiangning 		so_unlock_single(so, SOLOCKED);
2630f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2640f1702c5SYu Xiangning 	} else {
2650f1702c5SYu Xiangning 		/* If the caller held the lock don't release it here */
2660f1702c5SYu Xiangning 		ASSERT(MUTEX_HELD(&so->so_lock));
2670f1702c5SYu Xiangning 		ASSERT(so->so_flag & SOLOCKED);
2680f1702c5SYu Xiangning 	}
2690f1702c5SYu Xiangning 	return (error);
2700f1702c5SYu Xiangning }
2710f1702c5SYu Xiangning 
2720f1702c5SYu Xiangning /*
2730f1702c5SYu Xiangning  * Turn socket into a listen socket.
2740f1702c5SYu Xiangning  */
2750f1702c5SYu Xiangning /* ARGSUSED */
2760f1702c5SYu Xiangning static int
2770f1702c5SYu Xiangning sosdp_listen(struct sonode *so, int backlog, struct cred *cr)
2780f1702c5SYu Xiangning {
2790f1702c5SYu Xiangning 	int error = 0;
2800f1702c5SYu Xiangning 
2810f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
2820f1702c5SYu Xiangning 	so_lock_single(so);
2830f1702c5SYu Xiangning 
2840f1702c5SYu Xiangning 	/*
2850f1702c5SYu Xiangning 	 * If this socket is trying to do connect, or if it has
2860f1702c5SYu Xiangning 	 * been connected, disallow.
2870f1702c5SYu Xiangning 	 */
2880f1702c5SYu Xiangning 	if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED |
2890f1702c5SYu Xiangning 	    SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) {
2900f1702c5SYu Xiangning 		error = EINVAL;
2910f1702c5SYu Xiangning 		eprintsoline(so, EINVAL);
2920f1702c5SYu Xiangning 		goto done;
2930f1702c5SYu Xiangning 	}
2940f1702c5SYu Xiangning 	/*
2950f1702c5SYu Xiangning 	 * If listen() is only called to change backlog, we don't
2960f1702c5SYu Xiangning 	 * need to notify protocol module.
2970f1702c5SYu Xiangning 	 */
2980f1702c5SYu Xiangning 	if (so->so_state & SS_ACCEPTCONN) {
2990f1702c5SYu Xiangning 		so->so_backlog = backlog;
3000f1702c5SYu Xiangning 		goto done;
3010f1702c5SYu Xiangning 	}
3020f1702c5SYu Xiangning 
3030f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3040f1702c5SYu Xiangning 
3050f1702c5SYu Xiangning 	error = sdp_listen((struct sdp_conn_struct_t *)so->so_proto_handle,
3060f1702c5SYu Xiangning 	    backlog);
3070f1702c5SYu Xiangning 
3080f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3090f1702c5SYu Xiangning 	if (error == 0) {
3100f1702c5SYu Xiangning 		so->so_state |= (SS_ACCEPTCONN | SS_ISBOUND);
3110f1702c5SYu Xiangning 		so->so_backlog = backlog;
3120f1702c5SYu Xiangning 	} else {
3130f1702c5SYu Xiangning 		eprintsoline(so, error);
3140f1702c5SYu Xiangning 	}
3150f1702c5SYu Xiangning done:
3160f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
3170f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3180f1702c5SYu Xiangning 
3190f1702c5SYu Xiangning 	return (error);
3200f1702c5SYu Xiangning }
3210f1702c5SYu Xiangning 
3220f1702c5SYu Xiangning /*
3230f1702c5SYu Xiangning  * Active open.
3240f1702c5SYu Xiangning  */
3250f1702c5SYu Xiangning /*ARGSUSED*/
3260f1702c5SYu Xiangning static int
327*3e95bd4aSAnders Persson sosdp_connect(struct sonode *so, struct sockaddr *name,
3280f1702c5SYu Xiangning     socklen_t namelen, int fflag, int flags, struct cred *cr)
3290f1702c5SYu Xiangning {
3300f1702c5SYu Xiangning 	int error = 0;
3310f1702c5SYu Xiangning 
3320f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3330f1702c5SYu Xiangning 	so_lock_single(so);
3340f1702c5SYu Xiangning 
3350f1702c5SYu Xiangning 	/*
3360f1702c5SYu Xiangning 	 * Can't connect() after listen(), or if the socket is already
3370f1702c5SYu Xiangning 	 * connected.
3380f1702c5SYu Xiangning 	 */
3390f1702c5SYu Xiangning 	if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) {
3400f1702c5SYu Xiangning 		if (so->so_state & SS_ISCONNECTED) {
3410f1702c5SYu Xiangning 			error = EISCONN;
3420f1702c5SYu Xiangning 		} else if (so->so_state & SS_ISCONNECTING) {
3430f1702c5SYu Xiangning 			error = EALREADY;
3440f1702c5SYu Xiangning 		} else {
3450f1702c5SYu Xiangning 			error = EOPNOTSUPP;
3460f1702c5SYu Xiangning 		}
3470f1702c5SYu Xiangning 		eprintsoline(so, error);
3480f1702c5SYu Xiangning 		goto done;
3490f1702c5SYu Xiangning 	}
3500f1702c5SYu Xiangning 
3510f1702c5SYu Xiangning 	/*
3520f1702c5SYu Xiangning 	 * check for failure of an earlier call
3530f1702c5SYu Xiangning 	 */
3540f1702c5SYu Xiangning 	if (so->so_error != 0) {
3550f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
3560f1702c5SYu Xiangning 		eprintsoline(so, error);
3570f1702c5SYu Xiangning 		goto done;
3580f1702c5SYu Xiangning 	}
3590f1702c5SYu Xiangning 
3600f1702c5SYu Xiangning 	/*
3610f1702c5SYu Xiangning 	 * Connection is closing, or closed, don't allow reconnect.
3620f1702c5SYu Xiangning 	 * TCP allows this to proceed, but the socket remains unwriteable.
3630f1702c5SYu Xiangning 	 * BSD returns EINVAL.
3640f1702c5SYu Xiangning 	 */
3650f1702c5SYu Xiangning 	if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE|
3660f1702c5SYu Xiangning 	    SS_CANTSENDMORE)) {
3670f1702c5SYu Xiangning 		error = EINVAL;
3680f1702c5SYu Xiangning 		eprintsoline(so, error);
3690f1702c5SYu Xiangning 		goto done;
3700f1702c5SYu Xiangning 	}
3710f1702c5SYu Xiangning 	if (name == NULL || namelen == 0) {
3720f1702c5SYu Xiangning 		eprintsoline(so, EINVAL);
3730f1702c5SYu Xiangning 		goto done;
3740f1702c5SYu Xiangning 	}
3750f1702c5SYu Xiangning 	soisconnecting(so);
3760f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3770f1702c5SYu Xiangning 
3780f1702c5SYu Xiangning 	error = sdp_connect((struct sdp_conn_struct_t *)so->so_proto_handle,
3790f1702c5SYu Xiangning 	    name, namelen);
3800f1702c5SYu Xiangning 
3810f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3820f1702c5SYu Xiangning 	if (error == 0) {
3830f1702c5SYu Xiangning 		/*
3840f1702c5SYu Xiangning 		 * Allow other threads to access the socket
3850f1702c5SYu Xiangning 		 */
3860f1702c5SYu Xiangning 		error = sowaitconnected(so, fflag, 0);
3870f1702c5SYu Xiangning 		dprint(4,
3880f1702c5SYu Xiangning 		    ("sosdp_connect: wait on so:%p "
3890f1702c5SYu Xiangning 		    "so_proto_handle:%p failed:%d",
3900f1702c5SYu Xiangning 		    (void *)so,	(void *)so->so_proto_handle, error));
3910f1702c5SYu Xiangning 	}
3920f1702c5SYu Xiangning 
3930f1702c5SYu Xiangning 	switch (error) {
3940f1702c5SYu Xiangning 	case 0:
3950f1702c5SYu Xiangning 	case EINPROGRESS:
3960f1702c5SYu Xiangning 	case EALREADY:
3970f1702c5SYu Xiangning 	case EINTR:
3980f1702c5SYu Xiangning 		/* Non-fatal errors */
3990f1702c5SYu Xiangning 		so->so_state |= SS_ISBOUND;
4000f1702c5SYu Xiangning 		break;
4010f1702c5SYu Xiangning 	default:
4020f1702c5SYu Xiangning 		/* clear SS_ISCONNECTING in case it was set */
4030f1702c5SYu Xiangning 		so->so_state &= ~SS_ISCONNECTING;
4040f1702c5SYu Xiangning 		break;
4050f1702c5SYu Xiangning 	}
4060f1702c5SYu Xiangning done:
4070f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
4080f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4090f1702c5SYu Xiangning 	return (error);
4100f1702c5SYu Xiangning }
4110f1702c5SYu Xiangning 
4120f1702c5SYu Xiangning /*
4130f1702c5SYu Xiangning  * Receive data.
4140f1702c5SYu Xiangning  */
4150f1702c5SYu Xiangning /* ARGSUSED */
4160f1702c5SYu Xiangning int
4170f1702c5SYu Xiangning sosdp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4180f1702c5SYu Xiangning     struct cred *cr)
4190f1702c5SYu Xiangning {
4200f1702c5SYu Xiangning 	int flags, error = 0;
4210f1702c5SYu Xiangning 	int size;
4220f1702c5SYu Xiangning 
4230f1702c5SYu Xiangning 	flags = msg->msg_flags;
4240f1702c5SYu Xiangning 	msg->msg_flags = 0;
4250f1702c5SYu Xiangning 
4260f1702c5SYu Xiangning 
4270f1702c5SYu Xiangning 	if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING|
4280f1702c5SYu Xiangning 	    SS_CANTRCVMORE))) {
4290f1702c5SYu Xiangning 		return (ENOTCONN);
4300f1702c5SYu Xiangning 	}
4310f1702c5SYu Xiangning 
4320f1702c5SYu Xiangning 	/*
4330f1702c5SYu Xiangning 	 * flag possibilities:
4340f1702c5SYu Xiangning 	 *
4350f1702c5SYu Xiangning 	 * MSG_PEEK	Don't consume data
4360f1702c5SYu Xiangning 	 * MSG_WAITALL	Wait for full quantity of data (ignored if MSG_PEEK)
4370f1702c5SYu Xiangning 	 * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
4380f1702c5SYu Xiangning 	 *
4390f1702c5SYu Xiangning 	 * MSG_WAITALL can return less than the full buffer if either
4400f1702c5SYu Xiangning 	 *
4410f1702c5SYu Xiangning 	 * 1. we would block and we are non-blocking
4420f1702c5SYu Xiangning 	 * 2. a full message cannot be delivered
4430f1702c5SYu Xiangning 	 *
4440f1702c5SYu Xiangning 	 */
4450f1702c5SYu Xiangning 
4460f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4470f1702c5SYu Xiangning 
4480f1702c5SYu Xiangning 	/*
4490f1702c5SYu Xiangning 	 * Allow just one reader at a time.
4500f1702c5SYu Xiangning 	 */
4510f1702c5SYu Xiangning 	error = so_lock_read_intr(so,
4520f1702c5SYu Xiangning 	    uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
4530f1702c5SYu Xiangning 	if (error != 0) {
4540f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
4550f1702c5SYu Xiangning 		return (error);
4560f1702c5SYu Xiangning 	}
4570f1702c5SYu Xiangning 	size = uiop->uio_resid;
4580f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4590f1702c5SYu Xiangning 
4600f1702c5SYu Xiangning 	if (!(so->so_state & SS_CANTRCVMORE)) {
4610f1702c5SYu Xiangning 		if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) {
4620f1702c5SYu Xiangning 			flags |= MSG_DONTWAIT;
4630f1702c5SYu Xiangning 		}
4640f1702c5SYu Xiangning 		error = sdp_recv(
4650f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle, msg,
4660f1702c5SYu Xiangning 		    size, flags, uiop);
4670f1702c5SYu Xiangning 	} else {
4680f1702c5SYu Xiangning 		msg->msg_controllen = 0;
4690f1702c5SYu Xiangning 		msg->msg_namelen = 0;
4700f1702c5SYu Xiangning 	}
4710f1702c5SYu Xiangning done:
4720f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4730f1702c5SYu Xiangning 	so_unlock_read(so);
4740f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4750f1702c5SYu Xiangning 	return (error);
4760f1702c5SYu Xiangning }
4770f1702c5SYu Xiangning 
4780f1702c5SYu Xiangning /*
4790f1702c5SYu Xiangning  * Send message.
4800f1702c5SYu Xiangning  */
4810f1702c5SYu Xiangning /* ARGSUSED */
4820f1702c5SYu Xiangning static int
4830f1702c5SYu Xiangning sosdp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4840f1702c5SYu Xiangning     struct cred *cr)
4850f1702c5SYu Xiangning {
4860f1702c5SYu Xiangning 	int flags;
4870f1702c5SYu Xiangning 	ssize_t count;
4880f1702c5SYu Xiangning 	int error;
4890f1702c5SYu Xiangning 
4900f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
4910f1702c5SYu Xiangning 
4920f1702c5SYu Xiangning 	dprint(4, ("sosdp_sendmsg: so:%p so_proto_handle:%p",
4930f1702c5SYu Xiangning 	    (void *)so, (void *)so->so_proto_handle));
4940f1702c5SYu Xiangning 
4950f1702c5SYu Xiangning 	flags = msg->msg_flags;
4960f1702c5SYu Xiangning 
4970f1702c5SYu Xiangning 	if (msg->msg_controllen != 0) {
4980f1702c5SYu Xiangning 		return (EOPNOTSUPP);
4990f1702c5SYu Xiangning 	}
5000f1702c5SYu Xiangning 
5010f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
5020f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE) {
5030f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5040f1702c5SYu Xiangning 		return (EPIPE);
5050f1702c5SYu Xiangning 	}
5060f1702c5SYu Xiangning 
5070f1702c5SYu Xiangning 	if (so->so_error != 0) {
5080f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
5090f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5100f1702c5SYu Xiangning 		return (error);
5110f1702c5SYu Xiangning 	}
5120f1702c5SYu Xiangning 
5130f1702c5SYu Xiangning 	if (uiop->uio_fmode & (FNDELAY|FNONBLOCK))
5140f1702c5SYu Xiangning 		flags |= MSG_DONTWAIT;
5150f1702c5SYu Xiangning 
5160f1702c5SYu Xiangning 	count = uiop->uio_resid;
5170f1702c5SYu Xiangning 
5180f1702c5SYu Xiangning 	if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) {
5190f1702c5SYu Xiangning 		dprint(4, ("sosdp_sendmsg: invalid state: <%x>",
5200f1702c5SYu Xiangning 		    so->so_state));
5210f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5220f1702c5SYu Xiangning 		return (ENOTCONN);
5230f1702c5SYu Xiangning 	}
5240f1702c5SYu Xiangning 
5250f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
5260f1702c5SYu Xiangning 	error = sdp_send((struct sdp_conn_struct_t *)so->so_proto_handle,
5270f1702c5SYu Xiangning 	    msg, count, flags, uiop);
5280f1702c5SYu Xiangning 
5290f1702c5SYu Xiangning 	return (error);
5300f1702c5SYu Xiangning }
5310f1702c5SYu Xiangning 
5320f1702c5SYu Xiangning /*
5330f1702c5SYu Xiangning  * Get address of remote node.
5340f1702c5SYu Xiangning  */
5350f1702c5SYu Xiangning /* ARGSUSED */
5360f1702c5SYu Xiangning static int
5370f1702c5SYu Xiangning sosdp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5380f1702c5SYu Xiangning     boolean_t accept, struct cred *cr)
5390f1702c5SYu Xiangning {
5400f1702c5SYu Xiangning 
5410f1702c5SYu Xiangning 	if (!accept && !(so->so_state & SS_ISCONNECTED)) {
5420f1702c5SYu Xiangning 		return (ENOTCONN);
5430f1702c5SYu Xiangning 	} else {
5440f1702c5SYu Xiangning 		return (sdp_getpeername(
5450f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
5460f1702c5SYu Xiangning 		    addr, addrlen));
5470f1702c5SYu Xiangning 	}
5480f1702c5SYu Xiangning }
5490f1702c5SYu Xiangning 
5500f1702c5SYu Xiangning /*
5510f1702c5SYu Xiangning  * Get local address.
5520f1702c5SYu Xiangning  */
5530f1702c5SYu Xiangning /* ARGSUSED */
5540f1702c5SYu Xiangning static int
5550f1702c5SYu Xiangning sosdp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5560f1702c5SYu Xiangning     struct cred *cr)
5570f1702c5SYu Xiangning {
5580f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
5590f1702c5SYu Xiangning 
5600f1702c5SYu Xiangning 	if (!(so->so_state & SS_ISBOUND)) {
5610f1702c5SYu Xiangning 		/*
5620f1702c5SYu Xiangning 		 * Zero address, except for address family
5630f1702c5SYu Xiangning 		 */
5640f1702c5SYu Xiangning 		if (so->so_family == AF_INET || so->so_family == AF_INET6) {
5650f1702c5SYu Xiangning 			bzero(addr, *addrlen);
5660f1702c5SYu Xiangning 			*addrlen = (so->so_family == AF_INET6) ?
5670f1702c5SYu Xiangning 			    sizeof (struct sockaddr_in6) :
5680f1702c5SYu Xiangning 			    sizeof (struct sockaddr_in);
5690f1702c5SYu Xiangning 			addr->sa_family = so->so_family;
5700f1702c5SYu Xiangning 		}
5710f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5720f1702c5SYu Xiangning 		return (0);
5730f1702c5SYu Xiangning 	} else {
5740f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5750f1702c5SYu Xiangning 		return (sdp_getsockname(
5760f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
5770f1702c5SYu Xiangning 		    addr, addrlen));
5780f1702c5SYu Xiangning 	}
5790f1702c5SYu Xiangning }
5800f1702c5SYu Xiangning 
5810f1702c5SYu Xiangning /*
5820f1702c5SYu Xiangning  * Called from shutdown().
5830f1702c5SYu Xiangning  */
5840f1702c5SYu Xiangning /* ARGSUSED */
5850f1702c5SYu Xiangning static int
5860f1702c5SYu Xiangning sosdp_shutdown(struct sonode *so, int how, struct cred *cr)
5870f1702c5SYu Xiangning {
5880f1702c5SYu Xiangning 	uint_t state_change;
5890f1702c5SYu Xiangning 	int error = 0;
5900f1702c5SYu Xiangning 
5910f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
5920f1702c5SYu Xiangning 	so_lock_single(so);
5930f1702c5SYu Xiangning 	/*
5940f1702c5SYu Xiangning 	 * Record the current state and then perform any state changes.
5950f1702c5SYu Xiangning 	 * Then use the difference between the old and new states to
5960f1702c5SYu Xiangning 	 * determine which needs to be done.
5970f1702c5SYu Xiangning 	 */
5980f1702c5SYu Xiangning 	state_change = so->so_state;
5990f1702c5SYu Xiangning 	if (!(state_change & SS_ISCONNECTED)) {
6000f1702c5SYu Xiangning 		error = ENOTCONN;
6010f1702c5SYu Xiangning 		goto done;
6020f1702c5SYu Xiangning 	}
6030f1702c5SYu Xiangning 
6040f1702c5SYu Xiangning 	switch (how) {
6050f1702c5SYu Xiangning 	case SHUT_RD:
6060f1702c5SYu Xiangning 		socantrcvmore(so);
6070f1702c5SYu Xiangning 		break;
6080f1702c5SYu Xiangning 	case SHUT_WR:
6090f1702c5SYu Xiangning 		socantsendmore(so);
6100f1702c5SYu Xiangning 		break;
6110f1702c5SYu Xiangning 	case SHUT_RDWR:
6120f1702c5SYu Xiangning 		socantsendmore(so);
6130f1702c5SYu Xiangning 		socantrcvmore(so);
6140f1702c5SYu Xiangning 		break;
6150f1702c5SYu Xiangning 	default:
6160f1702c5SYu Xiangning 		error = EINVAL;
6170f1702c5SYu Xiangning 		goto done;
6180f1702c5SYu Xiangning 	}
6190f1702c5SYu Xiangning 
6200f1702c5SYu Xiangning 	state_change = so->so_state & ~state_change;
6210f1702c5SYu Xiangning 
6220f1702c5SYu Xiangning 	if (state_change & SS_CANTSENDMORE) {
6230f1702c5SYu Xiangning 		so->so_state |= SS_ISDISCONNECTING;
6240f1702c5SYu Xiangning 	}
6250f1702c5SYu Xiangning 	so_notify_shutdown(so);
6260f1702c5SYu Xiangning 
6270f1702c5SYu Xiangning 	if (state_change & SS_CANTSENDMORE) {
6280f1702c5SYu Xiangning 		error = sdp_shutdown(
6290f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle, how);
6300f1702c5SYu Xiangning 	}
6310f1702c5SYu Xiangning 
6320f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
6330f1702c5SYu Xiangning done:
6340f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
6350f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
6360f1702c5SYu Xiangning 
6370f1702c5SYu Xiangning 	/*
6380f1702c5SYu Xiangning 	 * HACK: sdp_disconnect() may return EWOULDBLOCK.  But this error is
6390f1702c5SYu Xiangning 	 * not documented in standard socket API.  Catch it here.
6400f1702c5SYu Xiangning 	 */
6410f1702c5SYu Xiangning 	if (error == EWOULDBLOCK)
6420f1702c5SYu Xiangning 		error = 0;
6430f1702c5SYu Xiangning 	return (error);
6440f1702c5SYu Xiangning }
6450f1702c5SYu Xiangning 
6460f1702c5SYu Xiangning /*
6470f1702c5SYu Xiangning  * Get socket options.
6480f1702c5SYu Xiangning  */
6490f1702c5SYu Xiangning /*ARGSUSED*/
6500f1702c5SYu Xiangning static int
6510f1702c5SYu Xiangning sosdp_getsockopt(struct sonode *so, int level, int option_name,
6520f1702c5SYu Xiangning     void *optval, socklen_t *optlenp, int flags, struct cred *cr)
6530f1702c5SYu Xiangning {
6540f1702c5SYu Xiangning 	int error = 0;
6550f1702c5SYu Xiangning 	void *option = NULL;
6560f1702c5SYu Xiangning 	socklen_t maxlen = *optlenp, len, optlen;
6570f1702c5SYu Xiangning 	uint32_t value;
6580f1702c5SYu Xiangning 	uint8_t buffer[4];
6590f1702c5SYu Xiangning 	void *optbuf = &buffer;
6600f1702c5SYu Xiangning 
6610f1702c5SYu Xiangning 
6620f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
6630f1702c5SYu Xiangning 
6640f1702c5SYu Xiangning 	if (level == SOL_SOCKET) {
6650f1702c5SYu Xiangning 		switch (option_name) {
6660f1702c5SYu Xiangning 		case SO_TYPE:
6670f1702c5SYu Xiangning 		case SO_ERROR:
6680f1702c5SYu Xiangning 		case SO_DEBUG:
6690f1702c5SYu Xiangning 		case SO_ACCEPTCONN:
6700f1702c5SYu Xiangning 		case SO_REUSEADDR:
6710f1702c5SYu Xiangning 		case SO_KEEPALIVE:
6720f1702c5SYu Xiangning 		case SO_DONTROUTE:
6730f1702c5SYu Xiangning 		case SO_BROADCAST:
6740f1702c5SYu Xiangning 		case SO_USELOOPBACK:
6750f1702c5SYu Xiangning 		case SO_OOBINLINE:
6760f1702c5SYu Xiangning 		case SO_SNDBUF:
6770f1702c5SYu Xiangning 		case SO_RCVBUF:
6780f1702c5SYu Xiangning 		case SO_SNDLOWAT:
6790f1702c5SYu Xiangning 		case SO_RCVLOWAT:
6800f1702c5SYu Xiangning 		case SO_DGRAM_ERRIND:
6810f1702c5SYu Xiangning 			if (maxlen < (t_uscalar_t)sizeof (int32_t)) {
6820f1702c5SYu Xiangning 				error = EINVAL;
6830f1702c5SYu Xiangning 				eprintsoline(so, error);
6840f1702c5SYu Xiangning 				goto done;
6850f1702c5SYu Xiangning 			}
6860f1702c5SYu Xiangning 			break;
6870f1702c5SYu Xiangning 		case SO_LINGER:
6880f1702c5SYu Xiangning 			if (maxlen < (t_uscalar_t)sizeof (struct linger)) {
6890f1702c5SYu Xiangning 				error = EINVAL;
6900f1702c5SYu Xiangning 				eprintsoline(so, error);
6910f1702c5SYu Xiangning 				goto done;
6920f1702c5SYu Xiangning 			}
6930f1702c5SYu Xiangning 			break;
6940f1702c5SYu Xiangning 		}
6950f1702c5SYu Xiangning 		len = (t_uscalar_t)sizeof (uint32_t);   /* Default */
6960f1702c5SYu Xiangning 		option = &value;
6970f1702c5SYu Xiangning 
6980f1702c5SYu Xiangning 		switch (option_name) {
6990f1702c5SYu Xiangning 		case SO_TYPE:
7000f1702c5SYu Xiangning 			value = so->so_type;
7010f1702c5SYu Xiangning 			goto copyout;
7020f1702c5SYu Xiangning 
7030f1702c5SYu Xiangning 		case SO_ERROR:
7040f1702c5SYu Xiangning 			value = sogeterr(so, B_TRUE);
7050f1702c5SYu Xiangning 			goto copyout;
7060f1702c5SYu Xiangning 
7070f1702c5SYu Xiangning 		case SO_ACCEPTCONN:
7080f1702c5SYu Xiangning 			value = (so->so_state & SS_ACCEPTCONN) ?
7090f1702c5SYu Xiangning 			    SO_ACCEPTCONN : 0;
7100f1702c5SYu Xiangning 			goto copyout;
7110f1702c5SYu Xiangning 
7120f1702c5SYu Xiangning 		case SO_DEBUG:
7130f1702c5SYu Xiangning 		case SO_REUSEADDR:
7140f1702c5SYu Xiangning 		case SO_KEEPALIVE:
7150f1702c5SYu Xiangning 		case SO_DONTROUTE:
7160f1702c5SYu Xiangning 		case SO_BROADCAST:
7170f1702c5SYu Xiangning 		case SO_USELOOPBACK:
7180f1702c5SYu Xiangning 		case SO_OOBINLINE:
7190f1702c5SYu Xiangning 		case SO_DGRAM_ERRIND:
7200f1702c5SYu Xiangning 			value = (so->so_options & option_name);
7210f1702c5SYu Xiangning 			goto copyout;
7220f1702c5SYu Xiangning 
7230f1702c5SYu Xiangning 			/*
7240f1702c5SYu Xiangning 			 * The following options are only returned by sockfs
7250f1702c5SYu Xiangning 			 * when sdp_get_opt() fails.
7260f1702c5SYu Xiangning 			 */
7270f1702c5SYu Xiangning 
7280f1702c5SYu Xiangning 		case SO_LINGER:
7290f1702c5SYu Xiangning 			option = &so->so_linger;
7300f1702c5SYu Xiangning 			len = (t_uscalar_t)sizeof (struct linger);
7310f1702c5SYu Xiangning 			break;
7320f1702c5SYu Xiangning 		case SO_SNDBUF:
7330f1702c5SYu Xiangning 			value = so->so_sndbuf;
7340f1702c5SYu Xiangning 			len = (t_uscalar_t)sizeof (int);
7350f1702c5SYu Xiangning 			goto copyout;
7360f1702c5SYu Xiangning 
7370f1702c5SYu Xiangning 		case SO_RCVBUF:
7380f1702c5SYu Xiangning 			value = so->so_rcvbuf;
7390f1702c5SYu Xiangning 			len = (t_uscalar_t)sizeof (int);
7400f1702c5SYu Xiangning 			goto copyout;
7410f1702c5SYu Xiangning 
7420f1702c5SYu Xiangning 		case SO_SNDLOWAT:
7430f1702c5SYu Xiangning 			value = so->so_sndlowat;
7440f1702c5SYu Xiangning 			len = (t_uscalar_t)sizeof (int);
7450f1702c5SYu Xiangning 			goto copyout;
7460f1702c5SYu Xiangning 
7470f1702c5SYu Xiangning 		case SO_RCVLOWAT:
7480f1702c5SYu Xiangning 			value = so->so_rcvlowat;
7490f1702c5SYu Xiangning 			len = (t_uscalar_t)sizeof (int);
7500f1702c5SYu Xiangning 			goto copyout;
7510f1702c5SYu Xiangning 
7520f1702c5SYu Xiangning 		default:
7530f1702c5SYu Xiangning 			option = NULL;
7540f1702c5SYu Xiangning 			break;
7550f1702c5SYu Xiangning 		}
7560f1702c5SYu Xiangning 	}
7570f1702c5SYu Xiangning 	if (maxlen > sizeof (buffer)) {
7580f1702c5SYu Xiangning 		optbuf = kmem_alloc(maxlen, KM_SLEEP);
7590f1702c5SYu Xiangning 	}
7600f1702c5SYu Xiangning 	optlen = maxlen;
7610f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
7620f1702c5SYu Xiangning 	error = sdp_get_opt((struct sdp_conn_struct_t *)so->so_proto_handle,
7630f1702c5SYu Xiangning 	    level, option_name, optbuf, &optlen);
7640f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
7650f1702c5SYu Xiangning 	ASSERT(optlen <= maxlen);
7660f1702c5SYu Xiangning 	if (error != 0) {
7670f1702c5SYu Xiangning 		if (option == NULL) {
7680f1702c5SYu Xiangning 			/* We have no fallback value */
7690f1702c5SYu Xiangning 			eprintsoline(so, error);
7700f1702c5SYu Xiangning 			goto free;
7710f1702c5SYu Xiangning 		}
7720f1702c5SYu Xiangning 		error = 0;
7730f1702c5SYu Xiangning 		goto copyout;
7740f1702c5SYu Xiangning 	}
7750f1702c5SYu Xiangning 
7760f1702c5SYu Xiangning 	option = optbuf;
7770f1702c5SYu Xiangning 	len = optlen;
7780f1702c5SYu Xiangning 
7790f1702c5SYu Xiangning copyout:
7800f1702c5SYu Xiangning 	len = MIN(len, maxlen);
7810f1702c5SYu Xiangning 	bcopy(option, optval, len);
7820f1702c5SYu Xiangning 	*optlenp = len;
7830f1702c5SYu Xiangning 
7840f1702c5SYu Xiangning free:
7850f1702c5SYu Xiangning 	if (optbuf != &buffer) {
7860f1702c5SYu Xiangning 		kmem_free(optbuf, maxlen);
7870f1702c5SYu Xiangning 	}
7880f1702c5SYu Xiangning done:
7890f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
7900f1702c5SYu Xiangning 	return (error);
7910f1702c5SYu Xiangning }
7920f1702c5SYu Xiangning 
7930f1702c5SYu Xiangning /*
7940f1702c5SYu Xiangning  * Set socket options
7950f1702c5SYu Xiangning  */
7960f1702c5SYu Xiangning /* ARGSUSED */
7970f1702c5SYu Xiangning static int
7980f1702c5SYu Xiangning sosdp_setsockopt(struct sonode *so, int level, int option_name,
7990f1702c5SYu Xiangning     const void *optval, t_uscalar_t optlen, struct cred *cr)
8000f1702c5SYu Xiangning {
8010f1702c5SYu Xiangning 	void *conn = NULL;
8020f1702c5SYu Xiangning 	int error = 0;
8030f1702c5SYu Xiangning 
8040f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE) {
8050f1702c5SYu Xiangning 		return (EINVAL);
8060f1702c5SYu Xiangning 	}
8070f1702c5SYu Xiangning 
8080f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
8090f1702c5SYu Xiangning 	so_lock_single(so);
8100f1702c5SYu Xiangning 
8110f1702c5SYu Xiangning 	if (so->so_type == SOCK_STREAM) {
8120f1702c5SYu Xiangning 		conn = (void *)so->so_proto_handle;
8130f1702c5SYu Xiangning 	}
8140f1702c5SYu Xiangning 
8150f1702c5SYu Xiangning 	dprint(2, ("sosdp_setsockopt (%d) - conn %p %d %d \n",
8160f1702c5SYu Xiangning 	    so->so_type, conn, level, option_name));
8170f1702c5SYu Xiangning 
8180f1702c5SYu Xiangning 	if (conn != NULL) {
8190f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
8200f1702c5SYu Xiangning 		error = sdp_set_opt((struct sdp_conn_struct_t *)conn, level,
8210f1702c5SYu Xiangning 		    option_name, optval, optlen);
8220f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
8230f1702c5SYu Xiangning 	}
8240f1702c5SYu Xiangning 
8250f1702c5SYu Xiangning 	/*
8260f1702c5SYu Xiangning 	 * Check for SOL_SOCKET options and record their values.
8270f1702c5SYu Xiangning 	 * If we know about a SOL_SOCKET parameter and the transport
8280f1702c5SYu Xiangning 	 * failed it with TBADOPT or TOUTSTATE (i.e. ENOPROTOOPT or
8290f1702c5SYu Xiangning 	 * EPROTO) we let the setsockopt succeed.
8300f1702c5SYu Xiangning 	 */
8310f1702c5SYu Xiangning 	if (level == SOL_SOCKET) {
8320f1702c5SYu Xiangning 		boolean_t handled = B_FALSE;
8330f1702c5SYu Xiangning 
8340f1702c5SYu Xiangning 		/* Check parameters */
8350f1702c5SYu Xiangning 		switch (option_name) {
8360f1702c5SYu Xiangning 		case SO_DEBUG:
8370f1702c5SYu Xiangning 		case SO_REUSEADDR:
8380f1702c5SYu Xiangning 		case SO_KEEPALIVE:
8390f1702c5SYu Xiangning 		case SO_DONTROUTE:
8400f1702c5SYu Xiangning 		case SO_BROADCAST:
8410f1702c5SYu Xiangning 		case SO_USELOOPBACK:
8420f1702c5SYu Xiangning 		case SO_OOBINLINE:
8430f1702c5SYu Xiangning 		case SO_SNDBUF:
8440f1702c5SYu Xiangning 		case SO_RCVBUF:
8450f1702c5SYu Xiangning 		case SO_SNDLOWAT:
8460f1702c5SYu Xiangning 		case SO_RCVLOWAT:
8470f1702c5SYu Xiangning 		case SO_DGRAM_ERRIND:
8480f1702c5SYu Xiangning 			if (optlen != (t_uscalar_t)sizeof (int32_t)) {
8490f1702c5SYu Xiangning 				error = EINVAL;
8500f1702c5SYu Xiangning 				eprintsoline(so, error);
8510f1702c5SYu Xiangning 				goto done;
8520f1702c5SYu Xiangning 			}
8530f1702c5SYu Xiangning 			ASSERT(optval);
8540f1702c5SYu Xiangning 			handled = B_TRUE;
8550f1702c5SYu Xiangning 			break;
8560f1702c5SYu Xiangning 		case SO_LINGER:
8570f1702c5SYu Xiangning 			if (optlen != (t_uscalar_t)sizeof (struct linger)) {
8580f1702c5SYu Xiangning 				error = EINVAL;
8590f1702c5SYu Xiangning 				eprintsoline(so, error);
8600f1702c5SYu Xiangning 				goto done;
8610f1702c5SYu Xiangning 			}
8620f1702c5SYu Xiangning 			ASSERT(optval);
8630f1702c5SYu Xiangning 			handled = B_TRUE;
8640f1702c5SYu Xiangning 			break;
8650f1702c5SYu Xiangning 		}
8660f1702c5SYu Xiangning 
8670f1702c5SYu Xiangning #define	intvalue (*(int32_t *)optval)
8680f1702c5SYu Xiangning 
8690f1702c5SYu Xiangning 		switch (option_name) {
8700f1702c5SYu Xiangning 		case SO_TYPE:
8710f1702c5SYu Xiangning 		case SO_ERROR:
8720f1702c5SYu Xiangning 		case SO_ACCEPTCONN:
8730f1702c5SYu Xiangning 			/* Can't be set */
8740f1702c5SYu Xiangning 			error = ENOPROTOOPT;
8750f1702c5SYu Xiangning 			goto done;
8760f1702c5SYu Xiangning 		case SO_LINGER: {
8770f1702c5SYu Xiangning 			struct linger *l = (struct linger *)optval;
8780f1702c5SYu Xiangning 
8790f1702c5SYu Xiangning 			so->so_linger.l_linger = l->l_linger;
8800f1702c5SYu Xiangning 			if (l->l_onoff) {
8810f1702c5SYu Xiangning 				so->so_linger.l_onoff = SO_LINGER;
8820f1702c5SYu Xiangning 				so->so_options |= SO_LINGER;
8830f1702c5SYu Xiangning 			} else {
8840f1702c5SYu Xiangning 				so->so_linger.l_onoff = 0;
8850f1702c5SYu Xiangning 				so->so_options &= ~SO_LINGER;
8860f1702c5SYu Xiangning 			}
8870f1702c5SYu Xiangning 			break;
8880f1702c5SYu Xiangning 		}
8890f1702c5SYu Xiangning 
8900f1702c5SYu Xiangning 		case SO_DEBUG:
8910f1702c5SYu Xiangning 		case SO_REUSEADDR:
8920f1702c5SYu Xiangning 		case SO_KEEPALIVE:
8930f1702c5SYu Xiangning 		case SO_DONTROUTE:
8940f1702c5SYu Xiangning 		case SO_BROADCAST:
8950f1702c5SYu Xiangning 		case SO_USELOOPBACK:
8960f1702c5SYu Xiangning 		case SO_OOBINLINE:
8970f1702c5SYu Xiangning 		case SO_DGRAM_ERRIND:
8980f1702c5SYu Xiangning 			if (intvalue != 0) {
8990f1702c5SYu Xiangning 				dprintso(so, 1,
9000f1702c5SYu Xiangning 				    ("sosdp_setsockopt: setting 0x%x\n",
9010f1702c5SYu Xiangning 				    option_name));
9020f1702c5SYu Xiangning 				so->so_options |= option_name;
9030f1702c5SYu Xiangning 			} else {
9040f1702c5SYu Xiangning 				dprintso(so, 1,
9050f1702c5SYu Xiangning 				    ("sosdp_setsockopt: clearing 0x%x\n",
9060f1702c5SYu Xiangning 				    option_name));
9070f1702c5SYu Xiangning 				so->so_options &= ~option_name;
9080f1702c5SYu Xiangning 			}
9090f1702c5SYu Xiangning 			break;
9100f1702c5SYu Xiangning 
9110f1702c5SYu Xiangning 		case SO_SNDBUF:
9120f1702c5SYu Xiangning 			so->so_sndbuf = intvalue;
9130f1702c5SYu Xiangning 			if (so->so_sndlowat > so->so_sndbuf) {
9140f1702c5SYu Xiangning 				so->so_sndlowat = so->so_sndbuf;
9150f1702c5SYu Xiangning 			}
9160f1702c5SYu Xiangning 			break;
9170f1702c5SYu Xiangning 		case SO_RCVBUF:
9180f1702c5SYu Xiangning 			so->so_rcvbuf = intvalue;
9190f1702c5SYu Xiangning 			if (so->so_rcvlowat > so->so_rcvbuf) {
9200f1702c5SYu Xiangning 				so->so_rcvlowat = so->so_rcvbuf;
9210f1702c5SYu Xiangning 			}
9220f1702c5SYu Xiangning 			break;
9230f1702c5SYu Xiangning 		case SO_SNDLOWAT:
9240f1702c5SYu Xiangning 			if (so->so_sndlowat > so->so_sndbuf) {
9250f1702c5SYu Xiangning 				so->so_sndlowat = so->so_sndbuf;
9260f1702c5SYu Xiangning 			}
9270f1702c5SYu Xiangning 			break;
9280f1702c5SYu Xiangning 		case SO_RCVLOWAT:
9290f1702c5SYu Xiangning 			if (so->so_rcvlowat > so->so_rcvbuf) {
9300f1702c5SYu Xiangning 				so->so_rcvlowat = so->so_rcvbuf;
9310f1702c5SYu Xiangning 			}
9320f1702c5SYu Xiangning 			break;
9330f1702c5SYu Xiangning 		}
9340f1702c5SYu Xiangning #undef  intvalue
9350f1702c5SYu Xiangning 
9360f1702c5SYu Xiangning 		if (error != 0) {
9370f1702c5SYu Xiangning 			if ((error == ENOPROTOOPT || error == EPROTO ||
9380f1702c5SYu Xiangning 			    error == EINVAL) && handled) {
9390f1702c5SYu Xiangning 				dprintso(so, 1,
9400f1702c5SYu Xiangning 				    ("sosdp_setsockopt: ignoring error %d "
9410f1702c5SYu Xiangning 				    "for 0x%x\n", error, option_name));
9420f1702c5SYu Xiangning 				error = 0;
9430f1702c5SYu Xiangning 			}
9440f1702c5SYu Xiangning 		}
9450f1702c5SYu Xiangning 	}
9460f1702c5SYu Xiangning 
9470f1702c5SYu Xiangning done:
9480f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
9490f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
9500f1702c5SYu Xiangning 
9510f1702c5SYu Xiangning 	return (error);
9520f1702c5SYu Xiangning }
9530f1702c5SYu Xiangning 
9540f1702c5SYu Xiangning /* ARGSUSED */
9550f1702c5SYu Xiangning static int
9560f1702c5SYu Xiangning sosdp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
9570f1702c5SYu Xiangning     struct cred *cr, int32_t *rvalp)
9580f1702c5SYu Xiangning {
9590f1702c5SYu Xiangning 	int32_t value;
9600f1702c5SYu Xiangning 	int error, intval;
9610f1702c5SYu Xiangning 	pid_t pid;
9620f1702c5SYu Xiangning 
9630f1702c5SYu Xiangning 	/* handle socket specific ioctls */
9640f1702c5SYu Xiangning 	switch (cmd) {
9650f1702c5SYu Xiangning 	case FIONBIO:
9660f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
9670f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
9680f1702c5SYu Xiangning 			return (EFAULT);
9690f1702c5SYu Xiangning 		}
9700f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
9710f1702c5SYu Xiangning 		if (value != 0) {
9720f1702c5SYu Xiangning 			so->so_state |= SS_NDELAY;
9730f1702c5SYu Xiangning 		} else {
9740f1702c5SYu Xiangning 			so->so_state &= ~SS_NDELAY;
9750f1702c5SYu Xiangning 		}
9760f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
9770f1702c5SYu Xiangning 		return (0);
9780f1702c5SYu Xiangning 
9790f1702c5SYu Xiangning 	case FIOASYNC:
9800f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
9810f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
9820f1702c5SYu Xiangning 			return (EFAULT);
9830f1702c5SYu Xiangning 		}
9840f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
9850f1702c5SYu Xiangning 
9860f1702c5SYu Xiangning 		if (value) {
9870f1702c5SYu Xiangning 			/* Turn on SIGIO */
9880f1702c5SYu Xiangning 			so->so_state |= SS_ASYNC;
9890f1702c5SYu Xiangning 		} else {
9900f1702c5SYu Xiangning 			/* Turn off SIGIO */
9910f1702c5SYu Xiangning 			so->so_state &= ~SS_ASYNC;
9920f1702c5SYu Xiangning 		}
9930f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
9940f1702c5SYu Xiangning 		return (0);
9950f1702c5SYu Xiangning 
9960f1702c5SYu Xiangning 	case SIOCSPGRP:
9970f1702c5SYu Xiangning 	case FIOSETOWN:
9980f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &pid, sizeof (pid_t),
9990f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
10000f1702c5SYu Xiangning 			return (EFAULT);
10010f1702c5SYu Xiangning 		}
10020f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
10030f1702c5SYu Xiangning 
10040f1702c5SYu Xiangning 		error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0;
10050f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
10060f1702c5SYu Xiangning 		return (error);
10070f1702c5SYu Xiangning 
10080f1702c5SYu Xiangning 	case SIOCGPGRP:
10090f1702c5SYu Xiangning 	case FIOGETOWN:
10100f1702c5SYu Xiangning 		if (so_copyout(&so->so_pgrp, (void *)arg,
10110f1702c5SYu Xiangning 		    sizeof (pid_t), (mode & (int)FKIOCTL)))
10120f1702c5SYu Xiangning 			return (EFAULT);
10130f1702c5SYu Xiangning 		return (0);
10140f1702c5SYu Xiangning 
10150f1702c5SYu Xiangning 	case SIOCATMARK:
10160f1702c5SYu Xiangning 		intval = 0;
10170f1702c5SYu Xiangning 		error = sdp_ioctl(
10180f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10190f1702c5SYu Xiangning 		    &intval, cr);
10200f1702c5SYu Xiangning 		if (so_copyout(&intval, (void *)arg, sizeof (int),
10210f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL)))
10220f1702c5SYu Xiangning 			return (EFAULT);
10230f1702c5SYu Xiangning 		return (0);
10240f1702c5SYu Xiangning 
10250f1702c5SYu Xiangning 
10260f1702c5SYu Xiangning 	case SIOCSENABLESDP: {
10270f1702c5SYu Xiangning 		int32_t enable;
10280f1702c5SYu Xiangning 
10290f1702c5SYu Xiangning 		/*
10300f1702c5SYu Xiangning 		 * System wide enable SDP
10310f1702c5SYu Xiangning 		 */
10320f1702c5SYu Xiangning 
10330f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &enable, sizeof (int32_t),
10340f1702c5SYu Xiangning 		    mode & (int)FKIOCTL))
10350f1702c5SYu Xiangning 			return (EFAULT);
10360f1702c5SYu Xiangning 
10370f1702c5SYu Xiangning 		error = sdp_ioctl(
10380f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10390f1702c5SYu Xiangning 		    &enable, cr);
10400f1702c5SYu Xiangning 		if (so_copyout(&enable, (void *)arg,
10410f1702c5SYu Xiangning 		    sizeof (int32_t), (mode & (int)FKIOCTL)))
10420f1702c5SYu Xiangning 			return (EFAULT);
10430f1702c5SYu Xiangning 		return (0);
10440f1702c5SYu Xiangning 	}
10450f1702c5SYu Xiangning 		/* from strioctl */
10460f1702c5SYu Xiangning 	case FIONREAD:
10470f1702c5SYu Xiangning 		/*
10480f1702c5SYu Xiangning 		 * Return number of bytes of data in all data messages
10490f1702c5SYu Xiangning 		 * in queue in "arg".
10500f1702c5SYu Xiangning 		 * For stream socket, amount of available data.
10510f1702c5SYu Xiangning 		 */
10520f1702c5SYu Xiangning 		if (so->so_state & SS_ACCEPTCONN) {
10530f1702c5SYu Xiangning 			intval = 0;
10540f1702c5SYu Xiangning 		} else {
10550f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
10560f1702c5SYu Xiangning 			intval = sdp_polldata(
10570f1702c5SYu Xiangning 			    (struct sdp_conn_struct_t *)so->so_proto_handle,
10580f1702c5SYu Xiangning 			    SDP_READ);
10590f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
10600f1702c5SYu Xiangning 		}
10610f1702c5SYu Xiangning 		if (so_copyout(&intval, (void *)arg, sizeof (intval),
10620f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL)))
10630f1702c5SYu Xiangning 			return (EFAULT);
10640f1702c5SYu Xiangning 		return (0);
10650f1702c5SYu Xiangning 	default:
10660f1702c5SYu Xiangning 		return (EINVAL);
10670f1702c5SYu Xiangning 	}
10680f1702c5SYu Xiangning }
10690f1702c5SYu Xiangning 
10700f1702c5SYu Xiangning /*
10710f1702c5SYu Xiangning  * Check socktpi_poll() on why so_lock is not held in this function.
10720f1702c5SYu Xiangning  */
10730f1702c5SYu Xiangning static int
10740f1702c5SYu Xiangning sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp,
10750f1702c5SYu Xiangning     struct pollhead **phpp)
10760f1702c5SYu Xiangning {
10770f1702c5SYu Xiangning 	short origevents = events;
10780f1702c5SYu Xiangning 	int so_state;
10790f1702c5SYu Xiangning 
10800f1702c5SYu Xiangning 	so_state = so->so_state;
10810f1702c5SYu Xiangning 
10820f1702c5SYu Xiangning 	ASSERT(so->so_version != SOV_STREAM);
10830f1702c5SYu Xiangning 
10840f1702c5SYu Xiangning 	if (!(so_state & SS_ISCONNECTED) && (so->so_type == SOCK_STREAM)) {
10850f1702c5SYu Xiangning 		/*
10860f1702c5SYu Xiangning 		 * Not connected yet - turn off write side events
10870f1702c5SYu Xiangning 		 */
10880f1702c5SYu Xiangning 		events &= ~(POLLOUT|POLLWRBAND);
10890f1702c5SYu Xiangning 	}
10900f1702c5SYu Xiangning 
10910f1702c5SYu Xiangning 	/*
10920f1702c5SYu Xiangning 	 * Check for errors
10930f1702c5SYu Xiangning 	 */
10940f1702c5SYu Xiangning 	if (so->so_error != 0 &&
10950f1702c5SYu Xiangning 	    ((POLLIN|POLLRDNORM|POLLOUT) & origevents)  != 0) {
10960f1702c5SYu Xiangning 		*reventsp = (POLLIN|POLLRDNORM|POLLOUT) & origevents;
10970f1702c5SYu Xiangning 		return (0);
10980f1702c5SYu Xiangning 	}
10990f1702c5SYu Xiangning 
11000f1702c5SYu Xiangning 	*reventsp = 0;
11010f1702c5SYu Xiangning 
11020f1702c5SYu Xiangning 	/*
11030f1702c5SYu Xiangning 	 * Don't mark socket as writable until TX queued data is
11040f1702c5SYu Xiangning 	 * below watermark.
11050f1702c5SYu Xiangning 	 */
11060f1702c5SYu Xiangning 	if (so->so_type == SOCK_STREAM) {
11070f1702c5SYu Xiangning 		if (sdp_polldata(
11080f1702c5SYu Xiangning 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
11090f1702c5SYu Xiangning 		    SDP_XMIT)) {
11100f1702c5SYu Xiangning 			*reventsp |= POLLOUT & events;
11110f1702c5SYu Xiangning 		}
11120f1702c5SYu Xiangning 	} else {
11130f1702c5SYu Xiangning 		*reventsp = 0;
11140f1702c5SYu Xiangning 		goto done;
11150f1702c5SYu Xiangning 	}
11160f1702c5SYu Xiangning 
11170f1702c5SYu Xiangning 	if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle,
11180f1702c5SYu Xiangning 	    SDP_READ)) {
11190f1702c5SYu Xiangning 		*reventsp |= (POLLIN|POLLRDNORM) & events;
11200f1702c5SYu Xiangning 	}
11210f1702c5SYu Xiangning 
1122*3e95bd4aSAnders Persson 	if ((so_state & SS_CANTRCVMORE) || (so->so_acceptq_len > 0)) {
11230f1702c5SYu Xiangning 		*reventsp |= (POLLIN|POLLRDNORM) & events;
11240f1702c5SYu Xiangning 	}
11250f1702c5SYu Xiangning 
11260f1702c5SYu Xiangning done:
11270f1702c5SYu Xiangning 	if (!*reventsp && !anyyet) {
11280f1702c5SYu Xiangning 		*phpp = &so->so_poll_list;
11290f1702c5SYu Xiangning 	}
11300f1702c5SYu Xiangning 
11310f1702c5SYu Xiangning 	return (0);
11320f1702c5SYu Xiangning }
11330f1702c5SYu Xiangning 
11340f1702c5SYu Xiangning /* ARGSUSED */
11350f1702c5SYu Xiangning static int
11360f1702c5SYu Xiangning sosdp_close(struct sonode *so, int flag, struct cred *cr)
11370f1702c5SYu Xiangning {
11380f1702c5SYu Xiangning 	int error = 0;
11390f1702c5SYu Xiangning 
11400f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11410f1702c5SYu Xiangning 	so_lock_single(so);
11420f1702c5SYu Xiangning 	/*
11430f1702c5SYu Xiangning 	 * Need to set flags as there might be ops in progress on
11440f1702c5SYu Xiangning 	 * this socket.
11450f1702c5SYu Xiangning 	 *
11460f1702c5SYu Xiangning 	 * If socket already disconnected/disconnecting,
11470f1702c5SYu Xiangning 	 * don't send signal (again).
11480f1702c5SYu Xiangning 	 */
11490f1702c5SYu Xiangning 	soisdisconnected(so, 0);
11500f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
11510f1702c5SYu Xiangning 
11520f1702c5SYu Xiangning 	/*
11530f1702c5SYu Xiangning 	 * Initiate connection shutdown.
11540f1702c5SYu Xiangning 	 */
11550f1702c5SYu Xiangning 	error = sdp_disconnect((struct sdp_conn_struct_t *)so->so_proto_handle,
11560f1702c5SYu Xiangning 	    flag);
11570f1702c5SYu Xiangning 
11580f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11590f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
1160*3e95bd4aSAnders Persson 	so_notify_disconnected(so, B_FALSE, error);
11610f1702c5SYu Xiangning 
11620f1702c5SYu Xiangning 	return (error);
11630f1702c5SYu Xiangning }
11640f1702c5SYu Xiangning 
11650f1702c5SYu Xiangning /* ARGSUSED */
11660f1702c5SYu Xiangning void
11670f1702c5SYu Xiangning sosdp_fini(struct sonode *so, struct cred *cr)
11680f1702c5SYu Xiangning {
11690f1702c5SYu Xiangning 	dprint(3, ("sosdp_fini: so:%p so_proto_handle:%p", (void *)so,
11700f1702c5SYu Xiangning 	    (void *)so->so_proto_handle));
11710f1702c5SYu Xiangning 
11720f1702c5SYu Xiangning 	ASSERT(so->so_ops == &sosdp_sonodeops);
11730f1702c5SYu Xiangning 
11740f1702c5SYu Xiangning 	if (so->so_proto_handle != NULL)
11750f1702c5SYu Xiangning 		sdp_close((struct sdp_conn_struct_t *)so->so_proto_handle);
11760f1702c5SYu Xiangning 	so->so_proto_handle = NULL;
11770f1702c5SYu Xiangning 
11780f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11790f1702c5SYu Xiangning 
11802320a8c1SAnders Persson 	so_acceptq_flush(so, B_TRUE);
11810f1702c5SYu Xiangning 
11820f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
11830f1702c5SYu Xiangning 
11840f1702c5SYu Xiangning 	sonode_fini(so);
11850f1702c5SYu Xiangning }
11860f1702c5SYu Xiangning 
11870f1702c5SYu Xiangning /*
11880f1702c5SYu Xiangning  * Upcalls from SDP
11890f1702c5SYu Xiangning  */
11900f1702c5SYu Xiangning 
11910f1702c5SYu Xiangning /*
11920f1702c5SYu Xiangning  * Incoming connection on listen socket.
11930f1702c5SYu Xiangning  */
11940f1702c5SYu Xiangning static void *
11950f1702c5SYu Xiangning sdp_sock_newconn(void *parenthandle, void *connind)
11960f1702c5SYu Xiangning {
11970f1702c5SYu Xiangning 	struct sonode *lso = parenthandle;
11980f1702c5SYu Xiangning 	struct sonode *nso;
11990f1702c5SYu Xiangning 	int error;
12000f1702c5SYu Xiangning 
12010f1702c5SYu Xiangning 	ASSERT(lso->so_state & SS_ACCEPTCONN);
12020f1702c5SYu Xiangning 	ASSERT(lso->so_proto_handle != NULL); /* closed conn */
12030f1702c5SYu Xiangning 	ASSERT(lso->so_type == SOCK_STREAM);
12040f1702c5SYu Xiangning 
12050f1702c5SYu Xiangning 	dprint(3, ("sosdp_newconn A: so:%p so_proto_handle:%p", (void *)lso,
12060f1702c5SYu Xiangning 	    (void *)lso->so_proto_handle));
12070f1702c5SYu Xiangning 
12080f1702c5SYu Xiangning 	/*
12090f1702c5SYu Xiangning 	 * Check current # of queued conns against backlog
12100f1702c5SYu Xiangning 	 */
12110f1702c5SYu Xiangning 	if (lso->so_rcv_queued >= lso->so_backlog) {
12120f1702c5SYu Xiangning 		return (NULL);
12130f1702c5SYu Xiangning 	}
12140f1702c5SYu Xiangning 
12150f1702c5SYu Xiangning 	nso = socket_newconn(lso, connind, NULL, SOCKET_NOSLEEP, &error);
12160f1702c5SYu Xiangning 	if (nso == NULL) {
12170f1702c5SYu Xiangning 		eprintsoline(lso, error);
12180f1702c5SYu Xiangning 		return (NULL);
12190f1702c5SYu Xiangning 	}
12200f1702c5SYu Xiangning 
12210f1702c5SYu Xiangning 	dprint(2, ("sdp_stream_newconn: new %p\n", (void *)nso));
12220f1702c5SYu Xiangning 
12230f1702c5SYu Xiangning 	(void) so_acceptq_enqueue(lso, nso);
12240f1702c5SYu Xiangning 
12250f1702c5SYu Xiangning 	mutex_enter(&lso->so_lock);
12260f1702c5SYu Xiangning 	so_notify_newconn(lso);
12270f1702c5SYu Xiangning 	return (nso);
12280f1702c5SYu Xiangning }
12290f1702c5SYu Xiangning 
12300f1702c5SYu Xiangning /*
12310f1702c5SYu Xiangning  * For outgoing connections, the connection has been established.
12320f1702c5SYu Xiangning  */
12330f1702c5SYu Xiangning static void
12340f1702c5SYu Xiangning sdp_sock_connected(void *handle)
12350f1702c5SYu Xiangning {
12360f1702c5SYu Xiangning 	struct sonode *so = handle;
12370f1702c5SYu Xiangning 
12380f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
12390f1702c5SYu Xiangning 	dprint(3, ("sosdp_connected C: so:%p so_proto_handle:%p", (void *)so,
12400f1702c5SYu Xiangning 	    (void *)so->so_proto_handle));
12410f1702c5SYu Xiangning 
12420f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
12430f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle); /* closed conn */
12440f1702c5SYu Xiangning 
12450f1702c5SYu Xiangning 	ASSERT(!(so->so_state & SS_ACCEPTCONN));
12460f1702c5SYu Xiangning 	soisconnected(so);
12470f1702c5SYu Xiangning 
12480f1702c5SYu Xiangning 	so_notify_connected(so);
12490f1702c5SYu Xiangning }
12500f1702c5SYu Xiangning 
12510f1702c5SYu Xiangning /*
12520f1702c5SYu Xiangning  * Connection got disconnected. Either with an error, or through
12530f1702c5SYu Xiangning  * normal handshake.
12540f1702c5SYu Xiangning  */
12550f1702c5SYu Xiangning static void
12560f1702c5SYu Xiangning sdp_sock_disconnected(void *handle, int error)
12570f1702c5SYu Xiangning {
12580f1702c5SYu Xiangning 	struct sonode *so = handle;
12590f1702c5SYu Xiangning 
12600f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
12610f1702c5SYu Xiangning 	dprint(2, ("sosdp_disconnected C: so:%p so_proto_handle:%p error:%d",
12620f1702c5SYu Xiangning 	    (void *)so, (void *)so->so_proto_handle, error));
12630f1702c5SYu Xiangning 
12640f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
12650f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
12660f1702c5SYu Xiangning 
12670f1702c5SYu Xiangning 	soisdisconnected(so, error);
1268*3e95bd4aSAnders Persson 	so_notify_disconnected(so, B_FALSE, error);
12690f1702c5SYu Xiangning }
12700f1702c5SYu Xiangning 
12710f1702c5SYu Xiangning /*
12720f1702c5SYu Xiangning  * Incoming data.
12730f1702c5SYu Xiangning  */
12740f1702c5SYu Xiangning /*ARGSUSED*/
12750f1702c5SYu Xiangning static int
12760f1702c5SYu Xiangning sdp_sock_recv(void *handle, mblk_t *mp, int flags)
12770f1702c5SYu Xiangning {
12780f1702c5SYu Xiangning 	struct sonode *so = handle;
12790f1702c5SYu Xiangning 
12800f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
12810f1702c5SYu Xiangning 
12820f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
12830f1702c5SYu Xiangning 	so_notify_data(so, 0);
12840f1702c5SYu Xiangning 
12850f1702c5SYu Xiangning 	return (so->so_rcvbuf);
12860f1702c5SYu Xiangning }
12870f1702c5SYu Xiangning 
12880f1702c5SYu Xiangning /*
12890f1702c5SYu Xiangning  * TX queued data got acknowledged.
12900f1702c5SYu Xiangning  */
12910f1702c5SYu Xiangning static void
12920f1702c5SYu Xiangning sdp_sock_xmitted(void *handle, int writeable)
12930f1702c5SYu Xiangning {
12940f1702c5SYu Xiangning 	struct sonode *so = handle;
12950f1702c5SYu Xiangning 
12960f1702c5SYu Xiangning 	dprint(4, ("sosdp_sock_xmitted: so:%p so_proto_handle:%p txq:%d",
12970f1702c5SYu Xiangning 	    (void *)so, (void *)so->so_proto_handle, writeable));
12980f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
12990f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13000f1702c5SYu Xiangning 
13010f1702c5SYu Xiangning 
13020f1702c5SYu Xiangning 	/*
13030f1702c5SYu Xiangning 	 * Only do pollwakeup if the amount of queued data is less than
13040f1702c5SYu Xiangning 	 * watermark.
13050f1702c5SYu Xiangning 	 */
13060f1702c5SYu Xiangning 	if (!writeable) {
13070f1702c5SYu Xiangning 		so_notify_writable(so);
13080f1702c5SYu Xiangning 	} else {
13090f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
13100f1702c5SYu Xiangning 	}
13110f1702c5SYu Xiangning }
13120f1702c5SYu Xiangning 
13130f1702c5SYu Xiangning 
13140f1702c5SYu Xiangning /*
13150f1702c5SYu Xiangning  * SDP notifies socket for presence of urgent data.
13160f1702c5SYu Xiangning  */
13170f1702c5SYu Xiangning static void
13180f1702c5SYu Xiangning sdp_sock_urgdata(void *handle)
13190f1702c5SYu Xiangning {
13200f1702c5SYu Xiangning 	struct sonode *so = handle;
13210f1702c5SYu Xiangning 
13220f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
13230f1702c5SYu Xiangning 
13240f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
13250f1702c5SYu Xiangning 
13260f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13270f1702c5SYu Xiangning 	so_notify_oobsig(so);
13280f1702c5SYu Xiangning }
13290f1702c5SYu Xiangning 
13300f1702c5SYu Xiangning /*
13310f1702c5SYu Xiangning  * SDP notifies socket about receiving of conn close request from peer side.
13320f1702c5SYu Xiangning  */
13330f1702c5SYu Xiangning static void
13340f1702c5SYu Xiangning sdp_sock_ordrel(void *handle)
13350f1702c5SYu Xiangning {
13360f1702c5SYu Xiangning 	struct sonode *so = handle;
13370f1702c5SYu Xiangning 
13380f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
13390f1702c5SYu Xiangning 
13400f1702c5SYu Xiangning 	dprint(4, ("sdp_sock_ordrel : so:%p, so_proto_handle:%p",
13410f1702c5SYu Xiangning 	    (void *)so, (void *)so->so_proto_handle));
13420f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
13430f1702c5SYu Xiangning 	socantrcvmore(so);
13440f1702c5SYu Xiangning 	so_notify_eof(so);
13450f1702c5SYu Xiangning }
13460f1702c5SYu Xiangning 
13470f1702c5SYu Xiangning static void
13480f1702c5SYu Xiangning sdp_sock_connfail(void *handle, int error)
13490f1702c5SYu Xiangning {
13500f1702c5SYu Xiangning 	struct sonode *so = handle;
13510f1702c5SYu Xiangning 
13520f1702c5SYu Xiangning 	dprint(3, ("sosdp_conn Failed: so:%p so_proto_handle:%p", (void *)so,
13530f1702c5SYu Xiangning 	    (void *)so->so_proto_handle));
13540f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
13550f1702c5SYu Xiangning 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13560f1702c5SYu Xiangning 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
13570f1702c5SYu Xiangning 	so->so_error = (ushort_t)error;
13580f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
13590f1702c5SYu Xiangning 	cv_broadcast(&so->so_state_cv);
13600f1702c5SYu Xiangning }
1361