xref: /onnv-gate/usr/src/uts/common/inet/sockmods/socksdp.c (revision 12643:044ff822d212)
18348SEric.Yu@Sun.COM /*
28348SEric.Yu@Sun.COM  * CDDL HEADER START
38348SEric.Yu@Sun.COM  *
48348SEric.Yu@Sun.COM  * The contents of this file are subject to the terms of the
58348SEric.Yu@Sun.COM  * Common Development and Distribution License (the "License").
68348SEric.Yu@Sun.COM  * You may not use this file except in compliance with the License.
78348SEric.Yu@Sun.COM  *
88348SEric.Yu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98348SEric.Yu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108348SEric.Yu@Sun.COM  * See the License for the specific language governing permissions
118348SEric.Yu@Sun.COM  * and limitations under the License.
128348SEric.Yu@Sun.COM  *
138348SEric.Yu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148348SEric.Yu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158348SEric.Yu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168348SEric.Yu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178348SEric.Yu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188348SEric.Yu@Sun.COM  *
198348SEric.Yu@Sun.COM  * CDDL HEADER END
208348SEric.Yu@Sun.COM  */
218348SEric.Yu@Sun.COM 
228348SEric.Yu@Sun.COM /*
23*12643SAnders.Persson@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
248348SEric.Yu@Sun.COM  */
258348SEric.Yu@Sun.COM 
268348SEric.Yu@Sun.COM #include <sys/types.h>
278348SEric.Yu@Sun.COM #include <sys/t_lock.h>
288348SEric.Yu@Sun.COM #include <sys/param.h>
298348SEric.Yu@Sun.COM #include <sys/systm.h>
308348SEric.Yu@Sun.COM #include <sys/buf.h>
318348SEric.Yu@Sun.COM #include <sys/vfs.h>
328348SEric.Yu@Sun.COM #include <sys/vnode.h>
338348SEric.Yu@Sun.COM #include <sys/debug.h>
348348SEric.Yu@Sun.COM #include <sys/errno.h>
358348SEric.Yu@Sun.COM #include <sys/stropts.h>
368348SEric.Yu@Sun.COM #include <sys/cmn_err.h>
378348SEric.Yu@Sun.COM #include <sys/sysmacros.h>
3811537SCasper.Dik@Sun.COM #include <sys/policy.h>
398348SEric.Yu@Sun.COM 
408348SEric.Yu@Sun.COM #include <sys/filio.h>
418348SEric.Yu@Sun.COM #include <sys/sockio.h>
428348SEric.Yu@Sun.COM 
438348SEric.Yu@Sun.COM #include <sys/project.h>
448348SEric.Yu@Sun.COM #include <sys/tihdr.h>
458348SEric.Yu@Sun.COM #include <sys/strsubr.h>
468348SEric.Yu@Sun.COM 
478348SEric.Yu@Sun.COM #include <sys/socket.h>
488348SEric.Yu@Sun.COM #include <sys/socketvar.h>
498348SEric.Yu@Sun.COM #include <sys/strsun.h>
508348SEric.Yu@Sun.COM 
518348SEric.Yu@Sun.COM #include <sys/tsol/label.h>
528348SEric.Yu@Sun.COM 
538348SEric.Yu@Sun.COM #include <inet/sdp_itf.h>
548348SEric.Yu@Sun.COM #include "socksdp.h"
558348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h>
568348SEric.Yu@Sun.COM 
578348SEric.Yu@Sun.COM /*
588348SEric.Yu@Sun.COM  * SDP sockfs sonode operations
598348SEric.Yu@Sun.COM  */
608348SEric.Yu@Sun.COM static int sosdp_init(struct sonode *, struct sonode *, struct cred *, int);
618348SEric.Yu@Sun.COM static int sosdp_accept(struct sonode *, int, struct cred *, struct sonode **);
628348SEric.Yu@Sun.COM static int sosdp_bind(struct sonode *, struct sockaddr *, socklen_t, int,
638348SEric.Yu@Sun.COM     struct cred *);
648348SEric.Yu@Sun.COM static int sosdp_listen(struct sonode *, int, struct cred *);
65*12643SAnders.Persson@Sun.COM static int sosdp_connect(struct sonode *, struct sockaddr *, socklen_t,
668348SEric.Yu@Sun.COM     int, int, struct cred *);
678348SEric.Yu@Sun.COM static int sosdp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *,
688348SEric.Yu@Sun.COM     struct cred *);
698348SEric.Yu@Sun.COM static int sosdp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
708348SEric.Yu@Sun.COM     struct cred *);
718348SEric.Yu@Sun.COM static int sosdp_getpeername(struct sonode *, struct sockaddr *, socklen_t *,
728348SEric.Yu@Sun.COM     boolean_t, struct cred *);
738348SEric.Yu@Sun.COM static int sosdp_getsockname(struct sonode *, struct sockaddr *, socklen_t *,
748348SEric.Yu@Sun.COM     struct cred *);
758348SEric.Yu@Sun.COM static int sosdp_shutdown(struct sonode *, int, struct cred *);
768348SEric.Yu@Sun.COM static int sosdp_getsockopt(struct sonode *, int, int, void *, socklen_t *,
778348SEric.Yu@Sun.COM     int, struct cred *);
788348SEric.Yu@Sun.COM static int sosdp_setsockopt(struct sonode *, int, int, const void *,
798348SEric.Yu@Sun.COM     socklen_t, struct cred *);
808348SEric.Yu@Sun.COM static int sosdp_ioctl(struct sonode *, int, intptr_t, int, struct cred *,
818348SEric.Yu@Sun.COM     int32_t *);
828348SEric.Yu@Sun.COM static int sosdp_poll(struct sonode *, short, int, short *,
838348SEric.Yu@Sun.COM     struct pollhead **);
848348SEric.Yu@Sun.COM static int sosdp_close(struct sonode *, int, struct cred *);
858348SEric.Yu@Sun.COM void sosdp_fini(struct sonode *, struct cred *);
868348SEric.Yu@Sun.COM 
878348SEric.Yu@Sun.COM 
888348SEric.Yu@Sun.COM /*
898348SEric.Yu@Sun.COM  * Socket upcalls
908348SEric.Yu@Sun.COM  */
918348SEric.Yu@Sun.COM static void *sdp_sock_newconn(void *parenthandle, void *connind);
928348SEric.Yu@Sun.COM static void sdp_sock_connected(void *handle);
938348SEric.Yu@Sun.COM static void sdp_sock_disconnected(void *handle, int error);
948348SEric.Yu@Sun.COM static void sdp_sock_connfail(void *handle, int error);
958348SEric.Yu@Sun.COM static int sdp_sock_recv(void *handle, mblk_t *mp, int flags);
968348SEric.Yu@Sun.COM static void sdp_sock_xmitted(void *handle, int txqueued);
978348SEric.Yu@Sun.COM static void sdp_sock_urgdata(void *handle);
988348SEric.Yu@Sun.COM static void sdp_sock_ordrel(void *handle);
998348SEric.Yu@Sun.COM 
1008348SEric.Yu@Sun.COM sonodeops_t sosdp_sonodeops = {
1018348SEric.Yu@Sun.COM 	sosdp_init,			/* sop_init	*/
1028348SEric.Yu@Sun.COM 	sosdp_accept,			/* sop_accept	*/
1038348SEric.Yu@Sun.COM 	sosdp_bind,			/* sop_bind	*/
1048348SEric.Yu@Sun.COM 	sosdp_listen,			/* sop_listen	*/
1058348SEric.Yu@Sun.COM 	sosdp_connect,			/* sop_connect	*/
1068348SEric.Yu@Sun.COM 	sosdp_recvmsg,			/* sop_recvmsg	*/
1078348SEric.Yu@Sun.COM 	sosdp_sendmsg,			/* sop_sendmsg	*/
1088348SEric.Yu@Sun.COM 	so_sendmblk_notsupp,		/* sop_sendmblk */
1098348SEric.Yu@Sun.COM 	sosdp_getpeername,		/* sop_getpeername */
1108348SEric.Yu@Sun.COM 	sosdp_getsockname,		/* sop_getsockname */
1118348SEric.Yu@Sun.COM 	sosdp_shutdown,			/* sop_shutdown */
1128348SEric.Yu@Sun.COM 	sosdp_getsockopt,		/* sop_getsockopt */
1138348SEric.Yu@Sun.COM 	sosdp_setsockopt,		/* sop_setsockopt */
1148348SEric.Yu@Sun.COM 	sosdp_ioctl,			/* sop_ioctl	*/
1158348SEric.Yu@Sun.COM 	sosdp_poll,			/* sop_poll	*/
1168348SEric.Yu@Sun.COM 	sosdp_close,			/* sop_close	*/
1178348SEric.Yu@Sun.COM };
1188348SEric.Yu@Sun.COM 
1198348SEric.Yu@Sun.COM sdp_upcalls_t sosdp_sock_upcalls = {
1208348SEric.Yu@Sun.COM 	sdp_sock_newconn,
1218348SEric.Yu@Sun.COM 	sdp_sock_connected,
1228348SEric.Yu@Sun.COM 	sdp_sock_disconnected,
1238348SEric.Yu@Sun.COM 	sdp_sock_connfail,
1248348SEric.Yu@Sun.COM 	sdp_sock_recv,
1258348SEric.Yu@Sun.COM 	sdp_sock_xmitted,
1268348SEric.Yu@Sun.COM 	sdp_sock_urgdata,
1278348SEric.Yu@Sun.COM 	sdp_sock_ordrel,
1288348SEric.Yu@Sun.COM };
1298348SEric.Yu@Sun.COM 
1308348SEric.Yu@Sun.COM /* ARGSUSED */
1318348SEric.Yu@Sun.COM static int
sosdp_init(struct sonode * so,struct sonode * pso,struct cred * cr,int flags)1328348SEric.Yu@Sun.COM sosdp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1338348SEric.Yu@Sun.COM {
1348348SEric.Yu@Sun.COM 	int error = 0;
1358348SEric.Yu@Sun.COM 	sdp_sockbuf_limits_t sbl;
1368348SEric.Yu@Sun.COM 	sdp_upcalls_t *upcalls;
1378348SEric.Yu@Sun.COM 
1388348SEric.Yu@Sun.COM 	if (pso != NULL) {
1398348SEric.Yu@Sun.COM 		/* passive open, just inherit settings from parent */
1408348SEric.Yu@Sun.COM 
1418348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
1428348SEric.Yu@Sun.COM 
1438348SEric.Yu@Sun.COM 		so->so_state |= (SS_ISBOUND | SS_ISCONNECTED |
1448348SEric.Yu@Sun.COM 		    (pso->so_state & SS_ASYNC));
1458348SEric.Yu@Sun.COM 		sosdp_so_inherit(pso, so);
1468348SEric.Yu@Sun.COM 		so->so_proto_props = pso->so_proto_props;
1478348SEric.Yu@Sun.COM 
1488348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
1498348SEric.Yu@Sun.COM 
1508348SEric.Yu@Sun.COM 		return (0);
1518348SEric.Yu@Sun.COM 	}
1528348SEric.Yu@Sun.COM 
15311537SCasper.Dik@Sun.COM 	if ((error = secpolicy_basic_net_access(cr)) != 0)
15411537SCasper.Dik@Sun.COM 		return (error);
15511537SCasper.Dik@Sun.COM 
1568348SEric.Yu@Sun.COM 	upcalls = &sosdp_sock_upcalls;
1578348SEric.Yu@Sun.COM 
1588348SEric.Yu@Sun.COM 	so->so_proto_handle = (sock_lower_handle_t)sdp_create(so, NULL,
1598348SEric.Yu@Sun.COM 	    so->so_family, SDP_CAN_BLOCK, upcalls, &sbl, cr, &error);
1608348SEric.Yu@Sun.COM 	if (so->so_proto_handle == NULL)
1618348SEric.Yu@Sun.COM 		return (ENOMEM);
1628348SEric.Yu@Sun.COM 
1638348SEric.Yu@Sun.COM 	so->so_rcvbuf = sbl.sbl_rxbuf;
1648348SEric.Yu@Sun.COM 	so->so_rcvlowat = sbl.sbl_rxlowat;
1658348SEric.Yu@Sun.COM 	so->so_sndbuf = sbl.sbl_txbuf;
1668348SEric.Yu@Sun.COM 	so->so_sndlowat = sbl.sbl_txlowat;
1678348SEric.Yu@Sun.COM 
1688348SEric.Yu@Sun.COM 	return (error);
1698348SEric.Yu@Sun.COM }
1708348SEric.Yu@Sun.COM 
1718348SEric.Yu@Sun.COM /*
1728348SEric.Yu@Sun.COM  * Accept incoming connection.
1738348SEric.Yu@Sun.COM  */
1748348SEric.Yu@Sun.COM /* ARGSUSED */
1758348SEric.Yu@Sun.COM static int
sosdp_accept(struct sonode * lso,int fflag,struct cred * cr,struct sonode ** nsop)1768348SEric.Yu@Sun.COM sosdp_accept(struct sonode *lso, int fflag, struct cred *cr,
1778348SEric.Yu@Sun.COM     struct sonode **nsop)
1788348SEric.Yu@Sun.COM {
1798348SEric.Yu@Sun.COM 	int error = 0;
1808348SEric.Yu@Sun.COM 	struct sonode *nso;
1818348SEric.Yu@Sun.COM 
1828348SEric.Yu@Sun.COM 	dprint(3, ("sosdp_accept: so:%p so_proto_handle:%p", (void *)lso,
1838348SEric.Yu@Sun.COM 	    (void *)lso->so_proto_handle));
1848348SEric.Yu@Sun.COM 
1858348SEric.Yu@Sun.COM 	if (!(lso->so_state & SS_ACCEPTCONN)) {
1868348SEric.Yu@Sun.COM 		/*
1878348SEric.Yu@Sun.COM 		 * Not a listen socket.
1888348SEric.Yu@Sun.COM 		 */
1898348SEric.Yu@Sun.COM 		eprintsoline(lso, EINVAL);
1908348SEric.Yu@Sun.COM 		return (EINVAL);
1918348SEric.Yu@Sun.COM 	}
1928348SEric.Yu@Sun.COM 	/*
1938348SEric.Yu@Sun.COM 	 * Returns right away if socket is nonblocking.
1948348SEric.Yu@Sun.COM 	 */
1958348SEric.Yu@Sun.COM 	error = so_acceptq_dequeue(lso, (fflag & (FNONBLOCK|FNDELAY)), &nso);
1968348SEric.Yu@Sun.COM 	if (error != 0) {
1978348SEric.Yu@Sun.COM 		eprintsoline(lso, error);
1988348SEric.Yu@Sun.COM 		dprint(4, ("sosdp_accept: failed %d:lso:%p so_proto_handle:%p",
1998348SEric.Yu@Sun.COM 		    error, (void *)lso, (void *)lso->so_proto_handle));
2008348SEric.Yu@Sun.COM 		return (error);
2018348SEric.Yu@Sun.COM 	}
2028348SEric.Yu@Sun.COM 
2038348SEric.Yu@Sun.COM 	dprint(2, ("sosdp_accept: new %p\n", (void *)nso));
2048348SEric.Yu@Sun.COM 	*nsop = nso;
2058348SEric.Yu@Sun.COM 
2068348SEric.Yu@Sun.COM 	return (0);
2078348SEric.Yu@Sun.COM }
2088348SEric.Yu@Sun.COM 
2098348SEric.Yu@Sun.COM /*
2108348SEric.Yu@Sun.COM  * Bind local endpoint.
2118348SEric.Yu@Sun.COM  */
2128348SEric.Yu@Sun.COM /* ARGSUSED */
2138348SEric.Yu@Sun.COM int
sosdp_bind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int flags,struct cred * cr)2148348SEric.Yu@Sun.COM sosdp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
2158348SEric.Yu@Sun.COM     int flags, struct cred *cr)
2168348SEric.Yu@Sun.COM {
2178348SEric.Yu@Sun.COM 	int	error = 0;
2188348SEric.Yu@Sun.COM 
2198348SEric.Yu@Sun.COM 	if (!(flags & _SOBIND_LOCK_HELD)) {
2208348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
2218348SEric.Yu@Sun.COM 		so_lock_single(so);	/* Set SOLOCKED */
2228348SEric.Yu@Sun.COM 	} else {
2238348SEric.Yu@Sun.COM 		ASSERT(MUTEX_HELD(&so->so_lock));
2248348SEric.Yu@Sun.COM 		ASSERT(so->so_flag & SOLOCKED);
2258348SEric.Yu@Sun.COM 	}
2268348SEric.Yu@Sun.COM 
2278348SEric.Yu@Sun.COM 	if ((so->so_state & SS_ISBOUND) || name == NULL || namelen == 0) {
2288348SEric.Yu@Sun.COM 		/*
2298348SEric.Yu@Sun.COM 		 * Multiple binds not allowed for any SDP socket.
2308348SEric.Yu@Sun.COM 		 * Also binding with null address is not supported.
2318348SEric.Yu@Sun.COM 		 */
2328348SEric.Yu@Sun.COM 		error = EINVAL;
2338348SEric.Yu@Sun.COM 		eprintsoline(so, error);
2348348SEric.Yu@Sun.COM 		goto done;
2358348SEric.Yu@Sun.COM 	}
2368348SEric.Yu@Sun.COM 
2378348SEric.Yu@Sun.COM 	/*
2388348SEric.Yu@Sun.COM 	 * X/Open requires this check
2398348SEric.Yu@Sun.COM 	 */
2408348SEric.Yu@Sun.COM 	if (so->so_state & SS_CANTSENDMORE) {
2418348SEric.Yu@Sun.COM 		error = EINVAL;
2428348SEric.Yu@Sun.COM 		goto done;
2438348SEric.Yu@Sun.COM 	}
2448348SEric.Yu@Sun.COM 
2458348SEric.Yu@Sun.COM 	/*
2468348SEric.Yu@Sun.COM 	 * Protocol module does address family checks
2478348SEric.Yu@Sun.COM 	 */
2488348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
2498348SEric.Yu@Sun.COM 
2508348SEric.Yu@Sun.COM 	error = sdp_bind((struct sdp_conn_struct_t *)so->so_proto_handle,
2518348SEric.Yu@Sun.COM 	    name, namelen);
2528348SEric.Yu@Sun.COM 
2538348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
2548348SEric.Yu@Sun.COM 
2558348SEric.Yu@Sun.COM 	if (error == 0) {
2568348SEric.Yu@Sun.COM 		so->so_state |= SS_ISBOUND;
2578348SEric.Yu@Sun.COM 	} else {
2588348SEric.Yu@Sun.COM 		eprintsoline(so, error);
2598348SEric.Yu@Sun.COM 	}
2608348SEric.Yu@Sun.COM done:
2618348SEric.Yu@Sun.COM 	if (!(flags & _SOBIND_LOCK_HELD)) {
2628348SEric.Yu@Sun.COM 		so_unlock_single(so, SOLOCKED);
2638348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
2648348SEric.Yu@Sun.COM 	} else {
2658348SEric.Yu@Sun.COM 		/* If the caller held the lock don't release it here */
2668348SEric.Yu@Sun.COM 		ASSERT(MUTEX_HELD(&so->so_lock));
2678348SEric.Yu@Sun.COM 		ASSERT(so->so_flag & SOLOCKED);
2688348SEric.Yu@Sun.COM 	}
2698348SEric.Yu@Sun.COM 	return (error);
2708348SEric.Yu@Sun.COM }
2718348SEric.Yu@Sun.COM 
2728348SEric.Yu@Sun.COM /*
2738348SEric.Yu@Sun.COM  * Turn socket into a listen socket.
2748348SEric.Yu@Sun.COM  */
2758348SEric.Yu@Sun.COM /* ARGSUSED */
2768348SEric.Yu@Sun.COM static int
sosdp_listen(struct sonode * so,int backlog,struct cred * cr)2778348SEric.Yu@Sun.COM sosdp_listen(struct sonode *so, int backlog, struct cred *cr)
2788348SEric.Yu@Sun.COM {
2798348SEric.Yu@Sun.COM 	int error = 0;
2808348SEric.Yu@Sun.COM 
2818348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
2828348SEric.Yu@Sun.COM 	so_lock_single(so);
2838348SEric.Yu@Sun.COM 
2848348SEric.Yu@Sun.COM 	/*
2858348SEric.Yu@Sun.COM 	 * If this socket is trying to do connect, or if it has
2868348SEric.Yu@Sun.COM 	 * been connected, disallow.
2878348SEric.Yu@Sun.COM 	 */
2888348SEric.Yu@Sun.COM 	if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED |
2898348SEric.Yu@Sun.COM 	    SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) {
2908348SEric.Yu@Sun.COM 		error = EINVAL;
2918348SEric.Yu@Sun.COM 		eprintsoline(so, EINVAL);
2928348SEric.Yu@Sun.COM 		goto done;
2938348SEric.Yu@Sun.COM 	}
2948348SEric.Yu@Sun.COM 	/*
2958348SEric.Yu@Sun.COM 	 * If listen() is only called to change backlog, we don't
2968348SEric.Yu@Sun.COM 	 * need to notify protocol module.
2978348SEric.Yu@Sun.COM 	 */
2988348SEric.Yu@Sun.COM 	if (so->so_state & SS_ACCEPTCONN) {
2998348SEric.Yu@Sun.COM 		so->so_backlog = backlog;
3008348SEric.Yu@Sun.COM 		goto done;
3018348SEric.Yu@Sun.COM 	}
3028348SEric.Yu@Sun.COM 
3038348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
3048348SEric.Yu@Sun.COM 
3058348SEric.Yu@Sun.COM 	error = sdp_listen((struct sdp_conn_struct_t *)so->so_proto_handle,
3068348SEric.Yu@Sun.COM 	    backlog);
3078348SEric.Yu@Sun.COM 
3088348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
3098348SEric.Yu@Sun.COM 	if (error == 0) {
3108348SEric.Yu@Sun.COM 		so->so_state |= (SS_ACCEPTCONN | SS_ISBOUND);
3118348SEric.Yu@Sun.COM 		so->so_backlog = backlog;
3128348SEric.Yu@Sun.COM 	} else {
3138348SEric.Yu@Sun.COM 		eprintsoline(so, error);
3148348SEric.Yu@Sun.COM 	}
3158348SEric.Yu@Sun.COM done:
3168348SEric.Yu@Sun.COM 	so_unlock_single(so, SOLOCKED);
3178348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
3188348SEric.Yu@Sun.COM 
3198348SEric.Yu@Sun.COM 	return (error);
3208348SEric.Yu@Sun.COM }
3218348SEric.Yu@Sun.COM 
3228348SEric.Yu@Sun.COM /*
3238348SEric.Yu@Sun.COM  * Active open.
3248348SEric.Yu@Sun.COM  */
3258348SEric.Yu@Sun.COM /*ARGSUSED*/
3268348SEric.Yu@Sun.COM static int
sosdp_connect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags,struct cred * cr)327*12643SAnders.Persson@Sun.COM sosdp_connect(struct sonode *so, struct sockaddr *name,
3288348SEric.Yu@Sun.COM     socklen_t namelen, int fflag, int flags, struct cred *cr)
3298348SEric.Yu@Sun.COM {
3308348SEric.Yu@Sun.COM 	int error = 0;
3318348SEric.Yu@Sun.COM 
3328348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
3338348SEric.Yu@Sun.COM 	so_lock_single(so);
3348348SEric.Yu@Sun.COM 
3358348SEric.Yu@Sun.COM 	/*
3368348SEric.Yu@Sun.COM 	 * Can't connect() after listen(), or if the socket is already
3378348SEric.Yu@Sun.COM 	 * connected.
3388348SEric.Yu@Sun.COM 	 */
3398348SEric.Yu@Sun.COM 	if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) {
3408348SEric.Yu@Sun.COM 		if (so->so_state & SS_ISCONNECTED) {
3418348SEric.Yu@Sun.COM 			error = EISCONN;
3428348SEric.Yu@Sun.COM 		} else if (so->so_state & SS_ISCONNECTING) {
3438348SEric.Yu@Sun.COM 			error = EALREADY;
3448348SEric.Yu@Sun.COM 		} else {
3458348SEric.Yu@Sun.COM 			error = EOPNOTSUPP;
3468348SEric.Yu@Sun.COM 		}
3478348SEric.Yu@Sun.COM 		eprintsoline(so, error);
3488348SEric.Yu@Sun.COM 		goto done;
3498348SEric.Yu@Sun.COM 	}
3508348SEric.Yu@Sun.COM 
3518348SEric.Yu@Sun.COM 	/*
3528348SEric.Yu@Sun.COM 	 * check for failure of an earlier call
3538348SEric.Yu@Sun.COM 	 */
3548348SEric.Yu@Sun.COM 	if (so->so_error != 0) {
3558348SEric.Yu@Sun.COM 		error = sogeterr(so, B_TRUE);
3568348SEric.Yu@Sun.COM 		eprintsoline(so, error);
3578348SEric.Yu@Sun.COM 		goto done;
3588348SEric.Yu@Sun.COM 	}
3598348SEric.Yu@Sun.COM 
3608348SEric.Yu@Sun.COM 	/*
3618348SEric.Yu@Sun.COM 	 * Connection is closing, or closed, don't allow reconnect.
3628348SEric.Yu@Sun.COM 	 * TCP allows this to proceed, but the socket remains unwriteable.
3638348SEric.Yu@Sun.COM 	 * BSD returns EINVAL.
3648348SEric.Yu@Sun.COM 	 */
3658348SEric.Yu@Sun.COM 	if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE|
3668348SEric.Yu@Sun.COM 	    SS_CANTSENDMORE)) {
3678348SEric.Yu@Sun.COM 		error = EINVAL;
3688348SEric.Yu@Sun.COM 		eprintsoline(so, error);
3698348SEric.Yu@Sun.COM 		goto done;
3708348SEric.Yu@Sun.COM 	}
3718348SEric.Yu@Sun.COM 	if (name == NULL || namelen == 0) {
3728348SEric.Yu@Sun.COM 		eprintsoline(so, EINVAL);
3738348SEric.Yu@Sun.COM 		goto done;
3748348SEric.Yu@Sun.COM 	}
3758348SEric.Yu@Sun.COM 	soisconnecting(so);
3768348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
3778348SEric.Yu@Sun.COM 
3788348SEric.Yu@Sun.COM 	error = sdp_connect((struct sdp_conn_struct_t *)so->so_proto_handle,
3798348SEric.Yu@Sun.COM 	    name, namelen);
3808348SEric.Yu@Sun.COM 
3818348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
3828348SEric.Yu@Sun.COM 	if (error == 0) {
3838348SEric.Yu@Sun.COM 		/*
3848348SEric.Yu@Sun.COM 		 * Allow other threads to access the socket
3858348SEric.Yu@Sun.COM 		 */
3868348SEric.Yu@Sun.COM 		error = sowaitconnected(so, fflag, 0);
3878348SEric.Yu@Sun.COM 		dprint(4,
3888348SEric.Yu@Sun.COM 		    ("sosdp_connect: wait on so:%p "
3898348SEric.Yu@Sun.COM 		    "so_proto_handle:%p failed:%d",
3908348SEric.Yu@Sun.COM 		    (void *)so,	(void *)so->so_proto_handle, error));
3918348SEric.Yu@Sun.COM 	}
3928348SEric.Yu@Sun.COM 
3938348SEric.Yu@Sun.COM 	switch (error) {
3948348SEric.Yu@Sun.COM 	case 0:
3958348SEric.Yu@Sun.COM 	case EINPROGRESS:
3968348SEric.Yu@Sun.COM 	case EALREADY:
3978348SEric.Yu@Sun.COM 	case EINTR:
3988348SEric.Yu@Sun.COM 		/* Non-fatal errors */
3998348SEric.Yu@Sun.COM 		so->so_state |= SS_ISBOUND;
4008348SEric.Yu@Sun.COM 		break;
4018348SEric.Yu@Sun.COM 	default:
4028348SEric.Yu@Sun.COM 		/* clear SS_ISCONNECTING in case it was set */
4038348SEric.Yu@Sun.COM 		so->so_state &= ~SS_ISCONNECTING;
4048348SEric.Yu@Sun.COM 		break;
4058348SEric.Yu@Sun.COM 	}
4068348SEric.Yu@Sun.COM done:
4078348SEric.Yu@Sun.COM 	so_unlock_single(so, SOLOCKED);
4088348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
4098348SEric.Yu@Sun.COM 	return (error);
4108348SEric.Yu@Sun.COM }
4118348SEric.Yu@Sun.COM 
4128348SEric.Yu@Sun.COM /*
4138348SEric.Yu@Sun.COM  * Receive data.
4148348SEric.Yu@Sun.COM  */
4158348SEric.Yu@Sun.COM /* ARGSUSED */
4168348SEric.Yu@Sun.COM int
sosdp_recvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)4178348SEric.Yu@Sun.COM sosdp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4188348SEric.Yu@Sun.COM     struct cred *cr)
4198348SEric.Yu@Sun.COM {
4208348SEric.Yu@Sun.COM 	int flags, error = 0;
4218348SEric.Yu@Sun.COM 	int size;
4228348SEric.Yu@Sun.COM 
4238348SEric.Yu@Sun.COM 	flags = msg->msg_flags;
4248348SEric.Yu@Sun.COM 	msg->msg_flags = 0;
4258348SEric.Yu@Sun.COM 
4268348SEric.Yu@Sun.COM 
4278348SEric.Yu@Sun.COM 	if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING|
4288348SEric.Yu@Sun.COM 	    SS_CANTRCVMORE))) {
4298348SEric.Yu@Sun.COM 		return (ENOTCONN);
4308348SEric.Yu@Sun.COM 	}
4318348SEric.Yu@Sun.COM 
4328348SEric.Yu@Sun.COM 	/*
4338348SEric.Yu@Sun.COM 	 * flag possibilities:
4348348SEric.Yu@Sun.COM 	 *
4358348SEric.Yu@Sun.COM 	 * MSG_PEEK	Don't consume data
4368348SEric.Yu@Sun.COM 	 * MSG_WAITALL	Wait for full quantity of data (ignored if MSG_PEEK)
4378348SEric.Yu@Sun.COM 	 * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
4388348SEric.Yu@Sun.COM 	 *
4398348SEric.Yu@Sun.COM 	 * MSG_WAITALL can return less than the full buffer if either
4408348SEric.Yu@Sun.COM 	 *
4418348SEric.Yu@Sun.COM 	 * 1. we would block and we are non-blocking
4428348SEric.Yu@Sun.COM 	 * 2. a full message cannot be delivered
4438348SEric.Yu@Sun.COM 	 *
4448348SEric.Yu@Sun.COM 	 */
4458348SEric.Yu@Sun.COM 
4468348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
4478348SEric.Yu@Sun.COM 
4488348SEric.Yu@Sun.COM 	/*
4498348SEric.Yu@Sun.COM 	 * Allow just one reader at a time.
4508348SEric.Yu@Sun.COM 	 */
4518348SEric.Yu@Sun.COM 	error = so_lock_read_intr(so,
4528348SEric.Yu@Sun.COM 	    uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
4538348SEric.Yu@Sun.COM 	if (error != 0) {
4548348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
4558348SEric.Yu@Sun.COM 		return (error);
4568348SEric.Yu@Sun.COM 	}
4578348SEric.Yu@Sun.COM 	size = uiop->uio_resid;
4588348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
4598348SEric.Yu@Sun.COM 
4608348SEric.Yu@Sun.COM 	if (!(so->so_state & SS_CANTRCVMORE)) {
4618348SEric.Yu@Sun.COM 		if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) {
4628348SEric.Yu@Sun.COM 			flags |= MSG_DONTWAIT;
4638348SEric.Yu@Sun.COM 		}
4648348SEric.Yu@Sun.COM 		error = sdp_recv(
4658348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle, msg,
4668348SEric.Yu@Sun.COM 		    size, flags, uiop);
4678348SEric.Yu@Sun.COM 	} else {
4688348SEric.Yu@Sun.COM 		msg->msg_controllen = 0;
4698348SEric.Yu@Sun.COM 		msg->msg_namelen = 0;
4708348SEric.Yu@Sun.COM 	}
4718348SEric.Yu@Sun.COM done:
4728348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
4738348SEric.Yu@Sun.COM 	so_unlock_read(so);
4748348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
4758348SEric.Yu@Sun.COM 	return (error);
4768348SEric.Yu@Sun.COM }
4778348SEric.Yu@Sun.COM 
4788348SEric.Yu@Sun.COM /*
4798348SEric.Yu@Sun.COM  * Send message.
4808348SEric.Yu@Sun.COM  */
4818348SEric.Yu@Sun.COM /* ARGSUSED */
4828348SEric.Yu@Sun.COM static int
sosdp_sendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)4838348SEric.Yu@Sun.COM sosdp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4848348SEric.Yu@Sun.COM     struct cred *cr)
4858348SEric.Yu@Sun.COM {
4868348SEric.Yu@Sun.COM 	int flags;
4878348SEric.Yu@Sun.COM 	ssize_t count;
4888348SEric.Yu@Sun.COM 	int error;
4898348SEric.Yu@Sun.COM 
4908348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
4918348SEric.Yu@Sun.COM 
4928348SEric.Yu@Sun.COM 	dprint(4, ("sosdp_sendmsg: so:%p so_proto_handle:%p",
4938348SEric.Yu@Sun.COM 	    (void *)so, (void *)so->so_proto_handle));
4948348SEric.Yu@Sun.COM 
4958348SEric.Yu@Sun.COM 	flags = msg->msg_flags;
4968348SEric.Yu@Sun.COM 
4978348SEric.Yu@Sun.COM 	if (msg->msg_controllen != 0) {
4988348SEric.Yu@Sun.COM 		return (EOPNOTSUPP);
4998348SEric.Yu@Sun.COM 	}
5008348SEric.Yu@Sun.COM 
5018348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
5028348SEric.Yu@Sun.COM 	if (so->so_state & SS_CANTSENDMORE) {
5038348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
5048348SEric.Yu@Sun.COM 		return (EPIPE);
5058348SEric.Yu@Sun.COM 	}
5068348SEric.Yu@Sun.COM 
5078348SEric.Yu@Sun.COM 	if (so->so_error != 0) {
5088348SEric.Yu@Sun.COM 		error = sogeterr(so, B_TRUE);
5098348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
5108348SEric.Yu@Sun.COM 		return (error);
5118348SEric.Yu@Sun.COM 	}
5128348SEric.Yu@Sun.COM 
5138348SEric.Yu@Sun.COM 	if (uiop->uio_fmode & (FNDELAY|FNONBLOCK))
5148348SEric.Yu@Sun.COM 		flags |= MSG_DONTWAIT;
5158348SEric.Yu@Sun.COM 
5168348SEric.Yu@Sun.COM 	count = uiop->uio_resid;
5178348SEric.Yu@Sun.COM 
5188348SEric.Yu@Sun.COM 	if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) {
5198348SEric.Yu@Sun.COM 		dprint(4, ("sosdp_sendmsg: invalid state: <%x>",
5208348SEric.Yu@Sun.COM 		    so->so_state));
5218348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
5228348SEric.Yu@Sun.COM 		return (ENOTCONN);
5238348SEric.Yu@Sun.COM 	}
5248348SEric.Yu@Sun.COM 
5258348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
5268348SEric.Yu@Sun.COM 	error = sdp_send((struct sdp_conn_struct_t *)so->so_proto_handle,
5278348SEric.Yu@Sun.COM 	    msg, count, flags, uiop);
5288348SEric.Yu@Sun.COM 
5298348SEric.Yu@Sun.COM 	return (error);
5308348SEric.Yu@Sun.COM }
5318348SEric.Yu@Sun.COM 
5328348SEric.Yu@Sun.COM /*
5338348SEric.Yu@Sun.COM  * Get address of remote node.
5348348SEric.Yu@Sun.COM  */
5358348SEric.Yu@Sun.COM /* ARGSUSED */
5368348SEric.Yu@Sun.COM static int
sosdp_getpeername(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,boolean_t accept,struct cred * cr)5378348SEric.Yu@Sun.COM sosdp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5388348SEric.Yu@Sun.COM     boolean_t accept, struct cred *cr)
5398348SEric.Yu@Sun.COM {
5408348SEric.Yu@Sun.COM 
5418348SEric.Yu@Sun.COM 	if (!accept && !(so->so_state & SS_ISCONNECTED)) {
5428348SEric.Yu@Sun.COM 		return (ENOTCONN);
5438348SEric.Yu@Sun.COM 	} else {
5448348SEric.Yu@Sun.COM 		return (sdp_getpeername(
5458348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
5468348SEric.Yu@Sun.COM 		    addr, addrlen));
5478348SEric.Yu@Sun.COM 	}
5488348SEric.Yu@Sun.COM }
5498348SEric.Yu@Sun.COM 
5508348SEric.Yu@Sun.COM /*
5518348SEric.Yu@Sun.COM  * Get local address.
5528348SEric.Yu@Sun.COM  */
5538348SEric.Yu@Sun.COM /* ARGSUSED */
5548348SEric.Yu@Sun.COM static int
sosdp_getsockname(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5558348SEric.Yu@Sun.COM sosdp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5568348SEric.Yu@Sun.COM     struct cred *cr)
5578348SEric.Yu@Sun.COM {
5588348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
5598348SEric.Yu@Sun.COM 
5608348SEric.Yu@Sun.COM 	if (!(so->so_state & SS_ISBOUND)) {
5618348SEric.Yu@Sun.COM 		/*
5628348SEric.Yu@Sun.COM 		 * Zero address, except for address family
5638348SEric.Yu@Sun.COM 		 */
5648348SEric.Yu@Sun.COM 		if (so->so_family == AF_INET || so->so_family == AF_INET6) {
5658348SEric.Yu@Sun.COM 			bzero(addr, *addrlen);
5668348SEric.Yu@Sun.COM 			*addrlen = (so->so_family == AF_INET6) ?
5678348SEric.Yu@Sun.COM 			    sizeof (struct sockaddr_in6) :
5688348SEric.Yu@Sun.COM 			    sizeof (struct sockaddr_in);
5698348SEric.Yu@Sun.COM 			addr->sa_family = so->so_family;
5708348SEric.Yu@Sun.COM 		}
5718348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
5728348SEric.Yu@Sun.COM 		return (0);
5738348SEric.Yu@Sun.COM 	} else {
5748348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
5758348SEric.Yu@Sun.COM 		return (sdp_getsockname(
5768348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
5778348SEric.Yu@Sun.COM 		    addr, addrlen));
5788348SEric.Yu@Sun.COM 	}
5798348SEric.Yu@Sun.COM }
5808348SEric.Yu@Sun.COM 
5818348SEric.Yu@Sun.COM /*
5828348SEric.Yu@Sun.COM  * Called from shutdown().
5838348SEric.Yu@Sun.COM  */
5848348SEric.Yu@Sun.COM /* ARGSUSED */
5858348SEric.Yu@Sun.COM static int
sosdp_shutdown(struct sonode * so,int how,struct cred * cr)5868348SEric.Yu@Sun.COM sosdp_shutdown(struct sonode *so, int how, struct cred *cr)
5878348SEric.Yu@Sun.COM {
5888348SEric.Yu@Sun.COM 	uint_t state_change;
5898348SEric.Yu@Sun.COM 	int error = 0;
5908348SEric.Yu@Sun.COM 
5918348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
5928348SEric.Yu@Sun.COM 	so_lock_single(so);
5938348SEric.Yu@Sun.COM 	/*
5948348SEric.Yu@Sun.COM 	 * Record the current state and then perform any state changes.
5958348SEric.Yu@Sun.COM 	 * Then use the difference between the old and new states to
5968348SEric.Yu@Sun.COM 	 * determine which needs to be done.
5978348SEric.Yu@Sun.COM 	 */
5988348SEric.Yu@Sun.COM 	state_change = so->so_state;
5998348SEric.Yu@Sun.COM 	if (!(state_change & SS_ISCONNECTED)) {
6008348SEric.Yu@Sun.COM 		error = ENOTCONN;
6018348SEric.Yu@Sun.COM 		goto done;
6028348SEric.Yu@Sun.COM 	}
6038348SEric.Yu@Sun.COM 
6048348SEric.Yu@Sun.COM 	switch (how) {
6058348SEric.Yu@Sun.COM 	case SHUT_RD:
6068348SEric.Yu@Sun.COM 		socantrcvmore(so);
6078348SEric.Yu@Sun.COM 		break;
6088348SEric.Yu@Sun.COM 	case SHUT_WR:
6098348SEric.Yu@Sun.COM 		socantsendmore(so);
6108348SEric.Yu@Sun.COM 		break;
6118348SEric.Yu@Sun.COM 	case SHUT_RDWR:
6128348SEric.Yu@Sun.COM 		socantsendmore(so);
6138348SEric.Yu@Sun.COM 		socantrcvmore(so);
6148348SEric.Yu@Sun.COM 		break;
6158348SEric.Yu@Sun.COM 	default:
6168348SEric.Yu@Sun.COM 		error = EINVAL;
6178348SEric.Yu@Sun.COM 		goto done;
6188348SEric.Yu@Sun.COM 	}
6198348SEric.Yu@Sun.COM 
6208348SEric.Yu@Sun.COM 	state_change = so->so_state & ~state_change;
6218348SEric.Yu@Sun.COM 
6228348SEric.Yu@Sun.COM 	if (state_change & SS_CANTSENDMORE) {
6238348SEric.Yu@Sun.COM 		so->so_state |= SS_ISDISCONNECTING;
6248348SEric.Yu@Sun.COM 	}
6258348SEric.Yu@Sun.COM 	so_notify_shutdown(so);
6268348SEric.Yu@Sun.COM 
6278348SEric.Yu@Sun.COM 	if (state_change & SS_CANTSENDMORE) {
6288348SEric.Yu@Sun.COM 		error = sdp_shutdown(
6298348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle, how);
6308348SEric.Yu@Sun.COM 	}
6318348SEric.Yu@Sun.COM 
6328348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
6338348SEric.Yu@Sun.COM done:
6348348SEric.Yu@Sun.COM 	so_unlock_single(so, SOLOCKED);
6358348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
6368348SEric.Yu@Sun.COM 
6378348SEric.Yu@Sun.COM 	/*
6388348SEric.Yu@Sun.COM 	 * HACK: sdp_disconnect() may return EWOULDBLOCK.  But this error is
6398348SEric.Yu@Sun.COM 	 * not documented in standard socket API.  Catch it here.
6408348SEric.Yu@Sun.COM 	 */
6418348SEric.Yu@Sun.COM 	if (error == EWOULDBLOCK)
6428348SEric.Yu@Sun.COM 		error = 0;
6438348SEric.Yu@Sun.COM 	return (error);
6448348SEric.Yu@Sun.COM }
6458348SEric.Yu@Sun.COM 
6468348SEric.Yu@Sun.COM /*
6478348SEric.Yu@Sun.COM  * Get socket options.
6488348SEric.Yu@Sun.COM  */
6498348SEric.Yu@Sun.COM /*ARGSUSED*/
6508348SEric.Yu@Sun.COM static int
sosdp_getsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags,struct cred * cr)6518348SEric.Yu@Sun.COM sosdp_getsockopt(struct sonode *so, int level, int option_name,
6528348SEric.Yu@Sun.COM     void *optval, socklen_t *optlenp, int flags, struct cred *cr)
6538348SEric.Yu@Sun.COM {
6548348SEric.Yu@Sun.COM 	int error = 0;
6558348SEric.Yu@Sun.COM 	void *option = NULL;
6568348SEric.Yu@Sun.COM 	socklen_t maxlen = *optlenp, len, optlen;
6578348SEric.Yu@Sun.COM 	uint32_t value;
6588348SEric.Yu@Sun.COM 	uint8_t buffer[4];
6598348SEric.Yu@Sun.COM 	void *optbuf = &buffer;
6608348SEric.Yu@Sun.COM 
6618348SEric.Yu@Sun.COM 
6628348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
6638348SEric.Yu@Sun.COM 
6648348SEric.Yu@Sun.COM 	if (level == SOL_SOCKET) {
6658348SEric.Yu@Sun.COM 		switch (option_name) {
6668348SEric.Yu@Sun.COM 		case SO_TYPE:
6678348SEric.Yu@Sun.COM 		case SO_ERROR:
6688348SEric.Yu@Sun.COM 		case SO_DEBUG:
6698348SEric.Yu@Sun.COM 		case SO_ACCEPTCONN:
6708348SEric.Yu@Sun.COM 		case SO_REUSEADDR:
6718348SEric.Yu@Sun.COM 		case SO_KEEPALIVE:
6728348SEric.Yu@Sun.COM 		case SO_DONTROUTE:
6738348SEric.Yu@Sun.COM 		case SO_BROADCAST:
6748348SEric.Yu@Sun.COM 		case SO_USELOOPBACK:
6758348SEric.Yu@Sun.COM 		case SO_OOBINLINE:
6768348SEric.Yu@Sun.COM 		case SO_SNDBUF:
6778348SEric.Yu@Sun.COM 		case SO_RCVBUF:
6788348SEric.Yu@Sun.COM 		case SO_SNDLOWAT:
6798348SEric.Yu@Sun.COM 		case SO_RCVLOWAT:
6808348SEric.Yu@Sun.COM 		case SO_DGRAM_ERRIND:
6818348SEric.Yu@Sun.COM 			if (maxlen < (t_uscalar_t)sizeof (int32_t)) {
6828348SEric.Yu@Sun.COM 				error = EINVAL;
6838348SEric.Yu@Sun.COM 				eprintsoline(so, error);
6848348SEric.Yu@Sun.COM 				goto done;
6858348SEric.Yu@Sun.COM 			}
6868348SEric.Yu@Sun.COM 			break;
6878348SEric.Yu@Sun.COM 		case SO_LINGER:
6888348SEric.Yu@Sun.COM 			if (maxlen < (t_uscalar_t)sizeof (struct linger)) {
6898348SEric.Yu@Sun.COM 				error = EINVAL;
6908348SEric.Yu@Sun.COM 				eprintsoline(so, error);
6918348SEric.Yu@Sun.COM 				goto done;
6928348SEric.Yu@Sun.COM 			}
6938348SEric.Yu@Sun.COM 			break;
6948348SEric.Yu@Sun.COM 		}
6958348SEric.Yu@Sun.COM 		len = (t_uscalar_t)sizeof (uint32_t);   /* Default */
6968348SEric.Yu@Sun.COM 		option = &value;
6978348SEric.Yu@Sun.COM 
6988348SEric.Yu@Sun.COM 		switch (option_name) {
6998348SEric.Yu@Sun.COM 		case SO_TYPE:
7008348SEric.Yu@Sun.COM 			value = so->so_type;
7018348SEric.Yu@Sun.COM 			goto copyout;
7028348SEric.Yu@Sun.COM 
7038348SEric.Yu@Sun.COM 		case SO_ERROR:
7048348SEric.Yu@Sun.COM 			value = sogeterr(so, B_TRUE);
7058348SEric.Yu@Sun.COM 			goto copyout;
7068348SEric.Yu@Sun.COM 
7078348SEric.Yu@Sun.COM 		case SO_ACCEPTCONN:
7088348SEric.Yu@Sun.COM 			value = (so->so_state & SS_ACCEPTCONN) ?
7098348SEric.Yu@Sun.COM 			    SO_ACCEPTCONN : 0;
7108348SEric.Yu@Sun.COM 			goto copyout;
7118348SEric.Yu@Sun.COM 
7128348SEric.Yu@Sun.COM 		case SO_DEBUG:
7138348SEric.Yu@Sun.COM 		case SO_REUSEADDR:
7148348SEric.Yu@Sun.COM 		case SO_KEEPALIVE:
7158348SEric.Yu@Sun.COM 		case SO_DONTROUTE:
7168348SEric.Yu@Sun.COM 		case SO_BROADCAST:
7178348SEric.Yu@Sun.COM 		case SO_USELOOPBACK:
7188348SEric.Yu@Sun.COM 		case SO_OOBINLINE:
7198348SEric.Yu@Sun.COM 		case SO_DGRAM_ERRIND:
7208348SEric.Yu@Sun.COM 			value = (so->so_options & option_name);
7218348SEric.Yu@Sun.COM 			goto copyout;
7228348SEric.Yu@Sun.COM 
7238348SEric.Yu@Sun.COM 			/*
7248348SEric.Yu@Sun.COM 			 * The following options are only returned by sockfs
7258348SEric.Yu@Sun.COM 			 * when sdp_get_opt() fails.
7268348SEric.Yu@Sun.COM 			 */
7278348SEric.Yu@Sun.COM 
7288348SEric.Yu@Sun.COM 		case SO_LINGER:
7298348SEric.Yu@Sun.COM 			option = &so->so_linger;
7308348SEric.Yu@Sun.COM 			len = (t_uscalar_t)sizeof (struct linger);
7318348SEric.Yu@Sun.COM 			break;
7328348SEric.Yu@Sun.COM 		case SO_SNDBUF:
7338348SEric.Yu@Sun.COM 			value = so->so_sndbuf;
7348348SEric.Yu@Sun.COM 			len = (t_uscalar_t)sizeof (int);
7358348SEric.Yu@Sun.COM 			goto copyout;
7368348SEric.Yu@Sun.COM 
7378348SEric.Yu@Sun.COM 		case SO_RCVBUF:
7388348SEric.Yu@Sun.COM 			value = so->so_rcvbuf;
7398348SEric.Yu@Sun.COM 			len = (t_uscalar_t)sizeof (int);
7408348SEric.Yu@Sun.COM 			goto copyout;
7418348SEric.Yu@Sun.COM 
7428348SEric.Yu@Sun.COM 		case SO_SNDLOWAT:
7438348SEric.Yu@Sun.COM 			value = so->so_sndlowat;
7448348SEric.Yu@Sun.COM 			len = (t_uscalar_t)sizeof (int);
7458348SEric.Yu@Sun.COM 			goto copyout;
7468348SEric.Yu@Sun.COM 
7478348SEric.Yu@Sun.COM 		case SO_RCVLOWAT:
7488348SEric.Yu@Sun.COM 			value = so->so_rcvlowat;
7498348SEric.Yu@Sun.COM 			len = (t_uscalar_t)sizeof (int);
7508348SEric.Yu@Sun.COM 			goto copyout;
7518348SEric.Yu@Sun.COM 
7528348SEric.Yu@Sun.COM 		default:
7538348SEric.Yu@Sun.COM 			option = NULL;
7548348SEric.Yu@Sun.COM 			break;
7558348SEric.Yu@Sun.COM 		}
7568348SEric.Yu@Sun.COM 	}
7578348SEric.Yu@Sun.COM 	if (maxlen > sizeof (buffer)) {
7588348SEric.Yu@Sun.COM 		optbuf = kmem_alloc(maxlen, KM_SLEEP);
7598348SEric.Yu@Sun.COM 	}
7608348SEric.Yu@Sun.COM 	optlen = maxlen;
7618348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
7628348SEric.Yu@Sun.COM 	error = sdp_get_opt((struct sdp_conn_struct_t *)so->so_proto_handle,
7638348SEric.Yu@Sun.COM 	    level, option_name, optbuf, &optlen);
7648348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
7658348SEric.Yu@Sun.COM 	ASSERT(optlen <= maxlen);
7668348SEric.Yu@Sun.COM 	if (error != 0) {
7678348SEric.Yu@Sun.COM 		if (option == NULL) {
7688348SEric.Yu@Sun.COM 			/* We have no fallback value */
7698348SEric.Yu@Sun.COM 			eprintsoline(so, error);
7708348SEric.Yu@Sun.COM 			goto free;
7718348SEric.Yu@Sun.COM 		}
7728348SEric.Yu@Sun.COM 		error = 0;
7738348SEric.Yu@Sun.COM 		goto copyout;
7748348SEric.Yu@Sun.COM 	}
7758348SEric.Yu@Sun.COM 
7768348SEric.Yu@Sun.COM 	option = optbuf;
7778348SEric.Yu@Sun.COM 	len = optlen;
7788348SEric.Yu@Sun.COM 
7798348SEric.Yu@Sun.COM copyout:
7808348SEric.Yu@Sun.COM 	len = MIN(len, maxlen);
7818348SEric.Yu@Sun.COM 	bcopy(option, optval, len);
7828348SEric.Yu@Sun.COM 	*optlenp = len;
7838348SEric.Yu@Sun.COM 
7848348SEric.Yu@Sun.COM free:
7858348SEric.Yu@Sun.COM 	if (optbuf != &buffer) {
7868348SEric.Yu@Sun.COM 		kmem_free(optbuf, maxlen);
7878348SEric.Yu@Sun.COM 	}
7888348SEric.Yu@Sun.COM done:
7898348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
7908348SEric.Yu@Sun.COM 	return (error);
7918348SEric.Yu@Sun.COM }
7928348SEric.Yu@Sun.COM 
7938348SEric.Yu@Sun.COM /*
7948348SEric.Yu@Sun.COM  * Set socket options
7958348SEric.Yu@Sun.COM  */
7968348SEric.Yu@Sun.COM /* ARGSUSED */
7978348SEric.Yu@Sun.COM static int
sosdp_setsockopt(struct sonode * so,int level,int option_name,const void * optval,t_uscalar_t optlen,struct cred * cr)7988348SEric.Yu@Sun.COM sosdp_setsockopt(struct sonode *so, int level, int option_name,
7998348SEric.Yu@Sun.COM     const void *optval, t_uscalar_t optlen, struct cred *cr)
8008348SEric.Yu@Sun.COM {
8018348SEric.Yu@Sun.COM 	void *conn = NULL;
8028348SEric.Yu@Sun.COM 	int error = 0;
8038348SEric.Yu@Sun.COM 
8048348SEric.Yu@Sun.COM 	if (so->so_state & SS_CANTSENDMORE) {
8058348SEric.Yu@Sun.COM 		return (EINVAL);
8068348SEric.Yu@Sun.COM 	}
8078348SEric.Yu@Sun.COM 
8088348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
8098348SEric.Yu@Sun.COM 	so_lock_single(so);
8108348SEric.Yu@Sun.COM 
8118348SEric.Yu@Sun.COM 	if (so->so_type == SOCK_STREAM) {
8128348SEric.Yu@Sun.COM 		conn = (void *)so->so_proto_handle;
8138348SEric.Yu@Sun.COM 	}
8148348SEric.Yu@Sun.COM 
8158348SEric.Yu@Sun.COM 	dprint(2, ("sosdp_setsockopt (%d) - conn %p %d %d \n",
8168348SEric.Yu@Sun.COM 	    so->so_type, conn, level, option_name));
8178348SEric.Yu@Sun.COM 
8188348SEric.Yu@Sun.COM 	if (conn != NULL) {
8198348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
8208348SEric.Yu@Sun.COM 		error = sdp_set_opt((struct sdp_conn_struct_t *)conn, level,
8218348SEric.Yu@Sun.COM 		    option_name, optval, optlen);
8228348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
8238348SEric.Yu@Sun.COM 	}
8248348SEric.Yu@Sun.COM 
8258348SEric.Yu@Sun.COM 	/*
8268348SEric.Yu@Sun.COM 	 * Check for SOL_SOCKET options and record their values.
8278348SEric.Yu@Sun.COM 	 * If we know about a SOL_SOCKET parameter and the transport
8288348SEric.Yu@Sun.COM 	 * failed it with TBADOPT or TOUTSTATE (i.e. ENOPROTOOPT or
8298348SEric.Yu@Sun.COM 	 * EPROTO) we let the setsockopt succeed.
8308348SEric.Yu@Sun.COM 	 */
8318348SEric.Yu@Sun.COM 	if (level == SOL_SOCKET) {
8328348SEric.Yu@Sun.COM 		boolean_t handled = B_FALSE;
8338348SEric.Yu@Sun.COM 
8348348SEric.Yu@Sun.COM 		/* Check parameters */
8358348SEric.Yu@Sun.COM 		switch (option_name) {
8368348SEric.Yu@Sun.COM 		case SO_DEBUG:
8378348SEric.Yu@Sun.COM 		case SO_REUSEADDR:
8388348SEric.Yu@Sun.COM 		case SO_KEEPALIVE:
8398348SEric.Yu@Sun.COM 		case SO_DONTROUTE:
8408348SEric.Yu@Sun.COM 		case SO_BROADCAST:
8418348SEric.Yu@Sun.COM 		case SO_USELOOPBACK:
8428348SEric.Yu@Sun.COM 		case SO_OOBINLINE:
8438348SEric.Yu@Sun.COM 		case SO_SNDBUF:
8448348SEric.Yu@Sun.COM 		case SO_RCVBUF:
8458348SEric.Yu@Sun.COM 		case SO_SNDLOWAT:
8468348SEric.Yu@Sun.COM 		case SO_RCVLOWAT:
8478348SEric.Yu@Sun.COM 		case SO_DGRAM_ERRIND:
8488348SEric.Yu@Sun.COM 			if (optlen != (t_uscalar_t)sizeof (int32_t)) {
8498348SEric.Yu@Sun.COM 				error = EINVAL;
8508348SEric.Yu@Sun.COM 				eprintsoline(so, error);
8518348SEric.Yu@Sun.COM 				goto done;
8528348SEric.Yu@Sun.COM 			}
8538348SEric.Yu@Sun.COM 			ASSERT(optval);
8548348SEric.Yu@Sun.COM 			handled = B_TRUE;
8558348SEric.Yu@Sun.COM 			break;
8568348SEric.Yu@Sun.COM 		case SO_LINGER:
8578348SEric.Yu@Sun.COM 			if (optlen != (t_uscalar_t)sizeof (struct linger)) {
8588348SEric.Yu@Sun.COM 				error = EINVAL;
8598348SEric.Yu@Sun.COM 				eprintsoline(so, error);
8608348SEric.Yu@Sun.COM 				goto done;
8618348SEric.Yu@Sun.COM 			}
8628348SEric.Yu@Sun.COM 			ASSERT(optval);
8638348SEric.Yu@Sun.COM 			handled = B_TRUE;
8648348SEric.Yu@Sun.COM 			break;
8658348SEric.Yu@Sun.COM 		}
8668348SEric.Yu@Sun.COM 
8678348SEric.Yu@Sun.COM #define	intvalue (*(int32_t *)optval)
8688348SEric.Yu@Sun.COM 
8698348SEric.Yu@Sun.COM 		switch (option_name) {
8708348SEric.Yu@Sun.COM 		case SO_TYPE:
8718348SEric.Yu@Sun.COM 		case SO_ERROR:
8728348SEric.Yu@Sun.COM 		case SO_ACCEPTCONN:
8738348SEric.Yu@Sun.COM 			/* Can't be set */
8748348SEric.Yu@Sun.COM 			error = ENOPROTOOPT;
8758348SEric.Yu@Sun.COM 			goto done;
8768348SEric.Yu@Sun.COM 		case SO_LINGER: {
8778348SEric.Yu@Sun.COM 			struct linger *l = (struct linger *)optval;
8788348SEric.Yu@Sun.COM 
8798348SEric.Yu@Sun.COM 			so->so_linger.l_linger = l->l_linger;
8808348SEric.Yu@Sun.COM 			if (l->l_onoff) {
8818348SEric.Yu@Sun.COM 				so->so_linger.l_onoff = SO_LINGER;
8828348SEric.Yu@Sun.COM 				so->so_options |= SO_LINGER;
8838348SEric.Yu@Sun.COM 			} else {
8848348SEric.Yu@Sun.COM 				so->so_linger.l_onoff = 0;
8858348SEric.Yu@Sun.COM 				so->so_options &= ~SO_LINGER;
8868348SEric.Yu@Sun.COM 			}
8878348SEric.Yu@Sun.COM 			break;
8888348SEric.Yu@Sun.COM 		}
8898348SEric.Yu@Sun.COM 
8908348SEric.Yu@Sun.COM 		case SO_DEBUG:
8918348SEric.Yu@Sun.COM 		case SO_REUSEADDR:
8928348SEric.Yu@Sun.COM 		case SO_KEEPALIVE:
8938348SEric.Yu@Sun.COM 		case SO_DONTROUTE:
8948348SEric.Yu@Sun.COM 		case SO_BROADCAST:
8958348SEric.Yu@Sun.COM 		case SO_USELOOPBACK:
8968348SEric.Yu@Sun.COM 		case SO_OOBINLINE:
8978348SEric.Yu@Sun.COM 		case SO_DGRAM_ERRIND:
8988348SEric.Yu@Sun.COM 			if (intvalue != 0) {
8998348SEric.Yu@Sun.COM 				dprintso(so, 1,
9008348SEric.Yu@Sun.COM 				    ("sosdp_setsockopt: setting 0x%x\n",
9018348SEric.Yu@Sun.COM 				    option_name));
9028348SEric.Yu@Sun.COM 				so->so_options |= option_name;
9038348SEric.Yu@Sun.COM 			} else {
9048348SEric.Yu@Sun.COM 				dprintso(so, 1,
9058348SEric.Yu@Sun.COM 				    ("sosdp_setsockopt: clearing 0x%x\n",
9068348SEric.Yu@Sun.COM 				    option_name));
9078348SEric.Yu@Sun.COM 				so->so_options &= ~option_name;
9088348SEric.Yu@Sun.COM 			}
9098348SEric.Yu@Sun.COM 			break;
9108348SEric.Yu@Sun.COM 
9118348SEric.Yu@Sun.COM 		case SO_SNDBUF:
9128348SEric.Yu@Sun.COM 			so->so_sndbuf = intvalue;
9138348SEric.Yu@Sun.COM 			if (so->so_sndlowat > so->so_sndbuf) {
9148348SEric.Yu@Sun.COM 				so->so_sndlowat = so->so_sndbuf;
9158348SEric.Yu@Sun.COM 			}
9168348SEric.Yu@Sun.COM 			break;
9178348SEric.Yu@Sun.COM 		case SO_RCVBUF:
9188348SEric.Yu@Sun.COM 			so->so_rcvbuf = intvalue;
9198348SEric.Yu@Sun.COM 			if (so->so_rcvlowat > so->so_rcvbuf) {
9208348SEric.Yu@Sun.COM 				so->so_rcvlowat = so->so_rcvbuf;
9218348SEric.Yu@Sun.COM 			}
9228348SEric.Yu@Sun.COM 			break;
9238348SEric.Yu@Sun.COM 		case SO_SNDLOWAT:
9248348SEric.Yu@Sun.COM 			if (so->so_sndlowat > so->so_sndbuf) {
9258348SEric.Yu@Sun.COM 				so->so_sndlowat = so->so_sndbuf;
9268348SEric.Yu@Sun.COM 			}
9278348SEric.Yu@Sun.COM 			break;
9288348SEric.Yu@Sun.COM 		case SO_RCVLOWAT:
9298348SEric.Yu@Sun.COM 			if (so->so_rcvlowat > so->so_rcvbuf) {
9308348SEric.Yu@Sun.COM 				so->so_rcvlowat = so->so_rcvbuf;
9318348SEric.Yu@Sun.COM 			}
9328348SEric.Yu@Sun.COM 			break;
9338348SEric.Yu@Sun.COM 		}
9348348SEric.Yu@Sun.COM #undef  intvalue
9358348SEric.Yu@Sun.COM 
9368348SEric.Yu@Sun.COM 		if (error != 0) {
9378348SEric.Yu@Sun.COM 			if ((error == ENOPROTOOPT || error == EPROTO ||
9388348SEric.Yu@Sun.COM 			    error == EINVAL) && handled) {
9398348SEric.Yu@Sun.COM 				dprintso(so, 1,
9408348SEric.Yu@Sun.COM 				    ("sosdp_setsockopt: ignoring error %d "
9418348SEric.Yu@Sun.COM 				    "for 0x%x\n", error, option_name));
9428348SEric.Yu@Sun.COM 				error = 0;
9438348SEric.Yu@Sun.COM 			}
9448348SEric.Yu@Sun.COM 		}
9458348SEric.Yu@Sun.COM 	}
9468348SEric.Yu@Sun.COM 
9478348SEric.Yu@Sun.COM done:
9488348SEric.Yu@Sun.COM 	so_unlock_single(so, SOLOCKED);
9498348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
9508348SEric.Yu@Sun.COM 
9518348SEric.Yu@Sun.COM 	return (error);
9528348SEric.Yu@Sun.COM }
9538348SEric.Yu@Sun.COM 
9548348SEric.Yu@Sun.COM /* ARGSUSED */
9558348SEric.Yu@Sun.COM static int
sosdp_ioctl(struct sonode * so,int cmd,intptr_t arg,int mode,struct cred * cr,int32_t * rvalp)9568348SEric.Yu@Sun.COM sosdp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
9578348SEric.Yu@Sun.COM     struct cred *cr, int32_t *rvalp)
9588348SEric.Yu@Sun.COM {
9598348SEric.Yu@Sun.COM 	int32_t value;
9608348SEric.Yu@Sun.COM 	int error, intval;
9618348SEric.Yu@Sun.COM 	pid_t pid;
9628348SEric.Yu@Sun.COM 
9638348SEric.Yu@Sun.COM 	/* handle socket specific ioctls */
9648348SEric.Yu@Sun.COM 	switch (cmd) {
9658348SEric.Yu@Sun.COM 	case FIONBIO:
9668348SEric.Yu@Sun.COM 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
9678348SEric.Yu@Sun.COM 		    (mode & (int)FKIOCTL))) {
9688348SEric.Yu@Sun.COM 			return (EFAULT);
9698348SEric.Yu@Sun.COM 		}
9708348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
9718348SEric.Yu@Sun.COM 		if (value != 0) {
9728348SEric.Yu@Sun.COM 			so->so_state |= SS_NDELAY;
9738348SEric.Yu@Sun.COM 		} else {
9748348SEric.Yu@Sun.COM 			so->so_state &= ~SS_NDELAY;
9758348SEric.Yu@Sun.COM 		}
9768348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
9778348SEric.Yu@Sun.COM 		return (0);
9788348SEric.Yu@Sun.COM 
9798348SEric.Yu@Sun.COM 	case FIOASYNC:
9808348SEric.Yu@Sun.COM 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
9818348SEric.Yu@Sun.COM 		    (mode & (int)FKIOCTL))) {
9828348SEric.Yu@Sun.COM 			return (EFAULT);
9838348SEric.Yu@Sun.COM 		}
9848348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
9858348SEric.Yu@Sun.COM 
9868348SEric.Yu@Sun.COM 		if (value) {
9878348SEric.Yu@Sun.COM 			/* Turn on SIGIO */
9888348SEric.Yu@Sun.COM 			so->so_state |= SS_ASYNC;
9898348SEric.Yu@Sun.COM 		} else {
9908348SEric.Yu@Sun.COM 			/* Turn off SIGIO */
9918348SEric.Yu@Sun.COM 			so->so_state &= ~SS_ASYNC;
9928348SEric.Yu@Sun.COM 		}
9938348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
9948348SEric.Yu@Sun.COM 		return (0);
9958348SEric.Yu@Sun.COM 
9968348SEric.Yu@Sun.COM 	case SIOCSPGRP:
9978348SEric.Yu@Sun.COM 	case FIOSETOWN:
9988348SEric.Yu@Sun.COM 		if (so_copyin((void *)arg, &pid, sizeof (pid_t),
9998348SEric.Yu@Sun.COM 		    (mode & (int)FKIOCTL))) {
10008348SEric.Yu@Sun.COM 			return (EFAULT);
10018348SEric.Yu@Sun.COM 		}
10028348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
10038348SEric.Yu@Sun.COM 
10048348SEric.Yu@Sun.COM 		error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0;
10058348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
10068348SEric.Yu@Sun.COM 		return (error);
10078348SEric.Yu@Sun.COM 
10088348SEric.Yu@Sun.COM 	case SIOCGPGRP:
10098348SEric.Yu@Sun.COM 	case FIOGETOWN:
10108348SEric.Yu@Sun.COM 		if (so_copyout(&so->so_pgrp, (void *)arg,
10118348SEric.Yu@Sun.COM 		    sizeof (pid_t), (mode & (int)FKIOCTL)))
10128348SEric.Yu@Sun.COM 			return (EFAULT);
10138348SEric.Yu@Sun.COM 		return (0);
10148348SEric.Yu@Sun.COM 
10158348SEric.Yu@Sun.COM 	case SIOCATMARK:
10168348SEric.Yu@Sun.COM 		intval = 0;
10178348SEric.Yu@Sun.COM 		error = sdp_ioctl(
10188348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10198348SEric.Yu@Sun.COM 		    &intval, cr);
10208348SEric.Yu@Sun.COM 		if (so_copyout(&intval, (void *)arg, sizeof (int),
10218348SEric.Yu@Sun.COM 		    (mode & (int)FKIOCTL)))
10228348SEric.Yu@Sun.COM 			return (EFAULT);
10238348SEric.Yu@Sun.COM 		return (0);
10248348SEric.Yu@Sun.COM 
10258348SEric.Yu@Sun.COM 
10268348SEric.Yu@Sun.COM 	case SIOCSENABLESDP: {
10278348SEric.Yu@Sun.COM 		int32_t enable;
10288348SEric.Yu@Sun.COM 
10298348SEric.Yu@Sun.COM 		/*
10308348SEric.Yu@Sun.COM 		 * System wide enable SDP
10318348SEric.Yu@Sun.COM 		 */
10328348SEric.Yu@Sun.COM 
10338348SEric.Yu@Sun.COM 		if (so_copyin((void *)arg, &enable, sizeof (int32_t),
10348348SEric.Yu@Sun.COM 		    mode & (int)FKIOCTL))
10358348SEric.Yu@Sun.COM 			return (EFAULT);
10368348SEric.Yu@Sun.COM 
10378348SEric.Yu@Sun.COM 		error = sdp_ioctl(
10388348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10398348SEric.Yu@Sun.COM 		    &enable, cr);
10408348SEric.Yu@Sun.COM 		if (so_copyout(&enable, (void *)arg,
10418348SEric.Yu@Sun.COM 		    sizeof (int32_t), (mode & (int)FKIOCTL)))
10428348SEric.Yu@Sun.COM 			return (EFAULT);
10438348SEric.Yu@Sun.COM 		return (0);
10448348SEric.Yu@Sun.COM 	}
10458348SEric.Yu@Sun.COM 		/* from strioctl */
10468348SEric.Yu@Sun.COM 	case FIONREAD:
10478348SEric.Yu@Sun.COM 		/*
10488348SEric.Yu@Sun.COM 		 * Return number of bytes of data in all data messages
10498348SEric.Yu@Sun.COM 		 * in queue in "arg".
10508348SEric.Yu@Sun.COM 		 * For stream socket, amount of available data.
10518348SEric.Yu@Sun.COM 		 */
10528348SEric.Yu@Sun.COM 		if (so->so_state & SS_ACCEPTCONN) {
10538348SEric.Yu@Sun.COM 			intval = 0;
10548348SEric.Yu@Sun.COM 		} else {
10558348SEric.Yu@Sun.COM 			mutex_enter(&so->so_lock);
10568348SEric.Yu@Sun.COM 			intval = sdp_polldata(
10578348SEric.Yu@Sun.COM 			    (struct sdp_conn_struct_t *)so->so_proto_handle,
10588348SEric.Yu@Sun.COM 			    SDP_READ);
10598348SEric.Yu@Sun.COM 			mutex_exit(&so->so_lock);
10608348SEric.Yu@Sun.COM 		}
10618348SEric.Yu@Sun.COM 		if (so_copyout(&intval, (void *)arg, sizeof (intval),
10628348SEric.Yu@Sun.COM 		    (mode & (int)FKIOCTL)))
10638348SEric.Yu@Sun.COM 			return (EFAULT);
10648348SEric.Yu@Sun.COM 		return (0);
10658348SEric.Yu@Sun.COM 	default:
10668348SEric.Yu@Sun.COM 		return (EINVAL);
10678348SEric.Yu@Sun.COM 	}
10688348SEric.Yu@Sun.COM }
10698348SEric.Yu@Sun.COM 
10708348SEric.Yu@Sun.COM /*
10718348SEric.Yu@Sun.COM  * Check socktpi_poll() on why so_lock is not held in this function.
10728348SEric.Yu@Sun.COM  */
10738348SEric.Yu@Sun.COM static int
sosdp_poll(struct sonode * so,short events,int anyyet,short * reventsp,struct pollhead ** phpp)10748348SEric.Yu@Sun.COM sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp,
10758348SEric.Yu@Sun.COM     struct pollhead **phpp)
10768348SEric.Yu@Sun.COM {
10778348SEric.Yu@Sun.COM 	short origevents = events;
10788348SEric.Yu@Sun.COM 	int so_state;
10798348SEric.Yu@Sun.COM 
10808348SEric.Yu@Sun.COM 	so_state = so->so_state;
10818348SEric.Yu@Sun.COM 
10828348SEric.Yu@Sun.COM 	ASSERT(so->so_version != SOV_STREAM);
10838348SEric.Yu@Sun.COM 
10848348SEric.Yu@Sun.COM 	if (!(so_state & SS_ISCONNECTED) && (so->so_type == SOCK_STREAM)) {
10858348SEric.Yu@Sun.COM 		/*
10868348SEric.Yu@Sun.COM 		 * Not connected yet - turn off write side events
10878348SEric.Yu@Sun.COM 		 */
10888348SEric.Yu@Sun.COM 		events &= ~(POLLOUT|POLLWRBAND);
10898348SEric.Yu@Sun.COM 	}
10908348SEric.Yu@Sun.COM 
10918348SEric.Yu@Sun.COM 	/*
10928348SEric.Yu@Sun.COM 	 * Check for errors
10938348SEric.Yu@Sun.COM 	 */
10948348SEric.Yu@Sun.COM 	if (so->so_error != 0 &&
10958348SEric.Yu@Sun.COM 	    ((POLLIN|POLLRDNORM|POLLOUT) & origevents)  != 0) {
10968348SEric.Yu@Sun.COM 		*reventsp = (POLLIN|POLLRDNORM|POLLOUT) & origevents;
10978348SEric.Yu@Sun.COM 		return (0);
10988348SEric.Yu@Sun.COM 	}
10998348SEric.Yu@Sun.COM 
11008348SEric.Yu@Sun.COM 	*reventsp = 0;
11018348SEric.Yu@Sun.COM 
11028348SEric.Yu@Sun.COM 	/*
11038348SEric.Yu@Sun.COM 	 * Don't mark socket as writable until TX queued data is
11048348SEric.Yu@Sun.COM 	 * below watermark.
11058348SEric.Yu@Sun.COM 	 */
11068348SEric.Yu@Sun.COM 	if (so->so_type == SOCK_STREAM) {
11078348SEric.Yu@Sun.COM 		if (sdp_polldata(
11088348SEric.Yu@Sun.COM 		    (struct sdp_conn_struct_t *)so->so_proto_handle,
11098348SEric.Yu@Sun.COM 		    SDP_XMIT)) {
11108348SEric.Yu@Sun.COM 			*reventsp |= POLLOUT & events;
11118348SEric.Yu@Sun.COM 		}
11128348SEric.Yu@Sun.COM 	} else {
11138348SEric.Yu@Sun.COM 		*reventsp = 0;
11148348SEric.Yu@Sun.COM 		goto done;
11158348SEric.Yu@Sun.COM 	}
11168348SEric.Yu@Sun.COM 
11178348SEric.Yu@Sun.COM 	if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle,
11188348SEric.Yu@Sun.COM 	    SDP_READ)) {
11198348SEric.Yu@Sun.COM 		*reventsp |= (POLLIN|POLLRDNORM) & events;
11208348SEric.Yu@Sun.COM 	}
11218348SEric.Yu@Sun.COM 
1122*12643SAnders.Persson@Sun.COM 	if ((so_state & SS_CANTRCVMORE) || (so->so_acceptq_len > 0)) {
11238348SEric.Yu@Sun.COM 		*reventsp |= (POLLIN|POLLRDNORM) & events;
11248348SEric.Yu@Sun.COM 	}
11258348SEric.Yu@Sun.COM 
11268348SEric.Yu@Sun.COM done:
11278348SEric.Yu@Sun.COM 	if (!*reventsp && !anyyet) {
11288348SEric.Yu@Sun.COM 		*phpp = &so->so_poll_list;
11298348SEric.Yu@Sun.COM 	}
11308348SEric.Yu@Sun.COM 
11318348SEric.Yu@Sun.COM 	return (0);
11328348SEric.Yu@Sun.COM }
11338348SEric.Yu@Sun.COM 
11348348SEric.Yu@Sun.COM /* ARGSUSED */
11358348SEric.Yu@Sun.COM static int
sosdp_close(struct sonode * so,int flag,struct cred * cr)11368348SEric.Yu@Sun.COM sosdp_close(struct sonode *so, int flag, struct cred *cr)
11378348SEric.Yu@Sun.COM {
11388348SEric.Yu@Sun.COM 	int error = 0;
11398348SEric.Yu@Sun.COM 
11408348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
11418348SEric.Yu@Sun.COM 	so_lock_single(so);
11428348SEric.Yu@Sun.COM 	/*
11438348SEric.Yu@Sun.COM 	 * Need to set flags as there might be ops in progress on
11448348SEric.Yu@Sun.COM 	 * this socket.
11458348SEric.Yu@Sun.COM 	 *
11468348SEric.Yu@Sun.COM 	 * If socket already disconnected/disconnecting,
11478348SEric.Yu@Sun.COM 	 * don't send signal (again).
11488348SEric.Yu@Sun.COM 	 */
11498348SEric.Yu@Sun.COM 	soisdisconnected(so, 0);
11508348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
11518348SEric.Yu@Sun.COM 
11528348SEric.Yu@Sun.COM 	/*
11538348SEric.Yu@Sun.COM 	 * Initiate connection shutdown.
11548348SEric.Yu@Sun.COM 	 */
11558348SEric.Yu@Sun.COM 	error = sdp_disconnect((struct sdp_conn_struct_t *)so->so_proto_handle,
11568348SEric.Yu@Sun.COM 	    flag);
11578348SEric.Yu@Sun.COM 
11588348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
11598348SEric.Yu@Sun.COM 	so_unlock_single(so, SOLOCKED);
1160*12643SAnders.Persson@Sun.COM 	so_notify_disconnected(so, B_FALSE, error);
11618348SEric.Yu@Sun.COM 
11628348SEric.Yu@Sun.COM 	return (error);
11638348SEric.Yu@Sun.COM }
11648348SEric.Yu@Sun.COM 
11658348SEric.Yu@Sun.COM /* ARGSUSED */
11668348SEric.Yu@Sun.COM void
sosdp_fini(struct sonode * so,struct cred * cr)11678348SEric.Yu@Sun.COM sosdp_fini(struct sonode *so, struct cred *cr)
11688348SEric.Yu@Sun.COM {
11698348SEric.Yu@Sun.COM 	dprint(3, ("sosdp_fini: so:%p so_proto_handle:%p", (void *)so,
11708348SEric.Yu@Sun.COM 	    (void *)so->so_proto_handle));
11718348SEric.Yu@Sun.COM 
11728348SEric.Yu@Sun.COM 	ASSERT(so->so_ops == &sosdp_sonodeops);
11738348SEric.Yu@Sun.COM 
11748348SEric.Yu@Sun.COM 	if (so->so_proto_handle != NULL)
11758348SEric.Yu@Sun.COM 		sdp_close((struct sdp_conn_struct_t *)so->so_proto_handle);
11768348SEric.Yu@Sun.COM 	so->so_proto_handle = NULL;
11778348SEric.Yu@Sun.COM 
11788348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
11798348SEric.Yu@Sun.COM 
118010836SAnders.Persson@Sun.COM 	so_acceptq_flush(so, B_TRUE);
11818348SEric.Yu@Sun.COM 
11828348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
11838348SEric.Yu@Sun.COM 
11848348SEric.Yu@Sun.COM 	sonode_fini(so);
11858348SEric.Yu@Sun.COM }
11868348SEric.Yu@Sun.COM 
11878348SEric.Yu@Sun.COM /*
11888348SEric.Yu@Sun.COM  * Upcalls from SDP
11898348SEric.Yu@Sun.COM  */
11908348SEric.Yu@Sun.COM 
11918348SEric.Yu@Sun.COM /*
11928348SEric.Yu@Sun.COM  * Incoming connection on listen socket.
11938348SEric.Yu@Sun.COM  */
11948348SEric.Yu@Sun.COM static void *
sdp_sock_newconn(void * parenthandle,void * connind)11958348SEric.Yu@Sun.COM sdp_sock_newconn(void *parenthandle, void *connind)
11968348SEric.Yu@Sun.COM {
11978348SEric.Yu@Sun.COM 	struct sonode *lso = parenthandle;
11988348SEric.Yu@Sun.COM 	struct sonode *nso;
11998348SEric.Yu@Sun.COM 	int error;
12008348SEric.Yu@Sun.COM 
12018348SEric.Yu@Sun.COM 	ASSERT(lso->so_state & SS_ACCEPTCONN);
12028348SEric.Yu@Sun.COM 	ASSERT(lso->so_proto_handle != NULL); /* closed conn */
12038348SEric.Yu@Sun.COM 	ASSERT(lso->so_type == SOCK_STREAM);
12048348SEric.Yu@Sun.COM 
12058348SEric.Yu@Sun.COM 	dprint(3, ("sosdp_newconn A: so:%p so_proto_handle:%p", (void *)lso,
12068348SEric.Yu@Sun.COM 	    (void *)lso->so_proto_handle));
12078348SEric.Yu@Sun.COM 
12088348SEric.Yu@Sun.COM 	/*
12098348SEric.Yu@Sun.COM 	 * Check current # of queued conns against backlog
12108348SEric.Yu@Sun.COM 	 */
12118348SEric.Yu@Sun.COM 	if (lso->so_rcv_queued >= lso->so_backlog) {
12128348SEric.Yu@Sun.COM 		return (NULL);
12138348SEric.Yu@Sun.COM 	}
12148348SEric.Yu@Sun.COM 
12158348SEric.Yu@Sun.COM 	nso = socket_newconn(lso, connind, NULL, SOCKET_NOSLEEP, &error);
12168348SEric.Yu@Sun.COM 	if (nso == NULL) {
12178348SEric.Yu@Sun.COM 		eprintsoline(lso, error);
12188348SEric.Yu@Sun.COM 		return (NULL);
12198348SEric.Yu@Sun.COM 	}
12208348SEric.Yu@Sun.COM 
12218348SEric.Yu@Sun.COM 	dprint(2, ("sdp_stream_newconn: new %p\n", (void *)nso));
12228348SEric.Yu@Sun.COM 
12238348SEric.Yu@Sun.COM 	(void) so_acceptq_enqueue(lso, nso);
12248348SEric.Yu@Sun.COM 
12258348SEric.Yu@Sun.COM 	mutex_enter(&lso->so_lock);
12268348SEric.Yu@Sun.COM 	so_notify_newconn(lso);
12278348SEric.Yu@Sun.COM 	return (nso);
12288348SEric.Yu@Sun.COM }
12298348SEric.Yu@Sun.COM 
12308348SEric.Yu@Sun.COM /*
12318348SEric.Yu@Sun.COM  * For outgoing connections, the connection has been established.
12328348SEric.Yu@Sun.COM  */
12338348SEric.Yu@Sun.COM static void
sdp_sock_connected(void * handle)12348348SEric.Yu@Sun.COM sdp_sock_connected(void *handle)
12358348SEric.Yu@Sun.COM {
12368348SEric.Yu@Sun.COM 	struct sonode *so = handle;
12378348SEric.Yu@Sun.COM 
12388348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
12398348SEric.Yu@Sun.COM 	dprint(3, ("sosdp_connected C: so:%p so_proto_handle:%p", (void *)so,
12408348SEric.Yu@Sun.COM 	    (void *)so->so_proto_handle));
12418348SEric.Yu@Sun.COM 
12428348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
12438348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle); /* closed conn */
12448348SEric.Yu@Sun.COM 
12458348SEric.Yu@Sun.COM 	ASSERT(!(so->so_state & SS_ACCEPTCONN));
12468348SEric.Yu@Sun.COM 	soisconnected(so);
12478348SEric.Yu@Sun.COM 
12488348SEric.Yu@Sun.COM 	so_notify_connected(so);
12498348SEric.Yu@Sun.COM }
12508348SEric.Yu@Sun.COM 
12518348SEric.Yu@Sun.COM /*
12528348SEric.Yu@Sun.COM  * Connection got disconnected. Either with an error, or through
12538348SEric.Yu@Sun.COM  * normal handshake.
12548348SEric.Yu@Sun.COM  */
12558348SEric.Yu@Sun.COM static void
sdp_sock_disconnected(void * handle,int error)12568348SEric.Yu@Sun.COM sdp_sock_disconnected(void *handle, int error)
12578348SEric.Yu@Sun.COM {
12588348SEric.Yu@Sun.COM 	struct sonode *so = handle;
12598348SEric.Yu@Sun.COM 
12608348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
12618348SEric.Yu@Sun.COM 	dprint(2, ("sosdp_disconnected C: so:%p so_proto_handle:%p error:%d",
12628348SEric.Yu@Sun.COM 	    (void *)so, (void *)so->so_proto_handle, error));
12638348SEric.Yu@Sun.COM 
12648348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
12658348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
12668348SEric.Yu@Sun.COM 
12678348SEric.Yu@Sun.COM 	soisdisconnected(so, error);
1268*12643SAnders.Persson@Sun.COM 	so_notify_disconnected(so, B_FALSE, error);
12698348SEric.Yu@Sun.COM }
12708348SEric.Yu@Sun.COM 
12718348SEric.Yu@Sun.COM /*
12728348SEric.Yu@Sun.COM  * Incoming data.
12738348SEric.Yu@Sun.COM  */
12748348SEric.Yu@Sun.COM /*ARGSUSED*/
12758348SEric.Yu@Sun.COM static int
sdp_sock_recv(void * handle,mblk_t * mp,int flags)12768348SEric.Yu@Sun.COM sdp_sock_recv(void *handle, mblk_t *mp, int flags)
12778348SEric.Yu@Sun.COM {
12788348SEric.Yu@Sun.COM 	struct sonode *so = handle;
12798348SEric.Yu@Sun.COM 
12808348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
12818348SEric.Yu@Sun.COM 
12828348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
12838348SEric.Yu@Sun.COM 	so_notify_data(so, 0);
12848348SEric.Yu@Sun.COM 
12858348SEric.Yu@Sun.COM 	return (so->so_rcvbuf);
12868348SEric.Yu@Sun.COM }
12878348SEric.Yu@Sun.COM 
12888348SEric.Yu@Sun.COM /*
12898348SEric.Yu@Sun.COM  * TX queued data got acknowledged.
12908348SEric.Yu@Sun.COM  */
12918348SEric.Yu@Sun.COM static void
sdp_sock_xmitted(void * handle,int writeable)12928348SEric.Yu@Sun.COM sdp_sock_xmitted(void *handle, int writeable)
12938348SEric.Yu@Sun.COM {
12948348SEric.Yu@Sun.COM 	struct sonode *so = handle;
12958348SEric.Yu@Sun.COM 
12968348SEric.Yu@Sun.COM 	dprint(4, ("sosdp_sock_xmitted: so:%p so_proto_handle:%p txq:%d",
12978348SEric.Yu@Sun.COM 	    (void *)so, (void *)so->so_proto_handle, writeable));
12988348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
12998348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13008348SEric.Yu@Sun.COM 
13018348SEric.Yu@Sun.COM 
13028348SEric.Yu@Sun.COM 	/*
13038348SEric.Yu@Sun.COM 	 * Only do pollwakeup if the amount of queued data is less than
13048348SEric.Yu@Sun.COM 	 * watermark.
13058348SEric.Yu@Sun.COM 	 */
13068348SEric.Yu@Sun.COM 	if (!writeable) {
13078348SEric.Yu@Sun.COM 		so_notify_writable(so);
13088348SEric.Yu@Sun.COM 	} else {
13098348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
13108348SEric.Yu@Sun.COM 	}
13118348SEric.Yu@Sun.COM }
13128348SEric.Yu@Sun.COM 
13138348SEric.Yu@Sun.COM 
13148348SEric.Yu@Sun.COM /*
13158348SEric.Yu@Sun.COM  * SDP notifies socket for presence of urgent data.
13168348SEric.Yu@Sun.COM  */
13178348SEric.Yu@Sun.COM static void
sdp_sock_urgdata(void * handle)13188348SEric.Yu@Sun.COM sdp_sock_urgdata(void *handle)
13198348SEric.Yu@Sun.COM {
13208348SEric.Yu@Sun.COM 	struct sonode *so = handle;
13218348SEric.Yu@Sun.COM 
13228348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
13238348SEric.Yu@Sun.COM 
13248348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
13258348SEric.Yu@Sun.COM 
13268348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13278348SEric.Yu@Sun.COM 	so_notify_oobsig(so);
13288348SEric.Yu@Sun.COM }
13298348SEric.Yu@Sun.COM 
13308348SEric.Yu@Sun.COM /*
13318348SEric.Yu@Sun.COM  * SDP notifies socket about receiving of conn close request from peer side.
13328348SEric.Yu@Sun.COM  */
13338348SEric.Yu@Sun.COM static void
sdp_sock_ordrel(void * handle)13348348SEric.Yu@Sun.COM sdp_sock_ordrel(void *handle)
13358348SEric.Yu@Sun.COM {
13368348SEric.Yu@Sun.COM 	struct sonode *so = handle;
13378348SEric.Yu@Sun.COM 
13388348SEric.Yu@Sun.COM 	ASSERT(so->so_type == SOCK_STREAM);
13398348SEric.Yu@Sun.COM 
13408348SEric.Yu@Sun.COM 	dprint(4, ("sdp_sock_ordrel : so:%p, so_proto_handle:%p",
13418348SEric.Yu@Sun.COM 	    (void *)so, (void *)so->so_proto_handle));
13428348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
13438348SEric.Yu@Sun.COM 	socantrcvmore(so);
13448348SEric.Yu@Sun.COM 	so_notify_eof(so);
13458348SEric.Yu@Sun.COM }
13468348SEric.Yu@Sun.COM 
13478348SEric.Yu@Sun.COM static void
sdp_sock_connfail(void * handle,int error)13488348SEric.Yu@Sun.COM sdp_sock_connfail(void *handle, int error)
13498348SEric.Yu@Sun.COM {
13508348SEric.Yu@Sun.COM 	struct sonode *so = handle;
13518348SEric.Yu@Sun.COM 
13528348SEric.Yu@Sun.COM 	dprint(3, ("sosdp_conn Failed: so:%p so_proto_handle:%p", (void *)so,
13538348SEric.Yu@Sun.COM 	    (void *)so->so_proto_handle));
13548348SEric.Yu@Sun.COM 	mutex_enter(&so->so_lock);
13558348SEric.Yu@Sun.COM 	ASSERT(so->so_proto_handle != NULL); /* closed conn */
13568348SEric.Yu@Sun.COM 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
13578348SEric.Yu@Sun.COM 	so->so_error = (ushort_t)error;
13588348SEric.Yu@Sun.COM 	mutex_exit(&so->so_lock);
13598348SEric.Yu@Sun.COM 	cv_broadcast(&so->so_state_cv);
13608348SEric.Yu@Sun.COM }
1361