xref: /titanic_51/usr/src/uts/common/inet/sockmods/socksctp.c (revision a215d4eb400e2ff52f7a17e0781964c37aabfc04)
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 /*
233e95bd4aSAnders Persson  * Copyright (c) 2005, 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>
380f1702c5SYu Xiangning #include <sys/filio.h>
39634e26ecSCasper H.S. Dik #include <sys/policy.h>
400f1702c5SYu Xiangning 
410f1702c5SYu Xiangning #include <sys/project.h>
420f1702c5SYu Xiangning #include <sys/tihdr.h>
430f1702c5SYu Xiangning #include <sys/strsubr.h>
440f1702c5SYu Xiangning #include <sys/esunddi.h>
450f1702c5SYu Xiangning #include <sys/ddi.h>
460f1702c5SYu Xiangning 
470f1702c5SYu Xiangning #include <sys/sockio.h>
480f1702c5SYu Xiangning #include <sys/socket.h>
490f1702c5SYu Xiangning #include <sys/socketvar.h>
500f1702c5SYu Xiangning #include <sys/strsun.h>
510f1702c5SYu Xiangning 
520f1702c5SYu Xiangning #include <netinet/sctp.h>
530f1702c5SYu Xiangning #include <inet/sctp_itf.h>
540f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
550f1702c5SYu Xiangning #include "socksctp.h"
560f1702c5SYu Xiangning 
570f1702c5SYu Xiangning /*
580f1702c5SYu Xiangning  * SCTP sockfs sonode operations, 1-1 socket
590f1702c5SYu Xiangning  */
600f1702c5SYu Xiangning static int sosctp_init(struct sonode *, struct sonode *, struct cred *, int);
610f1702c5SYu Xiangning static int sosctp_accept(struct sonode *, int, struct cred *, struct sonode **);
620f1702c5SYu Xiangning static int sosctp_bind(struct sonode *, struct sockaddr *, socklen_t, int,
630f1702c5SYu Xiangning     struct cred *);
640f1702c5SYu Xiangning static int sosctp_listen(struct sonode *, int, struct cred *);
653e95bd4aSAnders Persson static int sosctp_connect(struct sonode *, struct sockaddr *, socklen_t,
660f1702c5SYu Xiangning     int, int, struct cred *);
670f1702c5SYu Xiangning static int sosctp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *,
680f1702c5SYu Xiangning     struct cred *);
690f1702c5SYu Xiangning static int sosctp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
700f1702c5SYu Xiangning     struct cred *);
710f1702c5SYu Xiangning static int sosctp_getpeername(struct sonode *, struct sockaddr *, socklen_t *,
720f1702c5SYu Xiangning     boolean_t, struct cred *);
730f1702c5SYu Xiangning static int sosctp_getsockname(struct sonode *, struct sockaddr *, socklen_t *,
740f1702c5SYu Xiangning     struct cred *);
750f1702c5SYu Xiangning static int sosctp_shutdown(struct sonode *, int, struct cred *);
760f1702c5SYu Xiangning static int sosctp_getsockopt(struct sonode *, int, int, void *, socklen_t *,
770f1702c5SYu Xiangning     int, struct cred *);
780f1702c5SYu Xiangning static int sosctp_setsockopt(struct sonode *, int, int, const void *,
790f1702c5SYu Xiangning     socklen_t, struct cred *);
800f1702c5SYu Xiangning static int sosctp_ioctl(struct sonode *, int, intptr_t, int, struct cred *,
810f1702c5SYu Xiangning     int32_t *);
820f1702c5SYu Xiangning static int sosctp_close(struct sonode *, int, struct cred *);
830f1702c5SYu Xiangning void sosctp_fini(struct sonode *, struct cred *);
840f1702c5SYu Xiangning 
850f1702c5SYu Xiangning /*
860f1702c5SYu Xiangning  * SCTP sockfs sonode operations, 1-N socket
870f1702c5SYu Xiangning  */
883e95bd4aSAnders Persson static int sosctp_seq_connect(struct sonode *, struct sockaddr *,
890f1702c5SYu Xiangning     socklen_t, int, int, struct cred *);
900f1702c5SYu Xiangning static int sosctp_seq_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
910f1702c5SYu Xiangning     struct cred *);
920f1702c5SYu Xiangning 
930f1702c5SYu Xiangning /*
940f1702c5SYu Xiangning  * Socket association upcalls, 1-N socket connection
950f1702c5SYu Xiangning  */
960f1702c5SYu Xiangning sock_upper_handle_t sctp_assoc_newconn(sock_upper_handle_t,
970f1702c5SYu Xiangning     sock_lower_handle_t, sock_downcalls_t *, struct cred *, pid_t,
980f1702c5SYu Xiangning     sock_upcalls_t **);
990f1702c5SYu Xiangning static void sctp_assoc_connected(sock_upper_handle_t, sock_connid_t,
1000f1702c5SYu Xiangning     struct cred *, pid_t);
1010f1702c5SYu Xiangning static int sctp_assoc_disconnected(sock_upper_handle_t, sock_connid_t, int);
1020f1702c5SYu Xiangning static void sctp_assoc_disconnecting(sock_upper_handle_t, sock_opctl_action_t,
1030f1702c5SYu Xiangning     uintptr_t arg);
1040f1702c5SYu Xiangning static ssize_t sctp_assoc_recv(sock_upper_handle_t, mblk_t *, size_t, int,
1050f1702c5SYu Xiangning     int *, boolean_t *);
1060f1702c5SYu Xiangning static void sctp_assoc_xmitted(sock_upper_handle_t, boolean_t);
1070f1702c5SYu Xiangning static void sctp_assoc_properties(sock_upper_handle_t,
1080f1702c5SYu Xiangning     struct sock_proto_props *);
1090f1702c5SYu Xiangning 
1100f1702c5SYu Xiangning sonodeops_t sosctp_sonodeops = {
1110f1702c5SYu Xiangning 	sosctp_init,			/* sop_init	*/
1120f1702c5SYu Xiangning 	sosctp_accept,			/* sop_accept	*/
1130f1702c5SYu Xiangning 	sosctp_bind,			/* sop_bind	*/
1140f1702c5SYu Xiangning 	sosctp_listen,			/* sop_listen	*/
1150f1702c5SYu Xiangning 	sosctp_connect,			/* sop_connect	*/
1160f1702c5SYu Xiangning 	sosctp_recvmsg,			/* sop_recvmsg	*/
1170f1702c5SYu Xiangning 	sosctp_sendmsg,			/* sop_sendmsg	*/
1180f1702c5SYu Xiangning 	so_sendmblk_notsupp,		/* sop_sendmblk	*/
1190f1702c5SYu Xiangning 	sosctp_getpeername,		/* sop_getpeername */
1200f1702c5SYu Xiangning 	sosctp_getsockname,		/* sop_getsockname */
1210f1702c5SYu Xiangning 	sosctp_shutdown,		/* sop_shutdown */
1220f1702c5SYu Xiangning 	sosctp_getsockopt,		/* sop_getsockopt */
1230f1702c5SYu Xiangning 	sosctp_setsockopt,		/* sop_setsockopt */
1240f1702c5SYu Xiangning 	sosctp_ioctl,			/* sop_ioctl	*/
1250f1702c5SYu Xiangning 	so_poll,			/* sop_poll	*/
1260f1702c5SYu Xiangning 	sosctp_close,			/* sop_close 	*/
1270f1702c5SYu Xiangning };
1280f1702c5SYu Xiangning 
1290f1702c5SYu Xiangning sonodeops_t sosctp_seq_sonodeops = {
1300f1702c5SYu Xiangning 	sosctp_init,			/* sop_init	*/
1310f1702c5SYu Xiangning 	so_accept_notsupp,		/* sop_accept	*/
1320f1702c5SYu Xiangning 	sosctp_bind,			/* sop_bind	*/
1330f1702c5SYu Xiangning 	sosctp_listen,			/* sop_listen	*/
1340f1702c5SYu Xiangning 	sosctp_seq_connect,		/* sop_connect	*/
1350f1702c5SYu Xiangning 	sosctp_recvmsg,			/* sop_recvmsg	*/
1360f1702c5SYu Xiangning 	sosctp_seq_sendmsg,		/* sop_sendmsg	*/
1370f1702c5SYu Xiangning 	so_sendmblk_notsupp,		/* sop_sendmblk	*/
1380f1702c5SYu Xiangning 	so_getpeername_notsupp,		/* sop_getpeername */
1390f1702c5SYu Xiangning 	sosctp_getsockname,		/* sop_getsockname */
1400f1702c5SYu Xiangning 	so_shutdown_notsupp,		/* sop_shutdown */
1410f1702c5SYu Xiangning 	sosctp_getsockopt,		/* sop_getsockopt */
1420f1702c5SYu Xiangning 	sosctp_setsockopt,		/* sop_setsockopt */
1430f1702c5SYu Xiangning 	sosctp_ioctl,			/* sop_ioctl	*/
1440f1702c5SYu Xiangning 	so_poll,			/* sop_poll	*/
1450f1702c5SYu Xiangning 	sosctp_close,			/* sop_close 	*/
1460f1702c5SYu Xiangning };
1470f1702c5SYu Xiangning 
148*a215d4ebSKacheong Poon /* All the upcalls expect the upper handle to be sonode. */
1490f1702c5SYu Xiangning sock_upcalls_t sosctp_sock_upcalls = {
1500f1702c5SYu Xiangning 	so_newconn,
1510f1702c5SYu Xiangning 	so_connected,
1520f1702c5SYu Xiangning 	so_disconnected,
1530f1702c5SYu Xiangning 	so_opctl,
1540f1702c5SYu Xiangning 	so_queue_msg,
1550f1702c5SYu Xiangning 	so_set_prop,
1560f1702c5SYu Xiangning 	so_txq_full,
1570f1702c5SYu Xiangning 	NULL,			/* su_signal_oob */
1580f1702c5SYu Xiangning };
1590f1702c5SYu Xiangning 
160*a215d4ebSKacheong Poon /* All the upcalls expect the upper handle to be sctp_sonode/sctp_soassoc. */
1610f1702c5SYu Xiangning sock_upcalls_t sosctp_assoc_upcalls = {
1620f1702c5SYu Xiangning 	sctp_assoc_newconn,
1630f1702c5SYu Xiangning 	sctp_assoc_connected,
1640f1702c5SYu Xiangning 	sctp_assoc_disconnected,
1650f1702c5SYu Xiangning 	sctp_assoc_disconnecting,
1660f1702c5SYu Xiangning 	sctp_assoc_recv,
1670f1702c5SYu Xiangning 	sctp_assoc_properties,
1680f1702c5SYu Xiangning 	sctp_assoc_xmitted,
1690f1702c5SYu Xiangning 	NULL,			/* su_recv_space */
1700f1702c5SYu Xiangning 	NULL,			/* su_signal_oob */
1710f1702c5SYu Xiangning };
1720f1702c5SYu Xiangning 
1730f1702c5SYu Xiangning /* ARGSUSED */
1740f1702c5SYu Xiangning static int
1750f1702c5SYu Xiangning sosctp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1760f1702c5SYu Xiangning {
1770f1702c5SYu Xiangning 	struct sctp_sonode *ss;
1780f1702c5SYu Xiangning 	struct sctp_sonode *pss;
1790f1702c5SYu Xiangning 	sctp_sockbuf_limits_t sbl;
180634e26ecSCasper H.S. Dik 	int err;
1810f1702c5SYu Xiangning 
1820f1702c5SYu Xiangning 	ss = SOTOSSO(so);
1830f1702c5SYu Xiangning 
1840f1702c5SYu Xiangning 	if (pso != NULL) {
1850f1702c5SYu Xiangning 		/*
1860f1702c5SYu Xiangning 		 * Passive open, just inherit settings from parent. We should
1870f1702c5SYu Xiangning 		 * not end up here for SOCK_SEQPACKET type sockets, since no
1880f1702c5SYu Xiangning 		 * new sonode is created in that case.
1890f1702c5SYu Xiangning 		 */
1900f1702c5SYu Xiangning 		ASSERT(so->so_type == SOCK_STREAM);
1910f1702c5SYu Xiangning 		pss = SOTOSSO(pso);
1920f1702c5SYu Xiangning 
1930f1702c5SYu Xiangning 		mutex_enter(&pso->so_lock);
1940f1702c5SYu Xiangning 		so->so_state |= (SS_ISBOUND | SS_ISCONNECTED |
1950f1702c5SYu Xiangning 		    (pso->so_state & SS_ASYNC));
1960f1702c5SYu Xiangning 		sosctp_so_inherit(pss, ss);
1970f1702c5SYu Xiangning 		so->so_proto_props = pso->so_proto_props;
1980f1702c5SYu Xiangning 		so->so_mode = pso->so_mode;
1990f1702c5SYu Xiangning 		mutex_exit(&pso->so_lock);
2000f1702c5SYu Xiangning 
2010f1702c5SYu Xiangning 		return (0);
2020f1702c5SYu Xiangning 	}
2030f1702c5SYu Xiangning 
204634e26ecSCasper H.S. Dik 	if ((err = secpolicy_basic_net_access(cr)) != 0)
205634e26ecSCasper H.S. Dik 		return (err);
206634e26ecSCasper H.S. Dik 
207*a215d4ebSKacheong Poon 	if (so->so_type == SOCK_STREAM) {
208*a215d4ebSKacheong Poon 		so->so_proto_handle = (sock_lower_handle_t)sctp_create(so,
209*a215d4ebSKacheong Poon 		    NULL, so->so_family, so->so_type, SCTP_CAN_BLOCK,
210*a215d4ebSKacheong Poon 		    &sosctp_sock_upcalls, &sbl, cr);
211*a215d4ebSKacheong Poon 		so->so_mode = SM_CONNREQUIRED;
212*a215d4ebSKacheong Poon 	} else {
213*a215d4ebSKacheong Poon 		ASSERT(so->so_type == SOCK_SEQPACKET);
214*a215d4ebSKacheong Poon 		so->so_proto_handle = (sock_lower_handle_t)sctp_create(ss,
215*a215d4ebSKacheong Poon 		    NULL, so->so_family, so->so_type, SCTP_CAN_BLOCK,
216*a215d4ebSKacheong Poon 		    &sosctp_assoc_upcalls, &sbl, cr);
217*a215d4ebSKacheong Poon 	}
218*a215d4ebSKacheong Poon 
2190f1702c5SYu Xiangning 	if (so->so_proto_handle == NULL)
2200f1702c5SYu Xiangning 		return (ENOMEM);
2210f1702c5SYu Xiangning 
2220f1702c5SYu Xiangning 	so->so_rcvbuf = sbl.sbl_rxbuf;
2230f1702c5SYu Xiangning 	so->so_rcvlowat = sbl.sbl_rxlowat;
2240f1702c5SYu Xiangning 	so->so_sndbuf = sbl.sbl_txbuf;
2250f1702c5SYu Xiangning 	so->so_sndlowat = sbl.sbl_txlowat;
2260f1702c5SYu Xiangning 
2270f1702c5SYu Xiangning 	return (0);
2280f1702c5SYu Xiangning }
2290f1702c5SYu Xiangning 
2300f1702c5SYu Xiangning /*
2310f1702c5SYu Xiangning  * Accept incoming connection.
2320f1702c5SYu Xiangning  */
2330f1702c5SYu Xiangning /*ARGSUSED*/
2340f1702c5SYu Xiangning static int
2350f1702c5SYu Xiangning sosctp_accept(struct sonode *so, int fflag, struct cred *cr,
2360f1702c5SYu Xiangning     struct sonode **nsop)
2370f1702c5SYu Xiangning {
2380f1702c5SYu Xiangning 	int error = 0;
2390f1702c5SYu Xiangning 
2400f1702c5SYu Xiangning 	if ((so->so_state & SS_ACCEPTCONN) == 0)
2410f1702c5SYu Xiangning 		return (EINVAL);
2420f1702c5SYu Xiangning 
2430f1702c5SYu Xiangning 	error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)), nsop);
2440f1702c5SYu Xiangning 
2450f1702c5SYu Xiangning 	return (error);
2460f1702c5SYu Xiangning }
2470f1702c5SYu Xiangning 
2480f1702c5SYu Xiangning /*
2490f1702c5SYu Xiangning  * Bind local endpoint.
2500f1702c5SYu Xiangning  */
2510f1702c5SYu Xiangning /*ARGSUSED*/
2520f1702c5SYu Xiangning static int
2530f1702c5SYu Xiangning sosctp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
2540f1702c5SYu Xiangning     int flags, struct cred *cr)
2550f1702c5SYu Xiangning {
2560f1702c5SYu Xiangning 	int error;
2570f1702c5SYu Xiangning 
2580f1702c5SYu Xiangning 	if (!(flags & _SOBIND_LOCK_HELD)) {
2590f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
2600f1702c5SYu Xiangning 		so_lock_single(so);	/* Set SOLOCKED */
2610f1702c5SYu Xiangning 	} else {
2620f1702c5SYu Xiangning 		ASSERT(MUTEX_HELD(&so->so_lock));
2630f1702c5SYu Xiangning 	}
2640f1702c5SYu Xiangning 
2650f1702c5SYu Xiangning 	/*
2660f1702c5SYu Xiangning 	 * X/Open requires this check
2670f1702c5SYu Xiangning 	 */
2680f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE) {
2690f1702c5SYu Xiangning 		error = EINVAL;
2700f1702c5SYu Xiangning 		goto done;
2710f1702c5SYu Xiangning 	}
2720f1702c5SYu Xiangning 
2730f1702c5SYu Xiangning 
2740f1702c5SYu Xiangning 	/*
2750f1702c5SYu Xiangning 	 * Protocol module does address family checks.
2760f1702c5SYu Xiangning 	 */
2770f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
2780f1702c5SYu Xiangning 
2790f1702c5SYu Xiangning 	error = sctp_bind((struct sctp_s *)so->so_proto_handle, name, namelen);
2800f1702c5SYu Xiangning 
2810f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
2820f1702c5SYu Xiangning 	if (error == 0) {
2830f1702c5SYu Xiangning 		so->so_state |= SS_ISBOUND;
2840f1702c5SYu Xiangning 	} else {
2850f1702c5SYu Xiangning 		eprintsoline(so, error);
2860f1702c5SYu Xiangning 	}
2870f1702c5SYu Xiangning done:
2880f1702c5SYu Xiangning 	if (!(flags & _SOBIND_LOCK_HELD)) {
2890f1702c5SYu Xiangning 		so_unlock_single(so, SOLOCKED);
2900f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2910f1702c5SYu Xiangning 	} else {
2920f1702c5SYu Xiangning 		/* If the caller held the lock don't release it here */
2930f1702c5SYu Xiangning 		ASSERT(MUTEX_HELD(&so->so_lock));
2940f1702c5SYu Xiangning 		ASSERT(so->so_flag & SOLOCKED);
2950f1702c5SYu Xiangning 	}
2960f1702c5SYu Xiangning 
2970f1702c5SYu Xiangning 	return (error);
2980f1702c5SYu Xiangning }
2990f1702c5SYu Xiangning 
3000f1702c5SYu Xiangning /*
3010f1702c5SYu Xiangning  * Turn socket into a listen socket.
3020f1702c5SYu Xiangning  */
3030f1702c5SYu Xiangning /* ARGSUSED */
3040f1702c5SYu Xiangning static int
3050f1702c5SYu Xiangning sosctp_listen(struct sonode *so, int backlog, struct cred *cr)
3060f1702c5SYu Xiangning {
3070f1702c5SYu Xiangning 	int error = 0;
3080f1702c5SYu Xiangning 
3090f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3100f1702c5SYu Xiangning 	so_lock_single(so);
3110f1702c5SYu Xiangning 
3120f1702c5SYu Xiangning 	/*
3130f1702c5SYu Xiangning 	 * If this socket is trying to do connect, or if it has
3140f1702c5SYu Xiangning 	 * been connected, disallow.
3150f1702c5SYu Xiangning 	 */
3160f1702c5SYu Xiangning 	if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED |
3170f1702c5SYu Xiangning 	    SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) {
3180f1702c5SYu Xiangning 		error = EINVAL;
3190f1702c5SYu Xiangning 		eprintsoline(so, error);
3200f1702c5SYu Xiangning 		goto done;
3210f1702c5SYu Xiangning 	}
3220f1702c5SYu Xiangning 
3230f1702c5SYu Xiangning 	if (backlog < 0) {
3240f1702c5SYu Xiangning 		backlog = 0;
3250f1702c5SYu Xiangning 	}
3260f1702c5SYu Xiangning 
3270f1702c5SYu Xiangning 	/*
3280f1702c5SYu Xiangning 	 * If listen() is only called to change backlog, we don't
3290f1702c5SYu Xiangning 	 * need to notify protocol module.
3300f1702c5SYu Xiangning 	 */
3310f1702c5SYu Xiangning 	if (so->so_state & SS_ACCEPTCONN) {
3320f1702c5SYu Xiangning 		so->so_backlog = backlog;
3330f1702c5SYu Xiangning 		goto done;
3340f1702c5SYu Xiangning 	}
3350f1702c5SYu Xiangning 
3360f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3370f1702c5SYu Xiangning 	error = sctp_listen((struct sctp_s *)so->so_proto_handle);
3380f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3390f1702c5SYu Xiangning 	if (error == 0) {
3400f1702c5SYu Xiangning 		so->so_state |= (SS_ACCEPTCONN|SS_ISBOUND);
3410f1702c5SYu Xiangning 		so->so_backlog = backlog;
3420f1702c5SYu Xiangning 	} else {
3430f1702c5SYu Xiangning 		eprintsoline(so, error);
3440f1702c5SYu Xiangning 	}
3450f1702c5SYu Xiangning done:
3460f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
3470f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3480f1702c5SYu Xiangning 
3490f1702c5SYu Xiangning 	return (error);
3500f1702c5SYu Xiangning }
3510f1702c5SYu Xiangning 
3520f1702c5SYu Xiangning /*
3530f1702c5SYu Xiangning  * Active open.
3540f1702c5SYu Xiangning  */
3550f1702c5SYu Xiangning /*ARGSUSED*/
3560f1702c5SYu Xiangning static int
3573e95bd4aSAnders Persson sosctp_connect(struct sonode *so, struct sockaddr *name,
3580f1702c5SYu Xiangning     socklen_t namelen, int fflag, int flags, struct cred *cr)
3590f1702c5SYu Xiangning {
3600f1702c5SYu Xiangning 	int error = 0;
361bd670b35SErik Nordmark 	pid_t pid = curproc->p_pid;
3620f1702c5SYu Xiangning 
3630f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
3640f1702c5SYu Xiangning 
3650f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
3660f1702c5SYu Xiangning 	so_lock_single(so);
3670f1702c5SYu Xiangning 
3680f1702c5SYu Xiangning 	/*
3690f1702c5SYu Xiangning 	 * Can't connect() after listen(), or if the socket is already
3700f1702c5SYu Xiangning 	 * connected.
3710f1702c5SYu Xiangning 	 */
3720f1702c5SYu Xiangning 	if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) {
3730f1702c5SYu Xiangning 		if (so->so_state & SS_ISCONNECTED) {
3740f1702c5SYu Xiangning 			error = EISCONN;
3750f1702c5SYu Xiangning 		} else if (so->so_state & SS_ISCONNECTING) {
3760f1702c5SYu Xiangning 			error = EALREADY;
3770f1702c5SYu Xiangning 		} else {
3780f1702c5SYu Xiangning 			error = EOPNOTSUPP;
3790f1702c5SYu Xiangning 		}
3800f1702c5SYu Xiangning 		eprintsoline(so, error);
3810f1702c5SYu Xiangning 		goto done;
3820f1702c5SYu Xiangning 	}
3830f1702c5SYu Xiangning 
3840f1702c5SYu Xiangning 	/*
3850f1702c5SYu Xiangning 	 * Check for failure of an earlier call
3860f1702c5SYu Xiangning 	 */
3870f1702c5SYu Xiangning 	if (so->so_error != 0) {
3880f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
3890f1702c5SYu Xiangning 		eprintsoline(so, error);
3900f1702c5SYu Xiangning 		goto done;
3910f1702c5SYu Xiangning 	}
3920f1702c5SYu Xiangning 
3930f1702c5SYu Xiangning 	/*
3940f1702c5SYu Xiangning 	 * Connection is closing, or closed, don't allow reconnect.
3950f1702c5SYu Xiangning 	 * TCP allows this to proceed, but the socket remains unwriteable.
3960f1702c5SYu Xiangning 	 * BSD returns EINVAL.
3970f1702c5SYu Xiangning 	 */
3980f1702c5SYu Xiangning 	if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE|
3990f1702c5SYu Xiangning 	    SS_CANTSENDMORE)) {
4000f1702c5SYu Xiangning 		error = EINVAL;
4010f1702c5SYu Xiangning 		eprintsoline(so, error);
4020f1702c5SYu Xiangning 		goto done;
4030f1702c5SYu Xiangning 	}
4040f1702c5SYu Xiangning 
4050f1702c5SYu Xiangning 	if (name == NULL || namelen == 0) {
4060f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
4070f1702c5SYu Xiangning 		error = EINVAL;
4080f1702c5SYu Xiangning 		eprintsoline(so, error);
4090f1702c5SYu Xiangning 		goto done;
4100f1702c5SYu Xiangning 	}
4110f1702c5SYu Xiangning 
4120f1702c5SYu Xiangning 	soisconnecting(so);
4130f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4140f1702c5SYu Xiangning 
4150f1702c5SYu Xiangning 	error = sctp_connect((struct sctp_s *)so->so_proto_handle,
416bd670b35SErik Nordmark 	    name, namelen, cr, pid);
4170f1702c5SYu Xiangning 
4180f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4190f1702c5SYu Xiangning 	if (error == 0) {
4200f1702c5SYu Xiangning 		/*
4210f1702c5SYu Xiangning 		 * Allow other threads to access the socket
4220f1702c5SYu Xiangning 		 */
4230f1702c5SYu Xiangning 		error = sowaitconnected(so, fflag, 0);
4240f1702c5SYu Xiangning 	}
4250f1702c5SYu Xiangning done:
4260f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
4270f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4280f1702c5SYu Xiangning 	return (error);
4290f1702c5SYu Xiangning }
4300f1702c5SYu Xiangning 
4310f1702c5SYu Xiangning /*
4320f1702c5SYu Xiangning  * Active open for 1-N sockets, create a new association and
4330f1702c5SYu Xiangning  * call connect on that.
4340f1702c5SYu Xiangning  * If there parent hasn't been bound yet (this is the first association),
4350f1702c5SYu Xiangning  * make it so.
4360f1702c5SYu Xiangning  */
4370f1702c5SYu Xiangning static int
4383e95bd4aSAnders Persson sosctp_seq_connect(struct sonode *so, struct sockaddr *name,
4390f1702c5SYu Xiangning     socklen_t namelen, int fflag, int flags, struct cred *cr)
4400f1702c5SYu Xiangning {
4410f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
4420f1702c5SYu Xiangning 	struct sctp_sonode *ss;
4430f1702c5SYu Xiangning 	int error;
4440f1702c5SYu Xiangning 
4450f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
4460f1702c5SYu Xiangning 
4470f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4480f1702c5SYu Xiangning 	so_lock_single(so);
4490f1702c5SYu Xiangning 
4500f1702c5SYu Xiangning 	if (name == NULL || namelen == 0) {
4510f1702c5SYu Xiangning 		error = EINVAL;
4520f1702c5SYu Xiangning 		eprintsoline(so, error);
4530f1702c5SYu Xiangning 		goto done;
4540f1702c5SYu Xiangning 	}
4550f1702c5SYu Xiangning 
4560f1702c5SYu Xiangning 	ss = SOTOSSO(so);
4570f1702c5SYu Xiangning 
4580f1702c5SYu Xiangning 	error = sosctp_assoc_createconn(ss, name, namelen, NULL, 0, fflag,
4590f1702c5SYu Xiangning 	    cr, &ssa);
4600f1702c5SYu Xiangning 	if (error != 0) {
4610f1702c5SYu Xiangning 		if ((error == EHOSTUNREACH) && (flags & _SOCONNECT_XPG4_2)) {
4620f1702c5SYu Xiangning 			error = ENETUNREACH;
4630f1702c5SYu Xiangning 		}
4640f1702c5SYu Xiangning 	}
4650f1702c5SYu Xiangning 	if (ssa != NULL) {
4660f1702c5SYu Xiangning 		SSA_REFRELE(ss, ssa);
4670f1702c5SYu Xiangning 	}
4680f1702c5SYu Xiangning 
4690f1702c5SYu Xiangning done:
4700f1702c5SYu Xiangning 	so_unlock_single(so, SOLOCKED);
4710f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4720f1702c5SYu Xiangning 	return (error);
4730f1702c5SYu Xiangning }
4740f1702c5SYu Xiangning 
4750f1702c5SYu Xiangning /*
4760f1702c5SYu Xiangning  * Receive data.
4770f1702c5SYu Xiangning  */
4780f1702c5SYu Xiangning /* ARGSUSED */
4790f1702c5SYu Xiangning static int
4800f1702c5SYu Xiangning sosctp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4810f1702c5SYu Xiangning     struct cred *cr)
4820f1702c5SYu Xiangning {
4830f1702c5SYu Xiangning 	struct sctp_sonode *ss = SOTOSSO(so);
4840f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = NULL;
4850f1702c5SYu Xiangning 	int flags, error = 0;
4860f1702c5SYu Xiangning 	struct T_unitdata_ind *tind;
487419dcee7SAnders Persson 	ssize_t orig_resid = uiop->uio_resid;
488*a215d4ebSKacheong Poon 	int len, count, readcnt = 0;
4890f1702c5SYu Xiangning 	socklen_t controllen, namelen;
4900f1702c5SYu Xiangning 	void *opt;
4910f1702c5SYu Xiangning 	mblk_t *mp;
4920f1702c5SYu Xiangning 	rval_t	rval;
4930f1702c5SYu Xiangning 
4940f1702c5SYu Xiangning 	controllen = msg->msg_controllen;
4950f1702c5SYu Xiangning 	namelen = msg->msg_namelen;
4960f1702c5SYu Xiangning 	flags = msg->msg_flags;
4970f1702c5SYu Xiangning 	msg->msg_flags = 0;
4980f1702c5SYu Xiangning 	msg->msg_controllen = 0;
4990f1702c5SYu Xiangning 	msg->msg_namelen = 0;
5000f1702c5SYu Xiangning 
5010f1702c5SYu Xiangning 	if (so->so_type == SOCK_STREAM) {
5020f1702c5SYu Xiangning 		if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING|
5030f1702c5SYu Xiangning 		    SS_CANTRCVMORE))) {
5040f1702c5SYu Xiangning 			return (ENOTCONN);
5050f1702c5SYu Xiangning 		}
5060f1702c5SYu Xiangning 	} else {
5070f1702c5SYu Xiangning 		/* NOTE: Will come here from vop_read() as well */
5080f1702c5SYu Xiangning 		/* For 1-N socket, recv() cannot be used. */
5090f1702c5SYu Xiangning 		if (namelen == 0)
5100f1702c5SYu Xiangning 			return (EOPNOTSUPP);
5110f1702c5SYu Xiangning 		/*
5120f1702c5SYu Xiangning 		 * If there are no associations, and no new connections are
5130f1702c5SYu Xiangning 		 * coming in, there's not going to be new messages coming
5140f1702c5SYu Xiangning 		 * in either.
5150f1702c5SYu Xiangning 		 */
516419dcee7SAnders Persson 		if (so->so_rcv_q_head == NULL && so->so_rcv_head == NULL &&
517419dcee7SAnders Persson 		    ss->ss_assoccnt == 0 && !(so->so_state & SS_ACCEPTCONN)) {
5180f1702c5SYu Xiangning 			return (ENOTCONN);
5190f1702c5SYu Xiangning 		}
5200f1702c5SYu Xiangning 	}
5210f1702c5SYu Xiangning 
5220f1702c5SYu Xiangning 	/*
5230f1702c5SYu Xiangning 	 * out-of-band data not supported.
5240f1702c5SYu Xiangning 	 */
5250f1702c5SYu Xiangning 	if (flags & MSG_OOB) {
5260f1702c5SYu Xiangning 		return (EOPNOTSUPP);
5270f1702c5SYu Xiangning 	}
5280f1702c5SYu Xiangning 
5290f1702c5SYu Xiangning 	/*
5300f1702c5SYu Xiangning 	 * flag possibilities:
5310f1702c5SYu Xiangning 	 *
5320f1702c5SYu Xiangning 	 * MSG_PEEK	Don't consume data
5330f1702c5SYu Xiangning 	 * MSG_WAITALL	Wait for full quantity of data (ignored if MSG_PEEK)
5340f1702c5SYu Xiangning 	 * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
5350f1702c5SYu Xiangning 	 *
5360f1702c5SYu Xiangning 	 * MSG_WAITALL can return less than the full buffer if either
5370f1702c5SYu Xiangning 	 *
5380f1702c5SYu Xiangning 	 * 1. we would block and we are non-blocking
5390f1702c5SYu Xiangning 	 * 2. a full message cannot be delivered
5400f1702c5SYu Xiangning 	 *
5410f1702c5SYu Xiangning 	 * Given that we always get a full message from proto below,
5420f1702c5SYu Xiangning 	 * MSG_WAITALL is not meaningful.
5430f1702c5SYu Xiangning 	 */
5440f1702c5SYu Xiangning 
5450f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
5460f1702c5SYu Xiangning 
5470f1702c5SYu Xiangning 	/*
5480f1702c5SYu Xiangning 	 * Allow just one reader at a time.
5490f1702c5SYu Xiangning 	 */
5500f1702c5SYu Xiangning 	error = so_lock_read_intr(so,
5510f1702c5SYu Xiangning 	    uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
5520f1702c5SYu Xiangning 	if (error) {
5530f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5540f1702c5SYu Xiangning 		return (error);
5550f1702c5SYu Xiangning 	}
5560f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
5570f1702c5SYu Xiangning again:
5580f1702c5SYu Xiangning 	error = so_dequeue_msg(so, &mp, uiop, &rval, flags | MSG_DUPCTRL);
5590f1702c5SYu Xiangning 	if (mp != NULL) {
5600f1702c5SYu Xiangning 		if (so->so_type == SOCK_SEQPACKET) {
5610f1702c5SYu Xiangning 			ssa = *(struct sctp_soassoc **)DB_BASE(mp);
5620f1702c5SYu Xiangning 		}
5630f1702c5SYu Xiangning 
5640f1702c5SYu Xiangning 		tind = (struct T_unitdata_ind *)mp->b_rptr;
5650f1702c5SYu Xiangning 
5660f1702c5SYu Xiangning 		len = tind->SRC_length;
5670f1702c5SYu Xiangning 
5680f1702c5SYu Xiangning 		if (namelen > 0 && len > 0) {
5690f1702c5SYu Xiangning 
5700f1702c5SYu Xiangning 			opt = sogetoff(mp, tind->SRC_offset, len, 1);
5710f1702c5SYu Xiangning 
5720f1702c5SYu Xiangning 			ASSERT(opt != NULL);
5730f1702c5SYu Xiangning 
5740f1702c5SYu Xiangning 			msg->msg_name = kmem_alloc(len, KM_SLEEP);
5750f1702c5SYu Xiangning 			msg->msg_namelen = len;
5760f1702c5SYu Xiangning 
5770f1702c5SYu Xiangning 			bcopy(opt, msg->msg_name, len);
5780f1702c5SYu Xiangning 		}
5790f1702c5SYu Xiangning 
5800f1702c5SYu Xiangning 		len = tind->OPT_length;
5810f1702c5SYu Xiangning 		if (controllen == 0) {
5820f1702c5SYu Xiangning 			if (len > 0) {
5830f1702c5SYu Xiangning 				msg->msg_flags |= MSG_CTRUNC;
5840f1702c5SYu Xiangning 			}
5850f1702c5SYu Xiangning 		} else if (len > 0) {
5860f1702c5SYu Xiangning 			opt = sogetoff(mp, tind->OPT_offset, len,
5870f1702c5SYu Xiangning 			    __TPI_ALIGN_SIZE);
5880f1702c5SYu Xiangning 
5890f1702c5SYu Xiangning 			ASSERT(opt != NULL);
5900f1702c5SYu Xiangning 			sosctp_pack_cmsg(opt, msg, len);
5910f1702c5SYu Xiangning 		}
5920f1702c5SYu Xiangning 
5930f1702c5SYu Xiangning 		if (mp->b_flag & SCTP_NOTIFICATION) {
5940f1702c5SYu Xiangning 			msg->msg_flags |= MSG_NOTIFICATION;
5950f1702c5SYu Xiangning 		}
5960f1702c5SYu Xiangning 
597*a215d4ebSKacheong Poon 		if (!(mp->b_flag & SCTP_PARTIAL_DATA) &&
598*a215d4ebSKacheong Poon 		    !(rval.r_val1 & MOREDATA)) {
5990f1702c5SYu Xiangning 			msg->msg_flags |= MSG_EOR;
600*a215d4ebSKacheong Poon 		}
6010f1702c5SYu Xiangning 		freemsg(mp);
6020f1702c5SYu Xiangning 	}
6030f1702c5SYu Xiangning done:
604419dcee7SAnders Persson 	if (!(flags & MSG_PEEK))
605419dcee7SAnders Persson 		readcnt = orig_resid - uiop->uio_resid;
6060f1702c5SYu Xiangning 	/*
6070f1702c5SYu Xiangning 	 * Determine if we need to update SCTP about the buffer
6080f1702c5SYu Xiangning 	 * space.  For performance reason, we cannot update SCTP
6090f1702c5SYu Xiangning 	 * every time a message is read.  The socket buffer low
6100f1702c5SYu Xiangning 	 * watermark is used as the threshold.
6110f1702c5SYu Xiangning 	 */
6120f1702c5SYu Xiangning 	if (ssa == NULL) {
6130f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
6140f1702c5SYu Xiangning 		count = so->so_rcvbuf - so->so_rcv_queued;
6150f1702c5SYu Xiangning 
6160f1702c5SYu Xiangning 		ASSERT(so->so_rcv_q_head != NULL ||
6170f1702c5SYu Xiangning 		    so->so_rcv_head != NULL ||
6180f1702c5SYu Xiangning 		    so->so_rcv_queued == 0);
6190f1702c5SYu Xiangning 
6200f1702c5SYu Xiangning 		so_unlock_read(so);
6210f1702c5SYu Xiangning 
6220f1702c5SYu Xiangning 		/*
623*a215d4ebSKacheong Poon 		 * so_dequeue_msg() sets r_val2 to true if flow control was
624*a215d4ebSKacheong Poon 		 * cleared and we need to update SCTP.  so_flowctrld was
625*a215d4ebSKacheong Poon 		 * cleared in so_dequeue_msg() via so_check_flow_control().
6260f1702c5SYu Xiangning 		 */
627*a215d4ebSKacheong Poon 		if (rval.r_val2) {
628*a215d4ebSKacheong Poon 			mutex_exit(&so->so_lock);
6290f1702c5SYu Xiangning 			sctp_recvd((struct sctp_s *)so->so_proto_handle, count);
630*a215d4ebSKacheong Poon 		} else {
631*a215d4ebSKacheong Poon 			mutex_exit(&so->so_lock);
6320f1702c5SYu Xiangning 		}
6330f1702c5SYu Xiangning 	} else {
634419dcee7SAnders Persson 		/*
635419dcee7SAnders Persson 		 * Each association keeps track of how much data it has
636419dcee7SAnders Persson 		 * queued; we need to update the value here. Note that this
637419dcee7SAnders Persson 		 * is slightly different from SOCK_STREAM type sockets, which
638419dcee7SAnders Persson 		 * does not need to update the byte count, as it is already
639419dcee7SAnders Persson 		 * done in so_dequeue_msg().
640419dcee7SAnders Persson 		 */
6410f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
642*a215d4ebSKacheong Poon 		ssa->ssa_rcv_queued -= readcnt;
6430f1702c5SYu Xiangning 		count = so->so_rcvbuf - ssa->ssa_rcv_queued;
6440f1702c5SYu Xiangning 
6450f1702c5SYu Xiangning 		so_unlock_read(so);
6460f1702c5SYu Xiangning 
647*a215d4ebSKacheong Poon 		if (readcnt > 0 && ssa->ssa_flowctrld &&
648*a215d4ebSKacheong Poon 		    ssa->ssa_rcv_queued < so->so_rcvlowat) {
6490f1702c5SYu Xiangning 			/*
650*a215d4ebSKacheong Poon 			 * Need to clear ssa_flowctrld, different from 1-1
651*a215d4ebSKacheong Poon 			 * style.
6520f1702c5SYu Xiangning 			 */
653*a215d4ebSKacheong Poon 			ssa->ssa_flowctrld = B_FALSE;
6540f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
655*a215d4ebSKacheong Poon 			sctp_recvd(ssa->ssa_conn, count);
6560f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
6570f1702c5SYu Xiangning 		}
658*a215d4ebSKacheong Poon 
6590f1702c5SYu Xiangning 		/*
6600f1702c5SYu Xiangning 		 * MOREDATA flag is set if all data could not be copied
6610f1702c5SYu Xiangning 		 */
6620f1702c5SYu Xiangning 		if (!(flags & MSG_PEEK) && !(rval.r_val1 & MOREDATA)) {
6630f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
6640f1702c5SYu Xiangning 		}
6650f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
6660f1702c5SYu Xiangning 	}
6670f1702c5SYu Xiangning 
6680f1702c5SYu Xiangning 	return (error);
6690f1702c5SYu Xiangning }
6700f1702c5SYu Xiangning 
6710f1702c5SYu Xiangning int
6720f1702c5SYu Xiangning sosctp_uiomove(mblk_t *hdr_mp, ssize_t count, ssize_t blk_size, int wroff,
673bd670b35SErik Nordmark     struct uio *uiop, int flags)
6740f1702c5SYu Xiangning {
6750f1702c5SYu Xiangning 	ssize_t size;
6760f1702c5SYu Xiangning 	int error;
6770f1702c5SYu Xiangning 	mblk_t *mp;
6780f1702c5SYu Xiangning 	dblk_t *dp;
6790f1702c5SYu Xiangning 
680d496d3f8SErik Nordmark 	if (blk_size == INFPSZ)
681d496d3f8SErik Nordmark 		blk_size = count;
682d496d3f8SErik Nordmark 
6830f1702c5SYu Xiangning 	/*
6840f1702c5SYu Xiangning 	 * Loop until we have all data copied into mblk's.
6850f1702c5SYu Xiangning 	 */
6860f1702c5SYu Xiangning 	while (count > 0) {
6870f1702c5SYu Xiangning 		size = MIN(count, blk_size);
6880f1702c5SYu Xiangning 
6890f1702c5SYu Xiangning 		/*
6900f1702c5SYu Xiangning 		 * As a message can be splitted up and sent in different
6910f1702c5SYu Xiangning 		 * packets, each mblk will have the extra space before
6920f1702c5SYu Xiangning 		 * data to accommodate what SCTP wants to put in there.
6930f1702c5SYu Xiangning 		 */
694bd670b35SErik Nordmark 		while ((mp = allocb(size + wroff, BPRI_MED)) == NULL) {
6950f1702c5SYu Xiangning 			if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
6960f1702c5SYu Xiangning 			    (flags & MSG_DONTWAIT)) {
6970f1702c5SYu Xiangning 				return (EAGAIN);
6980f1702c5SYu Xiangning 			}
6990f1702c5SYu Xiangning 			if ((error = strwaitbuf(size + wroff, BPRI_MED))) {
7000f1702c5SYu Xiangning 				return (error);
7010f1702c5SYu Xiangning 			}
7020f1702c5SYu Xiangning 		}
7030f1702c5SYu Xiangning 
7040f1702c5SYu Xiangning 		dp = mp->b_datap;
7050f1702c5SYu Xiangning 		dp->db_cpid = curproc->p_pid;
7060f1702c5SYu Xiangning 		ASSERT(wroff <= dp->db_lim - mp->b_wptr);
7070f1702c5SYu Xiangning 		mp->b_rptr += wroff;
7080f1702c5SYu Xiangning 		error = uiomove(mp->b_rptr, size, UIO_WRITE, uiop);
7090f1702c5SYu Xiangning 		if (error != 0) {
7100f1702c5SYu Xiangning 			freeb(mp);
7110f1702c5SYu Xiangning 			return (error);
7120f1702c5SYu Xiangning 		}
7130f1702c5SYu Xiangning 		mp->b_wptr = mp->b_rptr + size;
7140f1702c5SYu Xiangning 		count -= size;
7150f1702c5SYu Xiangning 		hdr_mp->b_cont = mp;
7160f1702c5SYu Xiangning 		hdr_mp = mp;
7170f1702c5SYu Xiangning 	}
7180f1702c5SYu Xiangning 	return (0);
7190f1702c5SYu Xiangning }
7200f1702c5SYu Xiangning 
7210f1702c5SYu Xiangning /*
7220f1702c5SYu Xiangning  * Send message.
7230f1702c5SYu Xiangning  */
7240f1702c5SYu Xiangning static int
7250f1702c5SYu Xiangning sosctp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
7260f1702c5SYu Xiangning     struct cred *cr)
7270f1702c5SYu Xiangning {
7280f1702c5SYu Xiangning 	mblk_t *mctl;
7290f1702c5SYu Xiangning 	struct cmsghdr *cmsg;
7300f1702c5SYu Xiangning 	struct sctp_sndrcvinfo *sinfo;
7310f1702c5SYu Xiangning 	int optlen, flags, fflag;
7320f1702c5SYu Xiangning 	ssize_t count, msglen;
7330f1702c5SYu Xiangning 	int error;
7340f1702c5SYu Xiangning 
7350f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_STREAM);
7360f1702c5SYu Xiangning 
7370f1702c5SYu Xiangning 	flags = msg->msg_flags;
7380f1702c5SYu Xiangning 	if (flags & MSG_OOB) {
7390f1702c5SYu Xiangning 		/*
7400f1702c5SYu Xiangning 		 * No out-of-band data support.
7410f1702c5SYu Xiangning 		 */
7420f1702c5SYu Xiangning 		return (EOPNOTSUPP);
7430f1702c5SYu Xiangning 	}
7440f1702c5SYu Xiangning 
7450f1702c5SYu Xiangning 	if (msg->msg_controllen != 0) {
7460f1702c5SYu Xiangning 		optlen = msg->msg_controllen;
7470f1702c5SYu Xiangning 		cmsg = sosctp_find_cmsg(msg->msg_control, optlen, SCTP_SNDRCV);
7480f1702c5SYu Xiangning 		if (cmsg != NULL) {
7490f1702c5SYu Xiangning 			if (cmsg->cmsg_len <
7500f1702c5SYu Xiangning 			    (sizeof (*sinfo) + sizeof (*cmsg))) {
7510f1702c5SYu Xiangning 				eprintsoline(so, EINVAL);
7520f1702c5SYu Xiangning 				return (EINVAL);
7530f1702c5SYu Xiangning 			}
7540f1702c5SYu Xiangning 			sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);
7550f1702c5SYu Xiangning 
7560f1702c5SYu Xiangning 			/* Both flags should not be set together. */
7570f1702c5SYu Xiangning 			if ((sinfo->sinfo_flags & MSG_EOF) &&
7580f1702c5SYu Xiangning 			    (sinfo->sinfo_flags & MSG_ABORT)) {
7590f1702c5SYu Xiangning 				eprintsoline(so, EINVAL);
7600f1702c5SYu Xiangning 				return (EINVAL);
7610f1702c5SYu Xiangning 			}
7620f1702c5SYu Xiangning 
7630f1702c5SYu Xiangning 			/* Initiate a graceful shutdown. */
7640f1702c5SYu Xiangning 			if (sinfo->sinfo_flags & MSG_EOF) {
7650f1702c5SYu Xiangning 				/* Can't include data in MSG_EOF message. */
7660f1702c5SYu Xiangning 				if (uiop->uio_resid != 0) {
7670f1702c5SYu Xiangning 					eprintsoline(so, EINVAL);
7680f1702c5SYu Xiangning 					return (EINVAL);
7690f1702c5SYu Xiangning 				}
7700f1702c5SYu Xiangning 
7710f1702c5SYu Xiangning 				/*
7720f1702c5SYu Xiangning 				 * This is the same sequence as done in
7730f1702c5SYu Xiangning 				 * shutdown(SHUT_WR).
7740f1702c5SYu Xiangning 				 */
7750f1702c5SYu Xiangning 				mutex_enter(&so->so_lock);
7760f1702c5SYu Xiangning 				so_lock_single(so);
7770f1702c5SYu Xiangning 				socantsendmore(so);
7780f1702c5SYu Xiangning 				cv_broadcast(&so->so_snd_cv);
7790f1702c5SYu Xiangning 				so->so_state |= SS_ISDISCONNECTING;
7800f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
7810f1702c5SYu Xiangning 
7820f1702c5SYu Xiangning 				pollwakeup(&so->so_poll_list, POLLOUT);
7830f1702c5SYu Xiangning 				sctp_recvd((struct sctp_s *)so->so_proto_handle,
7840f1702c5SYu Xiangning 				    so->so_rcvbuf);
7850f1702c5SYu Xiangning 				error = sctp_disconnect(
7860f1702c5SYu Xiangning 				    (struct sctp_s *)so->so_proto_handle);
7870f1702c5SYu Xiangning 
7880f1702c5SYu Xiangning 				mutex_enter(&so->so_lock);
7890f1702c5SYu Xiangning 				so_unlock_single(so, SOLOCKED);
7900f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
7910f1702c5SYu Xiangning 				return (error);
7920f1702c5SYu Xiangning 			}
7930f1702c5SYu Xiangning 		}
7940f1702c5SYu Xiangning 	} else {
7950f1702c5SYu Xiangning 		optlen = 0;
7960f1702c5SYu Xiangning 	}
7970f1702c5SYu Xiangning 
7980f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
7990f1702c5SYu Xiangning 	for (;;) {
8000f1702c5SYu Xiangning 		if (so->so_state & SS_CANTSENDMORE) {
8010f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
8020f1702c5SYu Xiangning 			return (EPIPE);
8030f1702c5SYu Xiangning 		}
8040f1702c5SYu Xiangning 
8050f1702c5SYu Xiangning 		if (so->so_error != 0) {
8060f1702c5SYu Xiangning 			error = sogeterr(so, B_TRUE);
8070f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
8080f1702c5SYu Xiangning 			return (error);
8090f1702c5SYu Xiangning 		}
8100f1702c5SYu Xiangning 
8110f1702c5SYu Xiangning 		if (!so->so_snd_qfull)
8120f1702c5SYu Xiangning 			break;
8130f1702c5SYu Xiangning 
8140f1702c5SYu Xiangning 		if (so->so_state & SS_CLOSING) {
8150f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
8160f1702c5SYu Xiangning 			return (EINTR);
8170f1702c5SYu Xiangning 		}
8180f1702c5SYu Xiangning 		/*
8190f1702c5SYu Xiangning 		 * Xmit window full in a blocking socket.
8200f1702c5SYu Xiangning 		 */
8210f1702c5SYu Xiangning 		if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
8220f1702c5SYu Xiangning 		    (flags & MSG_DONTWAIT)) {
8230f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
8240f1702c5SYu Xiangning 			return (EAGAIN);
8250f1702c5SYu Xiangning 		} else {
8260f1702c5SYu Xiangning 			/*
8270f1702c5SYu Xiangning 			 * Wait for space to become available and try again.
8280f1702c5SYu Xiangning 			 */
8290f1702c5SYu Xiangning 			error = cv_wait_sig(&so->so_snd_cv, &so->so_lock);
8300f1702c5SYu Xiangning 			if (!error) { /* signal */
8310f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
8320f1702c5SYu Xiangning 				return (EINTR);
8330f1702c5SYu Xiangning 			}
8340f1702c5SYu Xiangning 		}
8350f1702c5SYu Xiangning 	}
8360f1702c5SYu Xiangning 	msglen = count = uiop->uio_resid;
8370f1702c5SYu Xiangning 
8380f1702c5SYu Xiangning 	/* Don't allow sending a message larger than the send buffer size. */
8390f1702c5SYu Xiangning 	/* XXX Transport module need to enforce this */
8400f1702c5SYu Xiangning 	if (msglen > so->so_sndbuf) {
8410f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
8420f1702c5SYu Xiangning 		return (EMSGSIZE);
8430f1702c5SYu Xiangning 	}
8440f1702c5SYu Xiangning 
8450f1702c5SYu Xiangning 	/*
8460f1702c5SYu Xiangning 	 * Allow piggybacking data on handshake messages (SS_ISCONNECTING).
8470f1702c5SYu Xiangning 	 */
8480f1702c5SYu Xiangning 	if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) {
8490f1702c5SYu Xiangning 		/*
8500f1702c5SYu Xiangning 		 * We need to check here for listener so that the
8510f1702c5SYu Xiangning 		 * same error will be returned as with a TCP socket.
8520f1702c5SYu Xiangning 		 * In this case, sosctp_connect() returns EOPNOTSUPP
8530f1702c5SYu Xiangning 		 * while a TCP socket returns ENOTCONN instead.  Catch it
8540f1702c5SYu Xiangning 		 * here to have the same behavior as a TCP socket.
8550f1702c5SYu Xiangning 		 *
8560f1702c5SYu Xiangning 		 * We also need to make sure that the peer address is
8570f1702c5SYu Xiangning 		 * provided before we attempt to do the connect.
8580f1702c5SYu Xiangning 		 */
8590f1702c5SYu Xiangning 		if ((so->so_state & SS_ACCEPTCONN) ||
8600f1702c5SYu Xiangning 		    msg->msg_name == NULL) {
8610f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
8620f1702c5SYu Xiangning 			error = ENOTCONN;
8630f1702c5SYu Xiangning 			goto error_nofree;
8640f1702c5SYu Xiangning 		}
8650f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
8660f1702c5SYu Xiangning 		fflag = uiop->uio_fmode;
8670f1702c5SYu Xiangning 		if (flags & MSG_DONTWAIT) {
8680f1702c5SYu Xiangning 			fflag |= FNDELAY;
8690f1702c5SYu Xiangning 		}
8700f1702c5SYu Xiangning 		error = sosctp_connect(so, msg->msg_name, msg->msg_namelen,
8710f1702c5SYu Xiangning 		    fflag, (so->so_version == SOV_XPG4_2) * _SOCONNECT_XPG4_2,
8720f1702c5SYu Xiangning 		    cr);
8730f1702c5SYu Xiangning 		if (error) {
8740f1702c5SYu Xiangning 			/*
8750f1702c5SYu Xiangning 			 * Check for non-fatal errors, socket connected
8760f1702c5SYu Xiangning 			 * while the lock had been lifted.
8770f1702c5SYu Xiangning 			 */
8780f1702c5SYu Xiangning 			if (error != EISCONN && error != EALREADY) {
8790f1702c5SYu Xiangning 				goto error_nofree;
8800f1702c5SYu Xiangning 			}
8810f1702c5SYu Xiangning 			error = 0;
8820f1702c5SYu Xiangning 		}
8830f1702c5SYu Xiangning 	} else {
8840f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
8850f1702c5SYu Xiangning 	}
8860f1702c5SYu Xiangning 
8870f1702c5SYu Xiangning 	mctl = sctp_alloc_hdr(msg->msg_name, msg->msg_namelen,
8880f1702c5SYu Xiangning 	    msg->msg_control, optlen, SCTP_CAN_BLOCK);
8890f1702c5SYu Xiangning 	if (mctl == NULL) {
8900f1702c5SYu Xiangning 		error = EINTR;
8910f1702c5SYu Xiangning 		goto error_nofree;
8920f1702c5SYu Xiangning 	}
8930f1702c5SYu Xiangning 
8940f1702c5SYu Xiangning 	/* Copy in the message. */
895*a215d4ebSKacheong Poon 	if ((error = sosctp_uiomove(mctl, count, so->so_proto_props.sopp_maxblk,
896*a215d4ebSKacheong Poon 	    so->so_proto_props.sopp_wroff, uiop, flags)) != 0) {
8970f1702c5SYu Xiangning 		goto error_ret;
8980f1702c5SYu Xiangning 	}
8990f1702c5SYu Xiangning 	error = sctp_sendmsg((struct sctp_s *)so->so_proto_handle, mctl, 0);
9000f1702c5SYu Xiangning 	if (error == 0)
9010f1702c5SYu Xiangning 		return (0);
9020f1702c5SYu Xiangning 
9030f1702c5SYu Xiangning error_ret:
9040f1702c5SYu Xiangning 	freemsg(mctl);
9050f1702c5SYu Xiangning error_nofree:
9060f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
9070f1702c5SYu Xiangning 	if ((error == EPIPE) && (so->so_state & SS_CANTSENDMORE)) {
9080f1702c5SYu Xiangning 		/*
9090f1702c5SYu Xiangning 		 * We received shutdown between the time lock was
9100f1702c5SYu Xiangning 		 * lifted and call to sctp_sendmsg().
9110f1702c5SYu Xiangning 		 */
9120f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
9130f1702c5SYu Xiangning 		return (EPIPE);
9140f1702c5SYu Xiangning 	}
9150f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
9160f1702c5SYu Xiangning 	return (error);
9170f1702c5SYu Xiangning }
9180f1702c5SYu Xiangning 
9190f1702c5SYu Xiangning /*
9200f1702c5SYu Xiangning  * Send message on 1-N socket. Connects automatically if there is
9210f1702c5SYu Xiangning  * no association.
9220f1702c5SYu Xiangning  */
9230f1702c5SYu Xiangning static int
9240f1702c5SYu Xiangning sosctp_seq_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
9250f1702c5SYu Xiangning     struct cred *cr)
9260f1702c5SYu Xiangning {
9270f1702c5SYu Xiangning 	struct sctp_sonode *ss;
9280f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
9290f1702c5SYu Xiangning 	struct cmsghdr *cmsg;
9300f1702c5SYu Xiangning 	struct sctp_sndrcvinfo *sinfo;
9310f1702c5SYu Xiangning 	int aid = 0;
9320f1702c5SYu Xiangning 	mblk_t *mctl;
9330f1702c5SYu Xiangning 	int namelen, optlen, flags;
9340f1702c5SYu Xiangning 	ssize_t count, msglen;
9350f1702c5SYu Xiangning 	int error;
9360f1702c5SYu Xiangning 	uint16_t s_flags = 0;
9370f1702c5SYu Xiangning 
9380f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
9390f1702c5SYu Xiangning 
9400f1702c5SYu Xiangning 	/*
9410f1702c5SYu Xiangning 	 * There shouldn't be problems with alignment, as the memory for
9420f1702c5SYu Xiangning 	 * msg_control was alloced with kmem_alloc.
9430f1702c5SYu Xiangning 	 */
9440f1702c5SYu Xiangning 	cmsg = sosctp_find_cmsg(msg->msg_control, msg->msg_controllen,
9450f1702c5SYu Xiangning 	    SCTP_SNDRCV);
9460f1702c5SYu Xiangning 	if (cmsg != NULL) {
9470f1702c5SYu Xiangning 		if (cmsg->cmsg_len < (sizeof (*sinfo) + sizeof (*cmsg))) {
9480f1702c5SYu Xiangning 			eprintsoline(so, EINVAL);
9490f1702c5SYu Xiangning 			return (EINVAL);
9500f1702c5SYu Xiangning 		}
9510f1702c5SYu Xiangning 		sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);
9520f1702c5SYu Xiangning 		s_flags = sinfo->sinfo_flags;
9530f1702c5SYu Xiangning 		aid = sinfo->sinfo_assoc_id;
9540f1702c5SYu Xiangning 	}
9550f1702c5SYu Xiangning 
9560f1702c5SYu Xiangning 	ss = SOTOSSO(so);
9570f1702c5SYu Xiangning 	namelen = msg->msg_namelen;
9580f1702c5SYu Xiangning 
9590f1702c5SYu Xiangning 	if (msg->msg_controllen > 0) {
9600f1702c5SYu Xiangning 		optlen = msg->msg_controllen;
9610f1702c5SYu Xiangning 	} else {
9620f1702c5SYu Xiangning 		optlen = 0;
9630f1702c5SYu Xiangning 	}
9640f1702c5SYu Xiangning 
9650f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
9660f1702c5SYu Xiangning 
9670f1702c5SYu Xiangning 	/*
9680f1702c5SYu Xiangning 	 * If there is no association id, connect to address specified
9690f1702c5SYu Xiangning 	 * in msg_name.  Otherwise look up the association using the id.
9700f1702c5SYu Xiangning 	 */
9710f1702c5SYu Xiangning 	if (aid == 0) {
9720f1702c5SYu Xiangning 		/*
9730f1702c5SYu Xiangning 		 * Connect and shutdown cannot be done together, so check for
9740f1702c5SYu Xiangning 		 * MSG_EOF.
9750f1702c5SYu Xiangning 		 */
9760f1702c5SYu Xiangning 		if (msg->msg_name == NULL || namelen == 0 ||
9770f1702c5SYu Xiangning 		    (s_flags & MSG_EOF)) {
9780f1702c5SYu Xiangning 			error = EINVAL;
9790f1702c5SYu Xiangning 			eprintsoline(so, error);
9800f1702c5SYu Xiangning 			goto done;
9810f1702c5SYu Xiangning 		}
9820f1702c5SYu Xiangning 		flags = uiop->uio_fmode;
9830f1702c5SYu Xiangning 		if (msg->msg_flags & MSG_DONTWAIT) {
9840f1702c5SYu Xiangning 			flags |= FNDELAY;
9850f1702c5SYu Xiangning 		}
9860f1702c5SYu Xiangning 		so_lock_single(so);
9870f1702c5SYu Xiangning 		error = sosctp_assoc_createconn(ss, msg->msg_name, namelen,
9880f1702c5SYu Xiangning 		    msg->msg_control, optlen, flags, cr, &ssa);
9890f1702c5SYu Xiangning 		if (error) {
9900f1702c5SYu Xiangning 			if ((so->so_version == SOV_XPG4_2) &&
9910f1702c5SYu Xiangning 			    (error == EHOSTUNREACH)) {
9920f1702c5SYu Xiangning 				error = ENETUNREACH;
9930f1702c5SYu Xiangning 			}
9940f1702c5SYu Xiangning 			if (ssa == NULL) {
9950f1702c5SYu Xiangning 				/*
9960f1702c5SYu Xiangning 				 * Fatal error during connect(). Bail out.
9970f1702c5SYu Xiangning 				 * If ssa exists, it means that the handshake
9980f1702c5SYu Xiangning 				 * is in progress.
9990f1702c5SYu Xiangning 				 */
10000f1702c5SYu Xiangning 				eprintsoline(so, error);
10010f1702c5SYu Xiangning 				so_unlock_single(so, SOLOCKED);
10020f1702c5SYu Xiangning 				goto done;
10030f1702c5SYu Xiangning 			}
10040f1702c5SYu Xiangning 			/*
10050f1702c5SYu Xiangning 			 * All the errors are non-fatal ones, don't return
10060f1702c5SYu Xiangning 			 * e.g. EINPROGRESS from sendmsg().
10070f1702c5SYu Xiangning 			 */
10080f1702c5SYu Xiangning 			error = 0;
10090f1702c5SYu Xiangning 		}
10100f1702c5SYu Xiangning 		so_unlock_single(so, SOLOCKED);
10110f1702c5SYu Xiangning 	} else {
10120f1702c5SYu Xiangning 		if ((error = sosctp_assoc(ss, aid, &ssa)) != 0) {
10130f1702c5SYu Xiangning 			eprintsoline(so, error);
10140f1702c5SYu Xiangning 			goto done;
10150f1702c5SYu Xiangning 		}
10160f1702c5SYu Xiangning 	}
10170f1702c5SYu Xiangning 
10180f1702c5SYu Xiangning 	/*
10190f1702c5SYu Xiangning 	 * Now we have an association.
10200f1702c5SYu Xiangning 	 */
10210f1702c5SYu Xiangning 	flags = msg->msg_flags;
10220f1702c5SYu Xiangning 
10230f1702c5SYu Xiangning 	/*
10240f1702c5SYu Xiangning 	 * MSG_EOF initiates graceful shutdown.
10250f1702c5SYu Xiangning 	 */
10260f1702c5SYu Xiangning 	if (s_flags & MSG_EOF) {
10270f1702c5SYu Xiangning 		if (uiop->uio_resid) {
10280f1702c5SYu Xiangning 			/*
10290f1702c5SYu Xiangning 			 * Can't include data in MSG_EOF message.
10300f1702c5SYu Xiangning 			 */
10310f1702c5SYu Xiangning 			error = EINVAL;
10320f1702c5SYu Xiangning 		} else {
10330f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
10340f1702c5SYu Xiangning 			ssa->ssa_state |= SS_ISDISCONNECTING;
1035*a215d4ebSKacheong Poon 			sctp_recvd(ssa->ssa_conn, so->so_rcvbuf);
1036*a215d4ebSKacheong Poon 			error = sctp_disconnect(ssa->ssa_conn);
10370f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
10380f1702c5SYu Xiangning 		}
10390f1702c5SYu Xiangning 		goto refrele;
10400f1702c5SYu Xiangning 	}
10410f1702c5SYu Xiangning 
10420f1702c5SYu Xiangning 	for (;;) {
10430f1702c5SYu Xiangning 		if (ssa->ssa_state & SS_CANTSENDMORE) {
10440f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
10450f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
10460f1702c5SYu Xiangning 			return (EPIPE);
10470f1702c5SYu Xiangning 		}
10480f1702c5SYu Xiangning 		if (ssa->ssa_error != 0) {
10490f1702c5SYu Xiangning 			error = ssa->ssa_error;
10500f1702c5SYu Xiangning 			ssa->ssa_error = 0;
10510f1702c5SYu Xiangning 			goto refrele;
10520f1702c5SYu Xiangning 		}
10530f1702c5SYu Xiangning 
10540f1702c5SYu Xiangning 		if (!ssa->ssa_snd_qfull)
10550f1702c5SYu Xiangning 			break;
10560f1702c5SYu Xiangning 
10570f1702c5SYu Xiangning 		if (so->so_state & SS_CLOSING) {
10580f1702c5SYu Xiangning 			error = EINTR;
10590f1702c5SYu Xiangning 			goto refrele;
10600f1702c5SYu Xiangning 		}
10610f1702c5SYu Xiangning 		if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
10620f1702c5SYu Xiangning 		    (flags & MSG_DONTWAIT)) {
10630f1702c5SYu Xiangning 			error = EAGAIN;
10640f1702c5SYu Xiangning 			goto refrele;
10650f1702c5SYu Xiangning 		} else {
10660f1702c5SYu Xiangning 			/*
10670f1702c5SYu Xiangning 			 * Wait for space to become available and try again.
10680f1702c5SYu Xiangning 			 */
10690f1702c5SYu Xiangning 			error = cv_wait_sig(&so->so_snd_cv, &so->so_lock);
10700f1702c5SYu Xiangning 			if (!error) { /* signal */
10710f1702c5SYu Xiangning 				error = EINTR;
10720f1702c5SYu Xiangning 				goto refrele;
10730f1702c5SYu Xiangning 			}
10740f1702c5SYu Xiangning 		}
10750f1702c5SYu Xiangning 	}
10760f1702c5SYu Xiangning 
10770f1702c5SYu Xiangning 	msglen = count = uiop->uio_resid;
10780f1702c5SYu Xiangning 
10790f1702c5SYu Xiangning 	/* Don't allow sending a message larger than the send buffer size. */
10800f1702c5SYu Xiangning 	if (msglen > so->so_sndbuf) {
10810f1702c5SYu Xiangning 		error = EMSGSIZE;
10820f1702c5SYu Xiangning 		goto refrele;
10830f1702c5SYu Xiangning 	}
10840f1702c5SYu Xiangning 
10850f1702c5SYu Xiangning 	/*
10860f1702c5SYu Xiangning 	 * Update TX buffer usage here so that we can lift the socket lock.
10870f1702c5SYu Xiangning 	 */
10880f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
10890f1702c5SYu Xiangning 
10900f1702c5SYu Xiangning 	mctl = sctp_alloc_hdr(msg->msg_name, namelen, msg->msg_control,
10910f1702c5SYu Xiangning 	    optlen, SCTP_CAN_BLOCK);
10920f1702c5SYu Xiangning 	if (mctl == NULL) {
10930f1702c5SYu Xiangning 		error = EINTR;
10940f1702c5SYu Xiangning 		goto lock_rele;
10950f1702c5SYu Xiangning 	}
10960f1702c5SYu Xiangning 
10970f1702c5SYu Xiangning 	/* Copy in the message. */
10980f1702c5SYu Xiangning 	if ((error = sosctp_uiomove(mctl, count, ssa->ssa_wrsize,
1099bd670b35SErik Nordmark 	    ssa->ssa_wroff, uiop, flags)) != 0) {
11000f1702c5SYu Xiangning 		goto lock_rele;
11010f1702c5SYu Xiangning 	}
11020f1702c5SYu Xiangning 	error = sctp_sendmsg((struct sctp_s *)ssa->ssa_conn, mctl, 0);
11030f1702c5SYu Xiangning lock_rele:
11040f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11050f1702c5SYu Xiangning 	if (error != 0) {
11060f1702c5SYu Xiangning 		freemsg(mctl);
11070f1702c5SYu Xiangning 		if ((error == EPIPE) && (ssa->ssa_state & SS_CANTSENDMORE)) {
11080f1702c5SYu Xiangning 			/*
11090f1702c5SYu Xiangning 			 * We received shutdown between the time lock was
11100f1702c5SYu Xiangning 			 * lifted and call to sctp_sendmsg().
11110f1702c5SYu Xiangning 			 */
11120f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
11130f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
11140f1702c5SYu Xiangning 			return (EPIPE);
11150f1702c5SYu Xiangning 		}
11160f1702c5SYu Xiangning 	}
11170f1702c5SYu Xiangning 
11180f1702c5SYu Xiangning refrele:
11190f1702c5SYu Xiangning 	SSA_REFRELE(ss, ssa);
11200f1702c5SYu Xiangning done:
11210f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
11220f1702c5SYu Xiangning 	return (error);
11230f1702c5SYu Xiangning }
11240f1702c5SYu Xiangning 
11250f1702c5SYu Xiangning /*
11260f1702c5SYu Xiangning  * Get address of remote node.
11270f1702c5SYu Xiangning  */
11280f1702c5SYu Xiangning /* ARGSUSED */
11290f1702c5SYu Xiangning static int
11300f1702c5SYu Xiangning sosctp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
11310f1702c5SYu Xiangning     boolean_t accept, struct cred *cr)
11320f1702c5SYu Xiangning {
11330f1702c5SYu Xiangning 	return (sctp_getpeername((struct sctp_s *)so->so_proto_handle, addr,
11340f1702c5SYu Xiangning 	    addrlen));
11350f1702c5SYu Xiangning }
11360f1702c5SYu Xiangning 
11370f1702c5SYu Xiangning /*
11380f1702c5SYu Xiangning  * Get local address.
11390f1702c5SYu Xiangning  */
11400f1702c5SYu Xiangning /* ARGSUSED */
11410f1702c5SYu Xiangning static int
11420f1702c5SYu Xiangning sosctp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
11430f1702c5SYu Xiangning     struct cred *cr)
11440f1702c5SYu Xiangning {
11450f1702c5SYu Xiangning 	return (sctp_getsockname((struct sctp_s *)so->so_proto_handle, addr,
11460f1702c5SYu Xiangning 	    addrlen));
11470f1702c5SYu Xiangning }
11480f1702c5SYu Xiangning 
11490f1702c5SYu Xiangning /*
11500f1702c5SYu Xiangning  * Called from shutdown().
11510f1702c5SYu Xiangning  */
11520f1702c5SYu Xiangning /* ARGSUSED */
11530f1702c5SYu Xiangning static int
11540f1702c5SYu Xiangning sosctp_shutdown(struct sonode *so, int how, struct cred *cr)
11550f1702c5SYu Xiangning {
11560f1702c5SYu Xiangning 	uint_t state_change;
11570f1702c5SYu Xiangning 	int wakesig = 0;
11580f1702c5SYu Xiangning 	int error = 0;
11590f1702c5SYu Xiangning 
11600f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
11610f1702c5SYu Xiangning 	/*
11620f1702c5SYu Xiangning 	 * Record the current state and then perform any state changes.
11630f1702c5SYu Xiangning 	 * Then use the difference between the old and new states to
11640f1702c5SYu Xiangning 	 * determine which needs to be done.
11650f1702c5SYu Xiangning 	 */
11660f1702c5SYu Xiangning 	state_change = so->so_state;
11670f1702c5SYu Xiangning 
11680f1702c5SYu Xiangning 	switch (how) {
11690f1702c5SYu Xiangning 	case SHUT_RD:
11700f1702c5SYu Xiangning 		socantrcvmore(so);
11710f1702c5SYu Xiangning 		break;
11720f1702c5SYu Xiangning 	case SHUT_WR:
11730f1702c5SYu Xiangning 		socantsendmore(so);
11740f1702c5SYu Xiangning 		break;
11750f1702c5SYu Xiangning 	case SHUT_RDWR:
11760f1702c5SYu Xiangning 		socantsendmore(so);
11770f1702c5SYu Xiangning 		socantrcvmore(so);
11780f1702c5SYu Xiangning 		break;
11790f1702c5SYu Xiangning 	default:
11800f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
11810f1702c5SYu Xiangning 		return (EINVAL);
11820f1702c5SYu Xiangning 	}
11830f1702c5SYu Xiangning 
11840f1702c5SYu Xiangning 	state_change = so->so_state & ~state_change;
11850f1702c5SYu Xiangning 
11860f1702c5SYu Xiangning 	if (state_change & SS_CANTRCVMORE) {
11870f1702c5SYu Xiangning 		if (so->so_rcv_q_head == NULL) {
11880f1702c5SYu Xiangning 			cv_signal(&so->so_rcv_cv);
11890f1702c5SYu Xiangning 		}
11900f1702c5SYu Xiangning 		wakesig = POLLIN|POLLRDNORM;
11910f1702c5SYu Xiangning 
11920f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_READ);
11930f1702c5SYu Xiangning 	}
11940f1702c5SYu Xiangning 	if (state_change & SS_CANTSENDMORE) {
11950f1702c5SYu Xiangning 		cv_broadcast(&so->so_snd_cv);
11960f1702c5SYu Xiangning 		wakesig |= POLLOUT;
11970f1702c5SYu Xiangning 
11980f1702c5SYu Xiangning 		so->so_state |= SS_ISDISCONNECTING;
11990f1702c5SYu Xiangning 	}
12000f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
12010f1702c5SYu Xiangning 
12020f1702c5SYu Xiangning 	pollwakeup(&so->so_poll_list, wakesig);
12030f1702c5SYu Xiangning 
12040f1702c5SYu Xiangning 	if (state_change & SS_CANTSENDMORE) {
12050f1702c5SYu Xiangning 		sctp_recvd((struct sctp_s *)so->so_proto_handle, so->so_rcvbuf);
12060f1702c5SYu Xiangning 		error = sctp_disconnect((struct sctp_s *)so->so_proto_handle);
12070f1702c5SYu Xiangning 	}
12080f1702c5SYu Xiangning 
12090f1702c5SYu Xiangning 	/*
12100f1702c5SYu Xiangning 	 * HACK: sctp_disconnect() may return EWOULDBLOCK.  But this error is
12110f1702c5SYu Xiangning 	 * not documented in standard socket API.  Catch it here.
12120f1702c5SYu Xiangning 	 */
12130f1702c5SYu Xiangning 	if (error == EWOULDBLOCK)
12140f1702c5SYu Xiangning 		error = 0;
12150f1702c5SYu Xiangning 	return (error);
12160f1702c5SYu Xiangning }
12170f1702c5SYu Xiangning 
12180f1702c5SYu Xiangning /*
12190f1702c5SYu Xiangning  * Get socket options.
12200f1702c5SYu Xiangning  */
12210f1702c5SYu Xiangning /*ARGSUSED5*/
12220f1702c5SYu Xiangning static int
12230f1702c5SYu Xiangning sosctp_getsockopt(struct sonode *so, int level, int option_name,
12240f1702c5SYu Xiangning     void *optval, socklen_t *optlenp, int flags, struct cred *cr)
12250f1702c5SYu Xiangning {
12262b36adecSRao Shoaib 	socklen_t maxlen = *optlenp;
12272b36adecSRao Shoaib 	socklen_t len;
12282b36adecSRao Shoaib 	socklen_t optlen;
12292b36adecSRao Shoaib 	uint8_t	buffer[4];
12302b36adecSRao Shoaib 	void	*optbuf = &buffer;
12312b36adecSRao Shoaib 	int	error = 0;
12322b36adecSRao Shoaib 
12332b36adecSRao Shoaib 	if (level == SOL_SOCKET) {
12342b36adecSRao Shoaib 		switch (option_name) {
12352b36adecSRao Shoaib 		/* Not supported options */
12362b36adecSRao Shoaib 		case SO_SNDTIMEO:
12372b36adecSRao Shoaib 		case SO_RCVTIMEO:
12382b36adecSRao Shoaib 		case SO_EXCLBIND:
12392c632ad5SAnders Persson 			eprintsoline(so, ENOPROTOOPT);
12402c632ad5SAnders Persson 			return (ENOPROTOOPT);
12412c632ad5SAnders Persson 		default:
12422c632ad5SAnders Persson 			error = socket_getopt_common(so, level, option_name,
12432c632ad5SAnders Persson 			    optval, optlenp, flags);
12442c632ad5SAnders Persson 			if (error >= 0)
12452c632ad5SAnders Persson 				return (error);
12462c632ad5SAnders Persson 			/* Pass the request to the protocol */
12472b36adecSRao Shoaib 			break;
12482b36adecSRao Shoaib 		}
12492b36adecSRao Shoaib 	}
12502b36adecSRao Shoaib 
12510f1702c5SYu Xiangning 	if (level == IPPROTO_SCTP) {
12520f1702c5SYu Xiangning 		/*
12530f1702c5SYu Xiangning 		 * Should go through ioctl().
12540f1702c5SYu Xiangning 		 */
12550f1702c5SYu Xiangning 		return (EINVAL);
12560f1702c5SYu Xiangning 	}
12572b36adecSRao Shoaib 
12582b36adecSRao Shoaib 	if (maxlen > sizeof (buffer)) {
12592b36adecSRao Shoaib 		optbuf = kmem_alloc(maxlen, KM_SLEEP);
12602b36adecSRao Shoaib 	}
12612b36adecSRao Shoaib 	optlen = maxlen;
12622b36adecSRao Shoaib 
12632b36adecSRao Shoaib 	/*
12642b36adecSRao Shoaib 	 * If the resulting optlen is greater than the provided maxlen, then
12652b36adecSRao Shoaib 	 * we sliently trucate.
12662b36adecSRao Shoaib 	 */
12672b36adecSRao Shoaib 	error = sctp_get_opt((struct sctp_s *)so->so_proto_handle, level,
12682b36adecSRao Shoaib 	    option_name, optbuf, &optlen);
12692b36adecSRao Shoaib 
12702b36adecSRao Shoaib 	if (error != 0) {
12712b36adecSRao Shoaib 		eprintsoline(so, error);
12722b36adecSRao Shoaib 		goto free;
12732b36adecSRao Shoaib 	}
12742b36adecSRao Shoaib 	len = optlen;
12752b36adecSRao Shoaib 
12762b36adecSRao Shoaib copyout:
12772b36adecSRao Shoaib 
12782b36adecSRao Shoaib 	len = MIN(len, maxlen);
12792b36adecSRao Shoaib 	bcopy(optbuf, optval, len);
12802b36adecSRao Shoaib 	*optlenp = optlen;
12812b36adecSRao Shoaib free:
12822b36adecSRao Shoaib 	if (optbuf != &buffer) {
12832b36adecSRao Shoaib 		kmem_free(optbuf, maxlen);
12842b36adecSRao Shoaib 	}
12852c632ad5SAnders Persson 
12862b36adecSRao Shoaib 	return (error);
12870f1702c5SYu Xiangning }
12880f1702c5SYu Xiangning 
12890f1702c5SYu Xiangning /*
12900f1702c5SYu Xiangning  * Set socket options
12910f1702c5SYu Xiangning  */
12920f1702c5SYu Xiangning /* ARGSUSED */
12930f1702c5SYu Xiangning static int
12940f1702c5SYu Xiangning sosctp_setsockopt(struct sonode *so, int level, int option_name,
12950f1702c5SYu Xiangning     const void *optval, t_uscalar_t optlen, struct cred *cr)
12960f1702c5SYu Xiangning {
12970f1702c5SYu Xiangning 	struct sctp_sonode *ss = SOTOSSO(so);
12980f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = NULL;
12990f1702c5SYu Xiangning 	sctp_assoc_t id;
13000f1702c5SYu Xiangning 	int error, rc;
13010f1702c5SYu Xiangning 	void *conn = NULL;
13020f1702c5SYu Xiangning 
13030f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
13040f1702c5SYu Xiangning 
13050f1702c5SYu Xiangning 	/*
13060f1702c5SYu Xiangning 	 * For some SCTP level options, one can select the association this
13070f1702c5SYu Xiangning 	 * applies to.
13080f1702c5SYu Xiangning 	 */
13090f1702c5SYu Xiangning 	if (so->so_type == SOCK_STREAM) {
13100f1702c5SYu Xiangning 		conn = so->so_proto_handle;
13110f1702c5SYu Xiangning 	} else {
13120f1702c5SYu Xiangning 		/*
13130f1702c5SYu Xiangning 		 * SOCK_SEQPACKET only
13140f1702c5SYu Xiangning 		 */
13150f1702c5SYu Xiangning 		id = 0;
13160f1702c5SYu Xiangning 		if (level == IPPROTO_SCTP) {
13170f1702c5SYu Xiangning 			switch (option_name) {
13180f1702c5SYu Xiangning 			case SCTP_RTOINFO:
13190f1702c5SYu Xiangning 			case SCTP_ASSOCINFO:
13200f1702c5SYu Xiangning 			case SCTP_SET_PEER_PRIMARY_ADDR:
13210f1702c5SYu Xiangning 			case SCTP_PRIMARY_ADDR:
13220f1702c5SYu Xiangning 			case SCTP_PEER_ADDR_PARAMS:
13230f1702c5SYu Xiangning 				/*
13240f1702c5SYu Xiangning 				 * Association ID is the first element
13250f1702c5SYu Xiangning 				 * params struct
13260f1702c5SYu Xiangning 				 */
13270f1702c5SYu Xiangning 				if (optlen < sizeof (sctp_assoc_t)) {
13280f1702c5SYu Xiangning 					error = EINVAL;
13290f1702c5SYu Xiangning 					eprintsoline(so, error);
13300f1702c5SYu Xiangning 					goto done;
13310f1702c5SYu Xiangning 				}
13320f1702c5SYu Xiangning 				id = *(sctp_assoc_t *)optval;
13330f1702c5SYu Xiangning 				break;
13340f1702c5SYu Xiangning 			case SCTP_DEFAULT_SEND_PARAM:
13350f1702c5SYu Xiangning 				if (optlen != sizeof (struct sctp_sndrcvinfo)) {
13360f1702c5SYu Xiangning 					error = EINVAL;
13370f1702c5SYu Xiangning 					eprintsoline(so, error);
13380f1702c5SYu Xiangning 					goto done;
13390f1702c5SYu Xiangning 				}
13400f1702c5SYu Xiangning 				id = ((struct sctp_sndrcvinfo *)
13410f1702c5SYu Xiangning 				    optval)->sinfo_assoc_id;
13420f1702c5SYu Xiangning 				break;
13430f1702c5SYu Xiangning 			case SCTP_INITMSG:
13440f1702c5SYu Xiangning 				/*
13450f1702c5SYu Xiangning 				 * Only applies to future associations
13460f1702c5SYu Xiangning 				 */
13470f1702c5SYu Xiangning 				conn = so->so_proto_handle;
13480f1702c5SYu Xiangning 				break;
13490f1702c5SYu Xiangning 			default:
13500f1702c5SYu Xiangning 				break;
13510f1702c5SYu Xiangning 			}
13520f1702c5SYu Xiangning 		} else if (level == SOL_SOCKET) {
13530f1702c5SYu Xiangning 			if (option_name == SO_LINGER) {
13540f1702c5SYu Xiangning 				error = EOPNOTSUPP;
13550f1702c5SYu Xiangning 				eprintsoline(so, error);
13560f1702c5SYu Xiangning 				goto done;
13570f1702c5SYu Xiangning 			}
13580f1702c5SYu Xiangning 			/*
13590f1702c5SYu Xiangning 			 * These 2 options are applied to all associations.
13600f1702c5SYu Xiangning 			 * The other socket level options are only applied
13610f1702c5SYu Xiangning 			 * to the socket (not associations).
13620f1702c5SYu Xiangning 			 */
13630f1702c5SYu Xiangning 			if ((option_name != SO_RCVBUF) &&
13640f1702c5SYu Xiangning 			    (option_name != SO_SNDBUF)) {
13650f1702c5SYu Xiangning 				conn = so->so_proto_handle;
13660f1702c5SYu Xiangning 			}
13670f1702c5SYu Xiangning 		} else {
13680f1702c5SYu Xiangning 			conn = NULL;
13690f1702c5SYu Xiangning 		}
13700f1702c5SYu Xiangning 
13710f1702c5SYu Xiangning 		/*
13720f1702c5SYu Xiangning 		 * If association ID was specified, do op on that assoc.
13730f1702c5SYu Xiangning 		 * Otherwise set the default setting of a socket.
13740f1702c5SYu Xiangning 		 */
13750f1702c5SYu Xiangning 		if (id != 0) {
13760f1702c5SYu Xiangning 			if ((error = sosctp_assoc(ss, id, &ssa)) != 0) {
13770f1702c5SYu Xiangning 				eprintsoline(so, error);
13780f1702c5SYu Xiangning 				goto done;
13790f1702c5SYu Xiangning 			}
13800f1702c5SYu Xiangning 			conn = ssa->ssa_conn;
13810f1702c5SYu Xiangning 		}
13820f1702c5SYu Xiangning 	}
13830f1702c5SYu Xiangning 	dprint(2, ("sosctp_setsockopt %p (%d) - conn %p %d %d id:%d\n",
13840f1702c5SYu Xiangning 	    (void *)ss, so->so_type, (void *)conn, level, option_name, id));
13850f1702c5SYu Xiangning 
13860f1702c5SYu Xiangning 	ASSERT(ssa == NULL || (ssa != NULL && conn != NULL));
13870f1702c5SYu Xiangning 	if (conn != NULL) {
13880f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
13890f1702c5SYu Xiangning 		error = sctp_set_opt((struct sctp_s *)conn, level, option_name,
13900f1702c5SYu Xiangning 		    optval, optlen);
13910f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
13920f1702c5SYu Xiangning 		if (ssa != NULL)
13930f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
13940f1702c5SYu Xiangning 	} else {
13950f1702c5SYu Xiangning 		/*
13960f1702c5SYu Xiangning 		 * 1-N socket, and we have to apply the operation to ALL
13970f1702c5SYu Xiangning 		 * associations. Like with anything of this sort, the
13980f1702c5SYu Xiangning 		 * problem is what to do if the operation fails.
13990f1702c5SYu Xiangning 		 * Just try to apply the setting to everyone, but store
14000f1702c5SYu Xiangning 		 * error number if someone returns such.  And since we are
14010f1702c5SYu Xiangning 		 * looping through all possible aids, some of them can be
14020f1702c5SYu Xiangning 		 * invalid.  We just ignore this kind (sosctp_assoc()) of
14030f1702c5SYu Xiangning 		 * errors.
14040f1702c5SYu Xiangning 		 */
14050f1702c5SYu Xiangning 		sctp_assoc_t aid;
14060f1702c5SYu Xiangning 
14070f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
14080f1702c5SYu Xiangning 		error = sctp_set_opt((struct sctp_s *)so->so_proto_handle,
14090f1702c5SYu Xiangning 		    level, option_name, optval, optlen);
14100f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
14110f1702c5SYu Xiangning 		for (aid = 1; aid < ss->ss_maxassoc; aid++) {
14120f1702c5SYu Xiangning 			if (sosctp_assoc(ss, aid, &ssa) != 0)
14130f1702c5SYu Xiangning 				continue;
14140f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
14150f1702c5SYu Xiangning 			rc = sctp_set_opt((struct sctp_s *)ssa->ssa_conn, level,
14160f1702c5SYu Xiangning 			    option_name, optval, optlen);
14170f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
14180f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
14190f1702c5SYu Xiangning 			if (error == 0) {
14200f1702c5SYu Xiangning 				error = rc;
14210f1702c5SYu Xiangning 			}
14220f1702c5SYu Xiangning 		}
14230f1702c5SYu Xiangning 	}
14240f1702c5SYu Xiangning done:
14250f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
14260f1702c5SYu Xiangning 	return (error);
14270f1702c5SYu Xiangning }
14280f1702c5SYu Xiangning 
14290f1702c5SYu Xiangning /*ARGSUSED*/
14300f1702c5SYu Xiangning static int
14310f1702c5SYu Xiangning sosctp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
14320f1702c5SYu Xiangning     struct cred *cr, int32_t *rvalp)
14330f1702c5SYu Xiangning {
14340f1702c5SYu Xiangning 	struct sctp_sonode	*ss;
14350f1702c5SYu Xiangning 	int32_t			value;
14360f1702c5SYu Xiangning 	int			error;
14370f1702c5SYu Xiangning 	int			intval;
14380f1702c5SYu Xiangning 	pid_t			pid;
14390f1702c5SYu Xiangning 	struct sctp_soassoc	*ssa;
14400f1702c5SYu Xiangning 	void			*conn;
14410f1702c5SYu Xiangning 	void			*buf;
14420f1702c5SYu Xiangning 	STRUCT_DECL(sctpopt, opt);
14430f1702c5SYu Xiangning 	uint32_t		optlen;
14440f1702c5SYu Xiangning 	int			buflen;
14450f1702c5SYu Xiangning 
14460f1702c5SYu Xiangning 	ss = SOTOSSO(so);
14470f1702c5SYu Xiangning 
14480f1702c5SYu Xiangning 	/* handle socket specific ioctls */
14490f1702c5SYu Xiangning 	switch (cmd) {
14500f1702c5SYu Xiangning 	case FIONBIO:
14510f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
14520f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
14530f1702c5SYu Xiangning 			return (EFAULT);
14540f1702c5SYu Xiangning 		}
14550f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
14560f1702c5SYu Xiangning 		if (value) {
14570f1702c5SYu Xiangning 			so->so_state |= SS_NDELAY;
14580f1702c5SYu Xiangning 		} else {
14590f1702c5SYu Xiangning 			so->so_state &= ~SS_NDELAY;
14600f1702c5SYu Xiangning 		}
14610f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
14620f1702c5SYu Xiangning 		return (0);
14630f1702c5SYu Xiangning 
14640f1702c5SYu Xiangning 	case FIOASYNC:
14650f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &value, sizeof (int32_t),
14660f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
14670f1702c5SYu Xiangning 			return (EFAULT);
14680f1702c5SYu Xiangning 		}
14690f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
14700f1702c5SYu Xiangning 
14710f1702c5SYu Xiangning 		if (value) {
14720f1702c5SYu Xiangning 			/* Turn on SIGIO */
14730f1702c5SYu Xiangning 			so->so_state |= SS_ASYNC;
14740f1702c5SYu Xiangning 		} else {
14750f1702c5SYu Xiangning 			/* Turn off SIGIO */
14760f1702c5SYu Xiangning 			so->so_state &= ~SS_ASYNC;
14770f1702c5SYu Xiangning 		}
14780f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
14790f1702c5SYu Xiangning 		return (0);
14800f1702c5SYu Xiangning 
14810f1702c5SYu Xiangning 	case SIOCSPGRP:
14820f1702c5SYu Xiangning 	case FIOSETOWN:
14830f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &pid, sizeof (pid_t),
14840f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
14850f1702c5SYu Xiangning 			return (EFAULT);
14860f1702c5SYu Xiangning 		}
14870f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
14880f1702c5SYu Xiangning 
14890f1702c5SYu Xiangning 		error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0;
14900f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
14910f1702c5SYu Xiangning 		return (error);
14920f1702c5SYu Xiangning 
14930f1702c5SYu Xiangning 	case SIOCGPGRP:
14940f1702c5SYu Xiangning 	case FIOGETOWN:
14950f1702c5SYu Xiangning 		if (so_copyout(&so->so_pgrp, (void *)arg,
14960f1702c5SYu Xiangning 		    sizeof (pid_t), (mode & (int)FKIOCTL)))
14970f1702c5SYu Xiangning 			return (EFAULT);
14980f1702c5SYu Xiangning 		return (0);
14990f1702c5SYu Xiangning 
15000f1702c5SYu Xiangning 	case FIONREAD:
15010f1702c5SYu Xiangning 		/* XXX: Cannot be used unless standard buffer is used */
15020f1702c5SYu Xiangning 		/*
15030f1702c5SYu Xiangning 		 * Return number of bytes of data in all data messages
15040f1702c5SYu Xiangning 		 * in queue in "arg".
15050f1702c5SYu Xiangning 		 * For stream socket, amount of available data.
15060f1702c5SYu Xiangning 		 * For sock_dgram, # of available bytes + addresses.
15070f1702c5SYu Xiangning 		 */
15080f1702c5SYu Xiangning 		intval = (so->so_state & SS_ACCEPTCONN) ? 0 :
15090f1702c5SYu Xiangning 		    MIN(so->so_rcv_queued, INT_MAX);
15100f1702c5SYu Xiangning 		if (so_copyout(&intval, (void *)arg, sizeof (intval),
15110f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL)))
15120f1702c5SYu Xiangning 			return (EFAULT);
15130f1702c5SYu Xiangning 		return (0);
15140f1702c5SYu Xiangning 	case SIOCATMARK:
15150f1702c5SYu Xiangning 		/*
15160f1702c5SYu Xiangning 		 * No support for urgent data.
15170f1702c5SYu Xiangning 		 */
15180f1702c5SYu Xiangning 		intval = 0;
15190f1702c5SYu Xiangning 
15200f1702c5SYu Xiangning 		if (so_copyout(&intval, (void *)arg, sizeof (int),
15210f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL)))
15220f1702c5SYu Xiangning 			return (EFAULT);
15230f1702c5SYu Xiangning 		return (0);
1524de8c4a14SErik Nordmark 	case _I_GETPEERCRED: {
1525de8c4a14SErik Nordmark 		int error = 0;
1526de8c4a14SErik Nordmark 
1527de8c4a14SErik Nordmark 		if ((mode & FKIOCTL) == 0)
1528de8c4a14SErik Nordmark 			return (EINVAL);
1529de8c4a14SErik Nordmark 
1530de8c4a14SErik Nordmark 		mutex_enter(&so->so_lock);
1531de8c4a14SErik Nordmark 		if ((so->so_mode & SM_CONNREQUIRED) == 0) {
1532de8c4a14SErik Nordmark 			error = ENOTSUP;
1533de8c4a14SErik Nordmark 		} else if ((so->so_state & SS_ISCONNECTED) == 0) {
1534de8c4a14SErik Nordmark 			error = ENOTCONN;
1535de8c4a14SErik Nordmark 		} else if (so->so_peercred != NULL) {
1536de8c4a14SErik Nordmark 			k_peercred_t *kp = (k_peercred_t *)arg;
1537de8c4a14SErik Nordmark 			kp->pc_cr = so->so_peercred;
1538de8c4a14SErik Nordmark 			kp->pc_cpid = so->so_cpid;
1539de8c4a14SErik Nordmark 			crhold(so->so_peercred);
1540de8c4a14SErik Nordmark 		} else {
1541de8c4a14SErik Nordmark 			error = EINVAL;
1542de8c4a14SErik Nordmark 		}
1543de8c4a14SErik Nordmark 		mutex_exit(&so->so_lock);
1544de8c4a14SErik Nordmark 		return (error);
1545de8c4a14SErik Nordmark 	}
15460f1702c5SYu Xiangning 	case SIOCSCTPGOPT:
15470f1702c5SYu Xiangning 		STRUCT_INIT(opt, mode);
15480f1702c5SYu Xiangning 
15490f1702c5SYu Xiangning 		if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt),
15500f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
15510f1702c5SYu Xiangning 			return (EFAULT);
15520f1702c5SYu Xiangning 		}
15530f1702c5SYu Xiangning 		if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE)
15540f1702c5SYu Xiangning 			return (EINVAL);
15550f1702c5SYu Xiangning 
15560f1702c5SYu Xiangning 		/*
15570f1702c5SYu Xiangning 		 * Find the correct sctp_t based on whether it is 1-N socket
15580f1702c5SYu Xiangning 		 * or not.
15590f1702c5SYu Xiangning 		 */
15600f1702c5SYu Xiangning 		intval = STRUCT_FGET(opt, sopt_aid);
15610f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
15620f1702c5SYu Xiangning 		if ((so->so_type == SOCK_SEQPACKET) && intval) {
15630f1702c5SYu Xiangning 			if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) {
15640f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
15650f1702c5SYu Xiangning 				return (error);
15660f1702c5SYu Xiangning 			}
15670f1702c5SYu Xiangning 			conn = ssa->ssa_conn;
15680f1702c5SYu Xiangning 			ASSERT(conn != NULL);
15690f1702c5SYu Xiangning 		} else {
15700f1702c5SYu Xiangning 			conn = so->so_proto_handle;
15710f1702c5SYu Xiangning 			ssa = NULL;
15720f1702c5SYu Xiangning 		}
15730f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
15740f1702c5SYu Xiangning 
15750f1702c5SYu Xiangning 		/* Copyin the option buffer and then call sctp_get_opt(). */
15760f1702c5SYu Xiangning 		buflen = optlen;
15770f1702c5SYu Xiangning 		/* Let's allocate a buffer enough to hold an int */
15780f1702c5SYu Xiangning 		if (buflen < sizeof (uint32_t))
15790f1702c5SYu Xiangning 			buflen = sizeof (uint32_t);
15800f1702c5SYu Xiangning 		buf = kmem_alloc(buflen, KM_SLEEP);
15810f1702c5SYu Xiangning 		if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen,
15820f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
15830f1702c5SYu Xiangning 			if (ssa != NULL) {
15840f1702c5SYu Xiangning 				mutex_enter(&so->so_lock);
15850f1702c5SYu Xiangning 				SSA_REFRELE(ss, ssa);
15860f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
15870f1702c5SYu Xiangning 			}
15880f1702c5SYu Xiangning 			kmem_free(buf, buflen);
15890f1702c5SYu Xiangning 			return (EFAULT);
15900f1702c5SYu Xiangning 		}
15910f1702c5SYu Xiangning 		/* The option level has to be IPPROTO_SCTP */
15920f1702c5SYu Xiangning 		error = sctp_get_opt((struct sctp_s *)conn, IPPROTO_SCTP,
15930f1702c5SYu Xiangning 		    STRUCT_FGET(opt, sopt_name), buf, &optlen);
15940f1702c5SYu Xiangning 		if (ssa != NULL) {
15950f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
15960f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
15970f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
15980f1702c5SYu Xiangning 		}
15990f1702c5SYu Xiangning 		optlen = MIN(buflen, optlen);
16000f1702c5SYu Xiangning 		/* No error, copyout the result with the correct buf len. */
16010f1702c5SYu Xiangning 		if (error == 0) {
16020f1702c5SYu Xiangning 			STRUCT_FSET(opt, sopt_len, optlen);
16030f1702c5SYu Xiangning 			if (so_copyout(STRUCT_BUF(opt), (void *)arg,
16040f1702c5SYu Xiangning 			    STRUCT_SIZE(opt), (mode & (int)FKIOCTL))) {
16050f1702c5SYu Xiangning 				error = EFAULT;
16060f1702c5SYu Xiangning 			} else if (so_copyout(buf, STRUCT_FGETP(opt, sopt_val),
16070f1702c5SYu Xiangning 			    optlen, (mode & (int)FKIOCTL))) {
16080f1702c5SYu Xiangning 				error = EFAULT;
16090f1702c5SYu Xiangning 			}
16100f1702c5SYu Xiangning 		}
16110f1702c5SYu Xiangning 		kmem_free(buf, buflen);
16120f1702c5SYu Xiangning 		return (error);
16130f1702c5SYu Xiangning 
16140f1702c5SYu Xiangning 	case SIOCSCTPSOPT:
16150f1702c5SYu Xiangning 		STRUCT_INIT(opt, mode);
16160f1702c5SYu Xiangning 
16170f1702c5SYu Xiangning 		if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt),
16180f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
16190f1702c5SYu Xiangning 			return (EFAULT);
16200f1702c5SYu Xiangning 		}
16210f1702c5SYu Xiangning 		if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE)
16220f1702c5SYu Xiangning 			return (EINVAL);
16230f1702c5SYu Xiangning 
16240f1702c5SYu Xiangning 		/*
16250f1702c5SYu Xiangning 		 * Find the correct sctp_t based on whether it is 1-N socket
16260f1702c5SYu Xiangning 		 * or not.
16270f1702c5SYu Xiangning 		 */
16280f1702c5SYu Xiangning 		intval = STRUCT_FGET(opt, sopt_aid);
16290f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
16300f1702c5SYu Xiangning 		if (intval != 0) {
16310f1702c5SYu Xiangning 			if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) {
16320f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
16330f1702c5SYu Xiangning 				return (error);
16340f1702c5SYu Xiangning 			}
16350f1702c5SYu Xiangning 			conn = ssa->ssa_conn;
16360f1702c5SYu Xiangning 			ASSERT(conn != NULL);
16370f1702c5SYu Xiangning 		} else {
16380f1702c5SYu Xiangning 			conn = so->so_proto_handle;
16390f1702c5SYu Xiangning 			ssa = NULL;
16400f1702c5SYu Xiangning 		}
16410f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
16420f1702c5SYu Xiangning 
16430f1702c5SYu Xiangning 		/* Copyin the option buffer and then call sctp_set_opt(). */
16440f1702c5SYu Xiangning 		buf = kmem_alloc(optlen, KM_SLEEP);
16450f1702c5SYu Xiangning 		if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen,
16460f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
16470f1702c5SYu Xiangning 			if (ssa != NULL) {
16480f1702c5SYu Xiangning 				mutex_enter(&so->so_lock);
16490f1702c5SYu Xiangning 				SSA_REFRELE(ss, ssa);
16500f1702c5SYu Xiangning 				mutex_exit(&so->so_lock);
16510f1702c5SYu Xiangning 			}
16520f1702c5SYu Xiangning 			kmem_free(buf, intval);
16530f1702c5SYu Xiangning 			return (EFAULT);
16540f1702c5SYu Xiangning 		}
16550f1702c5SYu Xiangning 		/* The option level has to be IPPROTO_SCTP */
16560f1702c5SYu Xiangning 		error = sctp_set_opt((struct sctp_s *)conn, IPPROTO_SCTP,
16570f1702c5SYu Xiangning 		    STRUCT_FGET(opt, sopt_name), buf, optlen);
16580f1702c5SYu Xiangning 		if (ssa) {
16590f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
16600f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
16610f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
16620f1702c5SYu Xiangning 		}
16630f1702c5SYu Xiangning 		kmem_free(buf, optlen);
16640f1702c5SYu Xiangning 		return (error);
16650f1702c5SYu Xiangning 
16660f1702c5SYu Xiangning 	case SIOCSCTPPEELOFF: {
16670f1702c5SYu Xiangning 		struct sonode *nso;
16680f1702c5SYu Xiangning 		struct sctp_uc_swap us;
16690f1702c5SYu Xiangning 		int nfd;
16700f1702c5SYu Xiangning 		struct file *nfp;
16710f1702c5SYu Xiangning 		struct vnode *nvp = NULL;
16720f1702c5SYu Xiangning 		struct sockparams *sp;
16730f1702c5SYu Xiangning 
16740f1702c5SYu Xiangning 		dprint(2, ("sctppeeloff %p\n", (void *)ss));
16750f1702c5SYu Xiangning 
16760f1702c5SYu Xiangning 		if (so->so_type != SOCK_SEQPACKET) {
16770f1702c5SYu Xiangning 			return (EOPNOTSUPP);
16780f1702c5SYu Xiangning 		}
16790f1702c5SYu Xiangning 		if (so_copyin((void *)arg, &intval, sizeof (intval),
16800f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
16810f1702c5SYu Xiangning 			return (EFAULT);
16820f1702c5SYu Xiangning 		}
16830f1702c5SYu Xiangning 		if (intval == 0) {
16840f1702c5SYu Xiangning 			return (EINVAL);
16850f1702c5SYu Xiangning 		}
16860f1702c5SYu Xiangning 
16870f1702c5SYu Xiangning 		/*
16880f1702c5SYu Xiangning 		 * Find sockparams. This is different from parent's entry,
16890f1702c5SYu Xiangning 		 * as the socket type is different.
16900f1702c5SYu Xiangning 		 */
16910f1702c5SYu Xiangning 		error = solookup(so->so_family, SOCK_STREAM, so->so_protocol,
16920f1702c5SYu Xiangning 		    &sp);
1693e4b767e8SAnders Persson 		if (error != 0)
1694e4b767e8SAnders Persson 			return (error);
16950f1702c5SYu Xiangning 
16960f1702c5SYu Xiangning 		/*
16970f1702c5SYu Xiangning 		 * Allocate the user fd.
16980f1702c5SYu Xiangning 		 */
16990f1702c5SYu Xiangning 		if ((nfd = ufalloc(0)) == -1) {
17000f1702c5SYu Xiangning 			eprintsoline(so, EMFILE);
170124101488SAnders Persson 			SOCKPARAMS_DEC_REF(sp);
17020f1702c5SYu Xiangning 			return (EMFILE);
17030f1702c5SYu Xiangning 		}
17040f1702c5SYu Xiangning 
17050f1702c5SYu Xiangning 		/*
17060f1702c5SYu Xiangning 		 * Copy the fd out.
17070f1702c5SYu Xiangning 		 */
17080f1702c5SYu Xiangning 		if (so_copyout(&nfd, (void *)arg, sizeof (nfd),
17090f1702c5SYu Xiangning 		    (mode & (int)FKIOCTL))) {
17100f1702c5SYu Xiangning 			error = EFAULT;
17110f1702c5SYu Xiangning 			goto err;
17120f1702c5SYu Xiangning 		}
17130f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
17140f1702c5SYu Xiangning 
17150f1702c5SYu Xiangning 		/*
17160f1702c5SYu Xiangning 		 * Don't use sosctp_assoc() in order to peel off disconnected
17170f1702c5SYu Xiangning 		 * associations.
17180f1702c5SYu Xiangning 		 */
17190f1702c5SYu Xiangning 		ssa = ((uint32_t)intval >= ss->ss_maxassoc) ? NULL :
17200f1702c5SYu Xiangning 		    ss->ss_assocs[intval].ssi_assoc;
17210f1702c5SYu Xiangning 		if (ssa == NULL) {
17220f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
17230f1702c5SYu Xiangning 			error = EINVAL;
17240f1702c5SYu Xiangning 			goto err;
17250f1702c5SYu Xiangning 		}
17260f1702c5SYu Xiangning 		SSA_REFHOLD(ssa);
17270f1702c5SYu Xiangning 
17280f1702c5SYu Xiangning 		nso = socksctp_create(sp, so->so_family, SOCK_STREAM,
17290f1702c5SYu Xiangning 		    so->so_protocol, so->so_version, SOCKET_NOSLEEP,
17300f1702c5SYu Xiangning 		    &error, cr);
17310f1702c5SYu Xiangning 		if (nso == NULL) {
17320f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
17330f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
17340f1702c5SYu Xiangning 			goto err;
17350f1702c5SYu Xiangning 		}
17360f1702c5SYu Xiangning 		nvp = SOTOV(nso);
17370f1702c5SYu Xiangning 		so_lock_single(so);
17380f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1739e4b767e8SAnders Persson 
1740e4b767e8SAnders Persson 		/* cannot fail, only inheriting properties */
1741e4b767e8SAnders Persson 		(void) sosctp_init(nso, so, CRED(), 0);
1742e4b767e8SAnders Persson 
1743e4b767e8SAnders Persson 		/*
1744e4b767e8SAnders Persson 		 * We have a single ref on the new socket. This is normally
1745e4b767e8SAnders Persson 		 * handled by socket_{create,newconn}, but since they are not
1746e4b767e8SAnders Persson 		 * used we have to do it here.
1747e4b767e8SAnders Persson 		 */
1748e4b767e8SAnders Persson 		nso->so_count = 1;
1749e4b767e8SAnders Persson 
1750e4b767e8SAnders Persson 		us.sus_handle = nso;
17510f1702c5SYu Xiangning 		us.sus_upcalls = &sosctp_sock_upcalls;
17520f1702c5SYu Xiangning 
17530f1702c5SYu Xiangning 		/*
17540f1702c5SYu Xiangning 		 * Upcalls to new socket are blocked for the duration of
17550f1702c5SYu Xiangning 		 * downcall.
17560f1702c5SYu Xiangning 		 */
17570f1702c5SYu Xiangning 		mutex_enter(&nso->so_lock);
17580f1702c5SYu Xiangning 
17590f1702c5SYu Xiangning 		error = sctp_set_opt((struct sctp_s *)ssa->ssa_conn,
17600f1702c5SYu Xiangning 		    IPPROTO_SCTP, SCTP_UC_SWAP, &us, sizeof (us));
17610f1702c5SYu Xiangning 		if (error) {
17620f1702c5SYu Xiangning 			goto peelerr;
17630f1702c5SYu Xiangning 		}
17640f1702c5SYu Xiangning 		error = falloc(nvp, FWRITE|FREAD, &nfp, NULL);
17650f1702c5SYu Xiangning 		if (error) {
17660f1702c5SYu Xiangning 			goto peelerr;
17670f1702c5SYu Xiangning 		}
17680f1702c5SYu Xiangning 
17690f1702c5SYu Xiangning 		/*
17700f1702c5SYu Xiangning 		 * fill in the entries that falloc reserved
17710f1702c5SYu Xiangning 		 */
17720f1702c5SYu Xiangning 		nfp->f_vnode = nvp;
17730f1702c5SYu Xiangning 		mutex_exit(&nfp->f_tlock);
17740f1702c5SYu Xiangning 		setf(nfd, nfp);
17750f1702c5SYu Xiangning 
17760f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
17770f1702c5SYu Xiangning 
17780f1702c5SYu Xiangning 		sosctp_assoc_move(ss, SOTOSSO(nso), ssa);
17790f1702c5SYu Xiangning 
17800f1702c5SYu Xiangning 		mutex_exit(&nso->so_lock);
17810f1702c5SYu Xiangning 
17820f1702c5SYu Xiangning 		ssa->ssa_conn = NULL;
17830f1702c5SYu Xiangning 		sosctp_assoc_free(ss, ssa);
17840f1702c5SYu Xiangning 
17850f1702c5SYu Xiangning 		so_unlock_single(so, SOLOCKED);
17860f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
17870f1702c5SYu Xiangning 
17880f1702c5SYu Xiangning 		return (0);
17890f1702c5SYu Xiangning 
17900f1702c5SYu Xiangning err:
179124101488SAnders Persson 		SOCKPARAMS_DEC_REF(sp);
17920f1702c5SYu Xiangning 		setf(nfd, NULL);
17930f1702c5SYu Xiangning 		eprintsoline(so, error);
17940f1702c5SYu Xiangning 		return (error);
17950f1702c5SYu Xiangning 
17960f1702c5SYu Xiangning peelerr:
17970f1702c5SYu Xiangning 		mutex_exit(&nso->so_lock);
17980f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
17990f1702c5SYu Xiangning 		ASSERT(nso->so_count == 1);
18000f1702c5SYu Xiangning 		nso->so_count = 0;
18010f1702c5SYu Xiangning 		so_unlock_single(so, SOLOCKED);
18020f1702c5SYu Xiangning 		SSA_REFRELE(ss, ssa);
18030f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
18040f1702c5SYu Xiangning 
18050f1702c5SYu Xiangning 		setf(nfd, NULL);
18060f1702c5SYu Xiangning 		ASSERT(nvp->v_count == 1);
18070f1702c5SYu Xiangning 		socket_destroy(nso);
18080f1702c5SYu Xiangning 		eprintsoline(so, error);
18090f1702c5SYu Xiangning 		return (error);
18100f1702c5SYu Xiangning 	}
18110f1702c5SYu Xiangning 	default:
18120f1702c5SYu Xiangning 		return (EINVAL);
18130f1702c5SYu Xiangning 	}
18140f1702c5SYu Xiangning }
18150f1702c5SYu Xiangning 
18160f1702c5SYu Xiangning /*ARGSUSED*/
18170f1702c5SYu Xiangning static int
18180f1702c5SYu Xiangning sosctp_close(struct sonode *so, int flag, struct cred *cr)
18190f1702c5SYu Xiangning {
18200f1702c5SYu Xiangning 	struct sctp_sonode *ss;
18210f1702c5SYu Xiangning 	struct sctp_sa_id *ssi;
18220f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
18230f1702c5SYu Xiangning 	int32_t i;
18240f1702c5SYu Xiangning 
18250f1702c5SYu Xiangning 	ss = SOTOSSO(so);
18260f1702c5SYu Xiangning 
18270f1702c5SYu Xiangning 	/*
1828*a215d4ebSKacheong Poon 	 * Initiate connection shutdown.  Tell SCTP if there is any data
1829*a215d4ebSKacheong Poon 	 * left unread.
18300f1702c5SYu Xiangning 	 */
18310f1702c5SYu Xiangning 	sctp_recvd((struct sctp_s *)so->so_proto_handle,
18320f1702c5SYu Xiangning 	    so->so_rcvbuf - so->so_rcv_queued);
18330f1702c5SYu Xiangning 	(void) sctp_disconnect((struct sctp_s *)so->so_proto_handle);
18340f1702c5SYu Xiangning 
18350f1702c5SYu Xiangning 	/*
18360f1702c5SYu Xiangning 	 * New associations can't come in, but old ones might get
18370f1702c5SYu Xiangning 	 * closed in upcall. Protect against that by taking a reference
18380f1702c5SYu Xiangning 	 * on the association.
18390f1702c5SYu Xiangning 	 */
18400f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
18410f1702c5SYu Xiangning 	ssi = ss->ss_assocs;
18420f1702c5SYu Xiangning 	for (i = 0; i < ss->ss_maxassoc; i++, ssi++) {
18430f1702c5SYu Xiangning 		if ((ssa = ssi->ssi_assoc) != NULL) {
18440f1702c5SYu Xiangning 			SSA_REFHOLD(ssa);
18450f1702c5SYu Xiangning 			sosctp_assoc_isdisconnected(ssa, 0);
18460f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
18470f1702c5SYu Xiangning 
1848*a215d4ebSKacheong Poon 			sctp_recvd(ssa->ssa_conn, so->so_rcvbuf -
1849*a215d4ebSKacheong Poon 			    ssa->ssa_rcv_queued);
1850*a215d4ebSKacheong Poon 			(void) sctp_disconnect(ssa->ssa_conn);
18510f1702c5SYu Xiangning 
18520f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
18530f1702c5SYu Xiangning 			SSA_REFRELE(ss, ssa);
18540f1702c5SYu Xiangning 		}
18550f1702c5SYu Xiangning 	}
18560f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
18570f1702c5SYu Xiangning 
18580f1702c5SYu Xiangning 	return (0);
18590f1702c5SYu Xiangning }
18600f1702c5SYu Xiangning 
18610f1702c5SYu Xiangning /*
18620f1702c5SYu Xiangning  * Closes incoming connections which were never accepted, frees
18630f1702c5SYu Xiangning  * resources.
18640f1702c5SYu Xiangning  */
18650f1702c5SYu Xiangning /* ARGSUSED */
18660f1702c5SYu Xiangning void
18670f1702c5SYu Xiangning sosctp_fini(struct sonode *so, struct cred *cr)
18680f1702c5SYu Xiangning {
18690f1702c5SYu Xiangning 	struct sctp_sonode *ss;
18700f1702c5SYu Xiangning 	struct sctp_sa_id *ssi;
18710f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
18720f1702c5SYu Xiangning 	int32_t i;
18730f1702c5SYu Xiangning 
18740f1702c5SYu Xiangning 	ss = SOTOSSO(so);
18750f1702c5SYu Xiangning 
18760f1702c5SYu Xiangning 	ASSERT(so->so_ops == &sosctp_sonodeops ||
18770f1702c5SYu Xiangning 	    so->so_ops == &sosctp_seq_sonodeops);
18780f1702c5SYu Xiangning 
18790f1702c5SYu Xiangning 	/* We are the sole owner of so now */
18800f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
18810f1702c5SYu Xiangning 
18820f1702c5SYu Xiangning 	/* Free all pending connections */
18832320a8c1SAnders Persson 	so_acceptq_flush(so, B_TRUE);
18840f1702c5SYu Xiangning 
18850f1702c5SYu Xiangning 	ssi = ss->ss_assocs;
18860f1702c5SYu Xiangning 	for (i = 0; i < ss->ss_maxassoc; i++, ssi++) {
18870f1702c5SYu Xiangning 		if ((ssa = ssi->ssi_assoc) != NULL) {
18880f1702c5SYu Xiangning 			SSA_REFHOLD(ssa);
18890f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
18900f1702c5SYu Xiangning 
18910f1702c5SYu Xiangning 			sctp_close((struct sctp_s *)ssa->ssa_conn);
18920f1702c5SYu Xiangning 
18930f1702c5SYu Xiangning 			mutex_enter(&so->so_lock);
18940f1702c5SYu Xiangning 			ssa->ssa_conn = NULL;
18950f1702c5SYu Xiangning 			sosctp_assoc_free(ss, ssa);
18960f1702c5SYu Xiangning 		}
18970f1702c5SYu Xiangning 	}
18980f1702c5SYu Xiangning 	if (ss->ss_assocs != NULL) {
18990f1702c5SYu Xiangning 		ASSERT(ss->ss_assoccnt == 0);
19000f1702c5SYu Xiangning 		kmem_free(ss->ss_assocs,
19010f1702c5SYu Xiangning 		    ss->ss_maxassoc * sizeof (struct sctp_sa_id));
19020f1702c5SYu Xiangning 	}
19030f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
19040f1702c5SYu Xiangning 
19050f1702c5SYu Xiangning 	if (so->so_proto_handle)
19060f1702c5SYu Xiangning 		sctp_close((struct sctp_s *)so->so_proto_handle);
19070f1702c5SYu Xiangning 	so->so_proto_handle = NULL;
19080f1702c5SYu Xiangning 
1909*a215d4ebSKacheong Poon 	/*
1910*a215d4ebSKacheong Poon 	 * Note until sctp_close() is called, SCTP can still send up
1911*a215d4ebSKacheong Poon 	 * messages, such as event notifications.  So we should flush
1912*a215d4ebSKacheong Poon 	 * the recevie buffer after calling sctp_close().
1913*a215d4ebSKacheong Poon 	 */
1914*a215d4ebSKacheong Poon 	mutex_enter(&so->so_lock);
1915*a215d4ebSKacheong Poon 	so_rcv_flush(so);
1916*a215d4ebSKacheong Poon 	mutex_exit(&so->so_lock);
1917*a215d4ebSKacheong Poon 
19180f1702c5SYu Xiangning 	sonode_fini(so);
19190f1702c5SYu Xiangning }
19200f1702c5SYu Xiangning 
19210f1702c5SYu Xiangning /*
19220f1702c5SYu Xiangning  * Upcalls from SCTP
19230f1702c5SYu Xiangning  */
19240f1702c5SYu Xiangning 
19250f1702c5SYu Xiangning /*
19260f1702c5SYu Xiangning  * This is the upcall function for 1-N (SOCK_SEQPACKET) socket when a new
19270f1702c5SYu Xiangning  * association is created.  Note that the first argument (handle) is of type
19280f1702c5SYu Xiangning  * sctp_sonode *, which is the one changed to a listener for new
19290f1702c5SYu Xiangning  * associations.  All the other upcalls for 1-N socket take sctp_soassoc *
19300f1702c5SYu Xiangning  * as handle.  The only exception is the su_properties upcall, which
19310f1702c5SYu Xiangning  * can take both types as handle.
19320f1702c5SYu Xiangning  */
19330f1702c5SYu Xiangning /* ARGSUSED */
19340f1702c5SYu Xiangning sock_upper_handle_t
19350f1702c5SYu Xiangning sctp_assoc_newconn(sock_upper_handle_t parenthandle,
19360f1702c5SYu Xiangning     sock_lower_handle_t connind, sock_downcalls_t *dc,
19370f1702c5SYu Xiangning     struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **ucp)
19380f1702c5SYu Xiangning {
1939*a215d4ebSKacheong Poon 	struct sctp_sonode *lss = (struct sctp_sonode *)parenthandle;
1940*a215d4ebSKacheong Poon 	struct sonode *lso = &lss->ss_so;
19410f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
19420f1702c5SYu Xiangning 	sctp_assoc_t id;
19430f1702c5SYu Xiangning 
19440f1702c5SYu Xiangning 	ASSERT(lss->ss_type == SOSCTP_SOCKET);
19450f1702c5SYu Xiangning 	ASSERT(lso->so_state & SS_ACCEPTCONN);
19460f1702c5SYu Xiangning 	ASSERT(lso->so_proto_handle != NULL); /* closed conn */
19470f1702c5SYu Xiangning 	ASSERT(lso->so_type == SOCK_SEQPACKET);
19480f1702c5SYu Xiangning 
19490f1702c5SYu Xiangning 	mutex_enter(&lso->so_lock);
19500f1702c5SYu Xiangning 
19510f1702c5SYu Xiangning 	if ((id = sosctp_aid_get(lss)) == -1) {
19520f1702c5SYu Xiangning 		/*
19530f1702c5SYu Xiangning 		 * Array not large enough; increase size.
19540f1702c5SYu Xiangning 		 */
19550f1702c5SYu Xiangning 		if (sosctp_aid_grow(lss, lss->ss_maxassoc, KM_NOSLEEP) < 0) {
19560f1702c5SYu Xiangning 			mutex_exit(&lso->so_lock);
19570f1702c5SYu Xiangning 			return (NULL);
19580f1702c5SYu Xiangning 		}
19590f1702c5SYu Xiangning 		id = sosctp_aid_get(lss);
19600f1702c5SYu Xiangning 		ASSERT(id != -1);
19610f1702c5SYu Xiangning 	}
19620f1702c5SYu Xiangning 
19630f1702c5SYu Xiangning 	/*
19640f1702c5SYu Xiangning 	 * Create soassoc for this connection
19650f1702c5SYu Xiangning 	 */
19660f1702c5SYu Xiangning 	ssa = sosctp_assoc_create(lss, KM_NOSLEEP);
19670f1702c5SYu Xiangning 	if (ssa == NULL) {
19680f1702c5SYu Xiangning 		mutex_exit(&lso->so_lock);
19690f1702c5SYu Xiangning 		return (NULL);
19700f1702c5SYu Xiangning 	}
19710f1702c5SYu Xiangning 	sosctp_aid_reserve(lss, id, 1);
19720f1702c5SYu Xiangning 	lss->ss_assocs[id].ssi_assoc = ssa;
19730f1702c5SYu Xiangning 	++lss->ss_assoccnt;
19740f1702c5SYu Xiangning 	ssa->ssa_id = id;
19750f1702c5SYu Xiangning 	ssa->ssa_conn = (struct sctp_s *)connind;
19760f1702c5SYu Xiangning 	ssa->ssa_state = (SS_ISBOUND | SS_ISCONNECTED);
19770f1702c5SYu Xiangning 	ssa->ssa_wroff = lss->ss_wroff;
19780f1702c5SYu Xiangning 	ssa->ssa_wrsize = lss->ss_wrsize;
19790f1702c5SYu Xiangning 
19800f1702c5SYu Xiangning 	mutex_exit(&lso->so_lock);
19810f1702c5SYu Xiangning 
19820f1702c5SYu Xiangning 	*ucp = &sosctp_assoc_upcalls;
19830f1702c5SYu Xiangning 
19840f1702c5SYu Xiangning 	return ((sock_upper_handle_t)ssa);
19850f1702c5SYu Xiangning }
19860f1702c5SYu Xiangning 
19870f1702c5SYu Xiangning /* ARGSUSED */
19880f1702c5SYu Xiangning static void
19890f1702c5SYu Xiangning sctp_assoc_connected(sock_upper_handle_t handle, sock_connid_t id,
19900f1702c5SYu Xiangning     struct cred *peer_cred, pid_t peer_cpid)
19910f1702c5SYu Xiangning {
19920f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
19930f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
19940f1702c5SYu Xiangning 
19950f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
19960f1702c5SYu Xiangning 	ASSERT(ssa->ssa_conn);
19970f1702c5SYu Xiangning 
19980f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
19990f1702c5SYu Xiangning 	sosctp_assoc_isconnected(ssa);
20000f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
20010f1702c5SYu Xiangning }
20020f1702c5SYu Xiangning 
20030f1702c5SYu Xiangning /* ARGSUSED */
20040f1702c5SYu Xiangning static int
20050f1702c5SYu Xiangning sctp_assoc_disconnected(sock_upper_handle_t handle, sock_connid_t id, int error)
20060f1702c5SYu Xiangning {
20070f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20080f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
20090f1702c5SYu Xiangning 	int ret;
20100f1702c5SYu Xiangning 
20110f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
20120f1702c5SYu Xiangning 	ASSERT(ssa->ssa_conn != NULL);
20130f1702c5SYu Xiangning 
20140f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
20150f1702c5SYu Xiangning 	sosctp_assoc_isdisconnected(ssa, error);
20160f1702c5SYu Xiangning 	if (ssa->ssa_refcnt == 1) {
20170f1702c5SYu Xiangning 		ret = 1;
20180f1702c5SYu Xiangning 		ssa->ssa_conn = NULL;
20190f1702c5SYu Xiangning 	} else {
20200f1702c5SYu Xiangning 		ret = 0;
20210f1702c5SYu Xiangning 	}
20220f1702c5SYu Xiangning 	SSA_REFRELE(SOTOSSO(so), ssa);
20230f1702c5SYu Xiangning 
20240f1702c5SYu Xiangning 	cv_broadcast(&so->so_snd_cv);
20250f1702c5SYu Xiangning 
20260f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
20270f1702c5SYu Xiangning 
20280f1702c5SYu Xiangning 	return (ret);
20290f1702c5SYu Xiangning }
20300f1702c5SYu Xiangning 
20310f1702c5SYu Xiangning /* ARGSUSED */
20320f1702c5SYu Xiangning static void
20330f1702c5SYu Xiangning sctp_assoc_disconnecting(sock_upper_handle_t handle, sock_opctl_action_t action,
20340f1702c5SYu Xiangning     uintptr_t arg)
20350f1702c5SYu Xiangning {
20360f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20370f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
20380f1702c5SYu Xiangning 
20390f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
20400f1702c5SYu Xiangning 	ASSERT(ssa->ssa_conn != NULL);
20410f1702c5SYu Xiangning 	ASSERT(action == SOCK_OPCTL_SHUT_SEND);
20420f1702c5SYu Xiangning 
20430f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
20440f1702c5SYu Xiangning 	sosctp_assoc_isdisconnecting(ssa);
20450f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
20460f1702c5SYu Xiangning }
20470f1702c5SYu Xiangning 
20480f1702c5SYu Xiangning /* ARGSUSED */
20490f1702c5SYu Xiangning static ssize_t
20500f1702c5SYu Xiangning sctp_assoc_recv(sock_upper_handle_t handle, mblk_t *mp, size_t len, int flags,
20510f1702c5SYu Xiangning     int *errorp, boolean_t *forcepush)
20520f1702c5SYu Xiangning {
20530f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20540f1702c5SYu Xiangning 	struct sctp_sonode *ss = ssa->ssa_sonode;
20550f1702c5SYu Xiangning 	struct sonode *so = &ss->ss_so;
20560f1702c5SYu Xiangning 	struct T_unitdata_ind *tind;
20570f1702c5SYu Xiangning 	mblk_t *mp2;
20580f1702c5SYu Xiangning 	union sctp_notification *sn;
20590f1702c5SYu Xiangning 	struct sctp_sndrcvinfo *sinfo;
2060419dcee7SAnders Persson 	ssize_t space_available;
20610f1702c5SYu Xiangning 
20620f1702c5SYu Xiangning 	ASSERT(ssa->ssa_type == SOSCTP_ASSOC);
20630f1702c5SYu Xiangning 	ASSERT(so->so_type == SOCK_SEQPACKET);
20640f1702c5SYu Xiangning 	ASSERT(ssa->ssa_conn != NULL); /* closed conn */
20650f1702c5SYu Xiangning 	ASSERT(mp != NULL);
20660f1702c5SYu Xiangning 
20670f1702c5SYu Xiangning 	ASSERT(errorp != NULL);
20680f1702c5SYu Xiangning 	*errorp = 0;
20690f1702c5SYu Xiangning 
20700f1702c5SYu Xiangning 	/*
20710f1702c5SYu Xiangning 	 * Should be getting T_unitdata_req's only.
20720f1702c5SYu Xiangning 	 * Must have address as part of packet.
20730f1702c5SYu Xiangning 	 */
20740f1702c5SYu Xiangning 	tind = (struct T_unitdata_ind *)mp->b_rptr;
20750f1702c5SYu Xiangning 	ASSERT((DB_TYPE(mp) == M_PROTO) &&
20760f1702c5SYu Xiangning 	    (tind->PRIM_type == T_UNITDATA_IND));
20770f1702c5SYu Xiangning 	ASSERT(tind->SRC_length);
20780f1702c5SYu Xiangning 
20790f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
20800f1702c5SYu Xiangning 
20810f1702c5SYu Xiangning 	/*
20820f1702c5SYu Xiangning 	 * For notify messages, need to fill in association id.
20830f1702c5SYu Xiangning 	 * For data messages, sndrcvinfo could be in ancillary data.
20840f1702c5SYu Xiangning 	 */
2085866a73c2SRao Shoaib 	if (mp->b_flag & SCTP_NOTIFICATION) {
20860f1702c5SYu Xiangning 		mp2 = mp->b_cont;
20870f1702c5SYu Xiangning 		sn = (union sctp_notification *)mp2->b_rptr;
20880f1702c5SYu Xiangning 		switch (sn->sn_header.sn_type) {
20890f1702c5SYu Xiangning 		case SCTP_ASSOC_CHANGE:
20900f1702c5SYu Xiangning 			sn->sn_assoc_change.sac_assoc_id = ssa->ssa_id;
20910f1702c5SYu Xiangning 			break;
20920f1702c5SYu Xiangning 		case SCTP_PEER_ADDR_CHANGE:
20930f1702c5SYu Xiangning 			sn->sn_paddr_change.spc_assoc_id = ssa->ssa_id;
20940f1702c5SYu Xiangning 			break;
20950f1702c5SYu Xiangning 		case SCTP_REMOTE_ERROR:
20960f1702c5SYu Xiangning 			sn->sn_remote_error.sre_assoc_id = ssa->ssa_id;
20970f1702c5SYu Xiangning 			break;
20980f1702c5SYu Xiangning 		case SCTP_SEND_FAILED:
20990f1702c5SYu Xiangning 			sn->sn_send_failed.ssf_assoc_id = ssa->ssa_id;
21000f1702c5SYu Xiangning 			break;
21010f1702c5SYu Xiangning 		case SCTP_SHUTDOWN_EVENT:
21020f1702c5SYu Xiangning 			sn->sn_shutdown_event.sse_assoc_id = ssa->ssa_id;
21030f1702c5SYu Xiangning 			break;
21040f1702c5SYu Xiangning 		case SCTP_ADAPTATION_INDICATION:
21050f1702c5SYu Xiangning 			sn->sn_adaptation_event.sai_assoc_id = ssa->ssa_id;
21060f1702c5SYu Xiangning 			break;
21070f1702c5SYu Xiangning 		case SCTP_PARTIAL_DELIVERY_EVENT:
21080f1702c5SYu Xiangning 			sn->sn_pdapi_event.pdapi_assoc_id = ssa->ssa_id;
21090f1702c5SYu Xiangning 			break;
21100f1702c5SYu Xiangning 		default:
21110f1702c5SYu Xiangning 			ASSERT(0);
21120f1702c5SYu Xiangning 			break;
21130f1702c5SYu Xiangning 		}
21140f1702c5SYu Xiangning 	} else {
21150f1702c5SYu Xiangning 		if (tind->OPT_length > 0) {
21160f1702c5SYu Xiangning 			struct cmsghdr	*cmsg;
21170f1702c5SYu Xiangning 			char		*cend;
21180f1702c5SYu Xiangning 
21190f1702c5SYu Xiangning 			cmsg = (struct cmsghdr *)
21200f1702c5SYu Xiangning 			    ((uchar_t *)mp->b_rptr + tind->OPT_offset);
21210f1702c5SYu Xiangning 			cend = (char *)cmsg + tind->OPT_length;
21220f1702c5SYu Xiangning 			for (;;) {
21230f1702c5SYu Xiangning 				if ((char *)(cmsg + 1) > cend ||
21240f1702c5SYu Xiangning 				    ((char *)cmsg + cmsg->cmsg_len) > cend) {
21250f1702c5SYu Xiangning 					break;
21260f1702c5SYu Xiangning 				}
21270f1702c5SYu Xiangning 				if ((cmsg->cmsg_level == IPPROTO_SCTP) &&
21280f1702c5SYu Xiangning 				    (cmsg->cmsg_type == SCTP_SNDRCV)) {
21290f1702c5SYu Xiangning 					sinfo = (struct sctp_sndrcvinfo *)
21300f1702c5SYu Xiangning 					    (cmsg + 1);
21310f1702c5SYu Xiangning 					sinfo->sinfo_assoc_id = ssa->ssa_id;
21320f1702c5SYu Xiangning 					break;
21330f1702c5SYu Xiangning 				}
21340f1702c5SYu Xiangning 				if (cmsg->cmsg_len > 0) {
21350f1702c5SYu Xiangning 					cmsg = (struct cmsghdr *)
21360f1702c5SYu Xiangning 					    ((uchar_t *)cmsg + cmsg->cmsg_len);
21370f1702c5SYu Xiangning 				} else {
21380f1702c5SYu Xiangning 					break;
21390f1702c5SYu Xiangning 				}
21400f1702c5SYu Xiangning 			}
21410f1702c5SYu Xiangning 		}
21420f1702c5SYu Xiangning 	}
21430f1702c5SYu Xiangning 
21440f1702c5SYu Xiangning 	/*
21450f1702c5SYu Xiangning 	 * SCTP has reserved space in the header for storing a pointer.
21460f1702c5SYu Xiangning 	 * Put the pointer to assocation there, and queue the data.
21470f1702c5SYu Xiangning 	 */
21480f1702c5SYu Xiangning 	SSA_REFHOLD(ssa);
21490f1702c5SYu Xiangning 	ASSERT((mp->b_rptr - DB_BASE(mp)) >= sizeof (ssa));
21500f1702c5SYu Xiangning 	*(struct sctp_soassoc **)DB_BASE(mp) = ssa;
21510f1702c5SYu Xiangning 
2152419dcee7SAnders Persson 	ssa->ssa_rcv_queued += len;
2153419dcee7SAnders Persson 	space_available = so->so_rcvbuf - ssa->ssa_rcv_queued;
2154*a215d4ebSKacheong Poon 	if (space_available <= 0)
2155*a215d4ebSKacheong Poon 		ssa->ssa_flowctrld = B_TRUE;
2156*a215d4ebSKacheong Poon 
2157419dcee7SAnders Persson 	so_enqueue_msg(so, mp, len);
21580f1702c5SYu Xiangning 
2159419dcee7SAnders Persson 	/* so_notify_data drops so_lock */
2160419dcee7SAnders Persson 	so_notify_data(so, len);
2161419dcee7SAnders Persson 
2162419dcee7SAnders Persson 	return (space_available);
21630f1702c5SYu Xiangning }
21640f1702c5SYu Xiangning 
21650f1702c5SYu Xiangning static void
21660f1702c5SYu Xiangning sctp_assoc_xmitted(sock_upper_handle_t handle, boolean_t qfull)
21670f1702c5SYu Xiangning {
21680f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
21690f1702c5SYu Xiangning 	struct sctp_sonode *ss = ssa->ssa_sonode;
21700f1702c5SYu Xiangning 
21710f1702c5SYu Xiangning 	ASSERT(ssa->ssa_type == SOSCTP_ASSOC);
21720f1702c5SYu Xiangning 	ASSERT(ss->ss_so.so_type == SOCK_SEQPACKET);
21730f1702c5SYu Xiangning 	ASSERT(ssa->ssa_conn != NULL);
21740f1702c5SYu Xiangning 
21750f1702c5SYu Xiangning 	mutex_enter(&ss->ss_so.so_lock);
21760f1702c5SYu Xiangning 
21770f1702c5SYu Xiangning 	ssa->ssa_snd_qfull = qfull;
21780f1702c5SYu Xiangning 
21790f1702c5SYu Xiangning 	/*
21800f1702c5SYu Xiangning 	 * Wake blocked writers.
21810f1702c5SYu Xiangning 	 */
21820f1702c5SYu Xiangning 	cv_broadcast(&ss->ss_so.so_snd_cv);
21830f1702c5SYu Xiangning 
21840f1702c5SYu Xiangning 	mutex_exit(&ss->ss_so.so_lock);
21850f1702c5SYu Xiangning }
21860f1702c5SYu Xiangning 
21870f1702c5SYu Xiangning static void
21880f1702c5SYu Xiangning sctp_assoc_properties(sock_upper_handle_t handle,
21890f1702c5SYu Xiangning     struct sock_proto_props *soppp)
21900f1702c5SYu Xiangning {
21910f1702c5SYu Xiangning 	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
2192*a215d4ebSKacheong Poon 	struct sonode *so;
21930f1702c5SYu Xiangning 
21940f1702c5SYu Xiangning 	if (ssa->ssa_type == SOSCTP_ASSOC) {
2195*a215d4ebSKacheong Poon 		so = &ssa->ssa_sonode->ss_so;
21960f1702c5SYu Xiangning 
2197*a215d4ebSKacheong Poon 		mutex_enter(&so->so_lock);
2198*a215d4ebSKacheong Poon 
2199*a215d4ebSKacheong Poon 		/* Per assoc_id properties. */
2200*a215d4ebSKacheong Poon 		if (soppp->sopp_flags & SOCKOPT_WROFF)
22010f1702c5SYu Xiangning 			ssa->ssa_wroff = soppp->sopp_wroff;
2202*a215d4ebSKacheong Poon 		if (soppp->sopp_flags & SOCKOPT_MAXBLK)
22030f1702c5SYu Xiangning 			ssa->ssa_wrsize = soppp->sopp_maxblk;
22040f1702c5SYu Xiangning 	} else {
2205*a215d4ebSKacheong Poon 		so = &((struct sctp_sonode *)handle)->ss_so;
2206*a215d4ebSKacheong Poon 		mutex_enter(&so->so_lock);
22070f1702c5SYu Xiangning 
2208*a215d4ebSKacheong Poon 		if (soppp->sopp_flags & SOCKOPT_WROFF)
2209*a215d4ebSKacheong Poon 			so->so_proto_props.sopp_wroff = soppp->sopp_wroff;
2210*a215d4ebSKacheong Poon 		if (soppp->sopp_flags & SOCKOPT_MAXBLK)
2211*a215d4ebSKacheong Poon 			so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk;
2212*a215d4ebSKacheong Poon 		if (soppp->sopp_flags & SOCKOPT_RCVHIWAT) {
2213*a215d4ebSKacheong Poon 			ssize_t lowat;
22140f1702c5SYu Xiangning 
2215*a215d4ebSKacheong Poon 			so->so_rcvbuf = soppp->sopp_rxhiwat;
2216*a215d4ebSKacheong Poon 			/*
2217*a215d4ebSKacheong Poon 			 * The low water mark should be adjusted properly
2218*a215d4ebSKacheong Poon 			 * if the high water mark is changed.  It should
2219*a215d4ebSKacheong Poon 			 * not be bigger than 1/4 of high water mark.
2220*a215d4ebSKacheong Poon 			 */
2221*a215d4ebSKacheong Poon 			lowat = soppp->sopp_rxhiwat >> 2;
2222*a215d4ebSKacheong Poon 			if (so->so_rcvlowat > lowat) {
2223*a215d4ebSKacheong Poon 				/* Sanity check... */
2224*a215d4ebSKacheong Poon 				if (lowat == 0)
2225*a215d4ebSKacheong Poon 					so->so_rcvlowat = soppp->sopp_rxhiwat;
2226*a215d4ebSKacheong Poon 				else
2227*a215d4ebSKacheong Poon 					so->so_rcvlowat = lowat;
2228*a215d4ebSKacheong Poon 			}
2229*a215d4ebSKacheong Poon 		}
2230*a215d4ebSKacheong Poon 	}
2231*a215d4ebSKacheong Poon 	mutex_exit(&so->so_lock);
22320f1702c5SYu Xiangning }
2233