xref: /titanic_53/usr/src/uts/common/inet/sockmods/socksctpsubr.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning  * CDDL HEADER START
30f1702c5SYu Xiangning  *
40f1702c5SYu Xiangning  * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning  * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning  * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning  *
80f1702c5SYu Xiangning  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning  * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning  * See the License for the specific language governing permissions
110f1702c5SYu Xiangning  * and limitations under the License.
120f1702c5SYu Xiangning  *
130f1702c5SYu Xiangning  * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning  * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning  * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning  * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning  *
190f1702c5SYu Xiangning  * CDDL HEADER END
200f1702c5SYu Xiangning  */
210f1702c5SYu Xiangning 
220f1702c5SYu Xiangning /*
23*a215d4ebSKacheong Poon  * Copyright (c) 2004, 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/debug.h>
310f1702c5SYu Xiangning #include <sys/errno.h>
320f1702c5SYu Xiangning #include <sys/strsubr.h>
330f1702c5SYu Xiangning #include <sys/cmn_err.h>
340f1702c5SYu Xiangning #include <sys/sysmacros.h>
350f1702c5SYu Xiangning 
360f1702c5SYu Xiangning #include <sys/socket.h>
370f1702c5SYu Xiangning #include <sys/socketvar.h>
380f1702c5SYu Xiangning #include <sys/strsun.h>
390f1702c5SYu Xiangning #include <sys/signal.h>
400f1702c5SYu Xiangning 
410f1702c5SYu Xiangning #include <netinet/sctp.h>
420f1702c5SYu Xiangning #include <inet/sctp_itf.h>
430f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
440f1702c5SYu Xiangning #include "socksctp.h"
450f1702c5SYu Xiangning 
460f1702c5SYu Xiangning extern kmem_cache_t *sosctp_assoccache;
470f1702c5SYu Xiangning /*
480f1702c5SYu Xiangning  * Find a free association id. See os/fio.c file descriptor allocator
490f1702c5SYu Xiangning  * for description of the algorithm.
500f1702c5SYu Xiangning  */
510f1702c5SYu Xiangning sctp_assoc_t
sosctp_aid_get(struct sctp_sonode * ss)520f1702c5SYu Xiangning sosctp_aid_get(struct sctp_sonode *ss)
530f1702c5SYu Xiangning {
540f1702c5SYu Xiangning 	sctp_assoc_t id, size, ralloc;
550f1702c5SYu Xiangning 	struct sctp_sa_id *assocs = ss->ss_assocs;
560f1702c5SYu Xiangning 
570f1702c5SYu Xiangning 	ASSERT((ss->ss_maxassoc & (ss->ss_maxassoc + 1)) == 0);
580f1702c5SYu Xiangning 
590f1702c5SYu Xiangning 	for (id = 1; (uint32_t)id < ss->ss_maxassoc; id |= id + 1) {
600f1702c5SYu Xiangning 		size = id + 1;
610f1702c5SYu Xiangning 		if (assocs[id].ssi_alloc == size)
620f1702c5SYu Xiangning 			continue;
630f1702c5SYu Xiangning 		for (ralloc = 0, size >>= 1; size != 0; size >>= 1) {
640f1702c5SYu Xiangning 			ralloc += assocs[id + size].ssi_alloc;
650f1702c5SYu Xiangning 			if (assocs[id].ssi_alloc == ralloc + size) {
660f1702c5SYu Xiangning 				id += size;
670f1702c5SYu Xiangning 				ralloc = 0;
680f1702c5SYu Xiangning 			}
690f1702c5SYu Xiangning 		}
700f1702c5SYu Xiangning 		return (id);
710f1702c5SYu Xiangning 	}
720f1702c5SYu Xiangning 	return (-1);
730f1702c5SYu Xiangning }
740f1702c5SYu Xiangning 
750f1702c5SYu Xiangning /*
760f1702c5SYu Xiangning  * Allocate or free ID, depending on whether incr is 1 or -1
770f1702c5SYu Xiangning  */
780f1702c5SYu Xiangning void
sosctp_aid_reserve(struct sctp_sonode * ss,sctp_assoc_t id,int incr)790f1702c5SYu Xiangning sosctp_aid_reserve(struct sctp_sonode *ss, sctp_assoc_t id, int incr)
800f1702c5SYu Xiangning {
810f1702c5SYu Xiangning 	struct sctp_sa_id *assocs = ss->ss_assocs;
820f1702c5SYu Xiangning 	sctp_assoc_t pid;
830f1702c5SYu Xiangning 
840f1702c5SYu Xiangning 	ASSERT((assocs[id].ssi_assoc == NULL && incr == 1) ||
850f1702c5SYu Xiangning 	    (assocs[id].ssi_assoc != NULL && incr == -1));
860f1702c5SYu Xiangning 
870f1702c5SYu Xiangning 	for (pid = id; pid >= 0; pid = (pid & (pid + 1)) - 1) {
880f1702c5SYu Xiangning 		assocs[pid].ssi_alloc += incr;
890f1702c5SYu Xiangning 	}
900f1702c5SYu Xiangning }
910f1702c5SYu Xiangning 
920f1702c5SYu Xiangning /*
930f1702c5SYu Xiangning  * Increase size of the ss_assocs array to accommodate at least maxid.
940f1702c5SYu Xiangning  * We keep the size of the form 2^n - 1 for benefit of sosctp_aid_get().
950f1702c5SYu Xiangning  */
960f1702c5SYu Xiangning int
sosctp_aid_grow(struct sctp_sonode * ss,sctp_assoc_t maxid,int kmflags)970f1702c5SYu Xiangning sosctp_aid_grow(struct sctp_sonode *ss, sctp_assoc_t maxid, int kmflags)
980f1702c5SYu Xiangning {
990f1702c5SYu Xiangning 	sctp_assoc_t newcnt, oldcnt;
1000f1702c5SYu Xiangning 	struct sctp_sa_id *newlist, *oldlist;
1010f1702c5SYu Xiangning 
1020f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&ss->ss_so.so_lock));
1030f1702c5SYu Xiangning 	for (newcnt = 1; newcnt <= maxid; newcnt = (newcnt << 1) | 1) {
1040f1702c5SYu Xiangning 		continue;
1050f1702c5SYu Xiangning 	}
1060f1702c5SYu Xiangning 
1070f1702c5SYu Xiangning 	mutex_exit(&ss->ss_so.so_lock);
1080f1702c5SYu Xiangning 	newlist = kmem_alloc(newcnt * sizeof (struct sctp_sa_id), kmflags);
1090f1702c5SYu Xiangning 	mutex_enter(&ss->ss_so.so_lock);
1100f1702c5SYu Xiangning 	if (newlist == NULL) {
1110f1702c5SYu Xiangning 		return (-1);
1120f1702c5SYu Xiangning 	}
1130f1702c5SYu Xiangning 	oldcnt = ss->ss_maxassoc;
1140f1702c5SYu Xiangning 	if (newcnt <= oldcnt) {
1150f1702c5SYu Xiangning 		kmem_free(newlist, newcnt * sizeof (struct sctp_sa_id));
1160f1702c5SYu Xiangning 		return (0);
1170f1702c5SYu Xiangning 	}
1180f1702c5SYu Xiangning 	ASSERT((newcnt & (newcnt + 1)) == 0);
1190f1702c5SYu Xiangning 	oldlist = ss->ss_assocs;
1200f1702c5SYu Xiangning 	ss->ss_assocs = newlist;
1210f1702c5SYu Xiangning 	ss->ss_maxassoc = newcnt;
1220f1702c5SYu Xiangning 
1230f1702c5SYu Xiangning 	bcopy(oldlist, newlist, oldcnt * sizeof (struct sctp_sa_id));
1240f1702c5SYu Xiangning 	bzero(newlist + oldcnt,
1250f1702c5SYu Xiangning 	    (newcnt - oldcnt) * sizeof (struct sctp_sa_id));
1260f1702c5SYu Xiangning 	if (oldlist != NULL) {
1270f1702c5SYu Xiangning 		kmem_free(oldlist, oldcnt * sizeof (struct sctp_sa_id));
1280f1702c5SYu Xiangning 	}
1290f1702c5SYu Xiangning 	return (0);
1300f1702c5SYu Xiangning }
1310f1702c5SYu Xiangning 
1320f1702c5SYu Xiangning /*
1330f1702c5SYu Xiangning  * Convert a id into a pointer to sctp_sockassoc structure.
1340f1702c5SYu Xiangning  * Increments refcnt.
1350f1702c5SYu Xiangning  */
1360f1702c5SYu Xiangning int
sosctp_assoc(struct sctp_sonode * ss,sctp_assoc_t id,struct sctp_soassoc ** ssa)1370f1702c5SYu Xiangning sosctp_assoc(struct sctp_sonode *ss, sctp_assoc_t id, struct sctp_soassoc **ssa)
1380f1702c5SYu Xiangning {
1390f1702c5SYu Xiangning 	ASSERT(ssa != NULL);
1400f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&ss->ss_so.so_lock));
1410f1702c5SYu Xiangning 	if ((uint32_t)id >= ss->ss_maxassoc) {
1420f1702c5SYu Xiangning 		*ssa = NULL;
1430f1702c5SYu Xiangning 		return (EINVAL);
1440f1702c5SYu Xiangning 	}
1450f1702c5SYu Xiangning 
1460f1702c5SYu Xiangning 	if ((*ssa = ss->ss_assocs[id].ssi_assoc) == NULL) {
1470f1702c5SYu Xiangning 		return (EINVAL);
1480f1702c5SYu Xiangning 	}
1490f1702c5SYu Xiangning 	if (((*ssa)->ssa_state & (SS_CANTSENDMORE|SS_CANTRCVMORE)) ==
1500f1702c5SYu Xiangning 	    (SS_CANTSENDMORE|SS_CANTRCVMORE)) {
1510f1702c5SYu Xiangning 		/*
1520f1702c5SYu Xiangning 		 * Disconnected connection, shouldn't be found anymore
1530f1702c5SYu Xiangning 		 */
1540f1702c5SYu Xiangning 		*ssa = NULL;
1550f1702c5SYu Xiangning 		return (ESHUTDOWN);
1560f1702c5SYu Xiangning 	}
1570f1702c5SYu Xiangning 	SSA_REFHOLD(*ssa)
1580f1702c5SYu Xiangning 
1590f1702c5SYu Xiangning 	return (0);
1600f1702c5SYu Xiangning }
1610f1702c5SYu Xiangning 
1620f1702c5SYu Xiangning /*
1630f1702c5SYu Xiangning  * Can be called from upcall, or through system call.
1640f1702c5SYu Xiangning  */
1650f1702c5SYu Xiangning struct sctp_soassoc *
sosctp_assoc_create(struct sctp_sonode * ss,int kmflag)1660f1702c5SYu Xiangning sosctp_assoc_create(struct sctp_sonode *ss, int kmflag)
1670f1702c5SYu Xiangning {
1680f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
1690f1702c5SYu Xiangning 
1700f1702c5SYu Xiangning 	ssa = kmem_cache_alloc(sosctp_assoccache, kmflag);
1710f1702c5SYu Xiangning 	if (ssa != NULL) {
1720f1702c5SYu Xiangning 		ssa->ssa_type = SOSCTP_ASSOC;
1730f1702c5SYu Xiangning 		ssa->ssa_refcnt = 1;
1740f1702c5SYu Xiangning 		ssa->ssa_sonode = ss;
1750f1702c5SYu Xiangning 		ssa->ssa_state = 0;
1760f1702c5SYu Xiangning 		ssa->ssa_error = 0;
1770f1702c5SYu Xiangning 		ssa->ssa_snd_qfull = 0;
178419dcee7SAnders Persson 		ssa->ssa_rcv_queued = 0;
179*a215d4ebSKacheong Poon 		ssa->ssa_flowctrld = B_FALSE;
1800f1702c5SYu Xiangning 	}
1810f1702c5SYu Xiangning 	dprint(2, ("sosctp_assoc_create %p %p\n", (void *)ss, (void *)ssa));
1820f1702c5SYu Xiangning 	return (ssa);
1830f1702c5SYu Xiangning }
1840f1702c5SYu Xiangning 
1850f1702c5SYu Xiangning void
sosctp_assoc_free(struct sctp_sonode * ss,struct sctp_soassoc * ssa)1860f1702c5SYu Xiangning sosctp_assoc_free(struct sctp_sonode *ss, struct sctp_soassoc *ssa)
1870f1702c5SYu Xiangning {
1880f1702c5SYu Xiangning 	struct sonode *so = &ss->ss_so;
1890f1702c5SYu Xiangning 
1900f1702c5SYu Xiangning 	dprint(2, ("sosctp_assoc_free %p %p (%d)\n", (void *)ss, (void *)ssa,
1910f1702c5SYu Xiangning 	    ssa->ssa_id));
1920f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
1930f1702c5SYu Xiangning 	if (ssa->ssa_conn != NULL) {
1940f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1950f1702c5SYu Xiangning 
1960f1702c5SYu Xiangning 		sctp_recvd(ssa->ssa_conn, so->so_rcvbuf);
1970f1702c5SYu Xiangning 		(void) sctp_disconnect(ssa->ssa_conn);
1980f1702c5SYu Xiangning 		sctp_close(ssa->ssa_conn);
1990f1702c5SYu Xiangning 
2000f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
2010f1702c5SYu Xiangning 		ssa->ssa_conn = NULL;
2020f1702c5SYu Xiangning 	}
2030f1702c5SYu Xiangning 	sosctp_aid_reserve(ss, ssa->ssa_id, -1);
2040f1702c5SYu Xiangning 	ss->ss_assocs[ssa->ssa_id].ssi_assoc = NULL;
2050f1702c5SYu Xiangning 	--ss->ss_assoccnt;
2060f1702c5SYu Xiangning 	kmem_cache_free(sosctp_assoccache, ssa);
2070f1702c5SYu Xiangning }
2080f1702c5SYu Xiangning 
2090f1702c5SYu Xiangning /*
2100f1702c5SYu Xiangning  * Pack the ancillary stuff taking care of alignment issues.
2110f1702c5SYu Xiangning  * sctp_input_add_ancillary() packs the information as:
2120f1702c5SYu Xiangning  * struct cmsghdr -> ancillary data + struct cmsghdr -> ancillary data + ...
2130f1702c5SYu Xiangning  * In the next version of SCTP, sctp_input_add_ancillary() should
2140f1702c5SYu Xiangning  * pack the information taking alignment into account, then we would
2150f1702c5SYu Xiangning  * not need this routine.
2160f1702c5SYu Xiangning  */
2170f1702c5SYu Xiangning void
sosctp_pack_cmsg(const uchar_t * opt,struct nmsghdr * msg,int len)2180f1702c5SYu Xiangning sosctp_pack_cmsg(const uchar_t *opt, struct nmsghdr *msg, int len)
2190f1702c5SYu Xiangning {
2200f1702c5SYu Xiangning 	struct cmsghdr	*ocmsg;
2210f1702c5SYu Xiangning 	struct cmsghdr	*cmsg;
2220f1702c5SYu Xiangning 	int		optlen = 0;
2230f1702c5SYu Xiangning 	char		*cend;
2240f1702c5SYu Xiangning 	boolean_t	isaligned = B_TRUE;
2250f1702c5SYu Xiangning 
2260f1702c5SYu Xiangning 	ocmsg = (struct cmsghdr *)opt;
2270f1702c5SYu Xiangning 	cend = (char *)opt + len;
2280f1702c5SYu Xiangning 	/* Figure out the length incl. alignment et. al. */
2290f1702c5SYu Xiangning 	for (;;) {
2300f1702c5SYu Xiangning 		if ((char *)(ocmsg + 1) > cend ||
2310f1702c5SYu Xiangning 		    ((char *)ocmsg + ocmsg->cmsg_len) > cend) {
2320f1702c5SYu Xiangning 			break;
2330f1702c5SYu Xiangning 		}
2340f1702c5SYu Xiangning 		if (isaligned && !ISALIGNED_cmsghdr(ocmsg))
2350f1702c5SYu Xiangning 			isaligned = B_FALSE;
2360f1702c5SYu Xiangning 		optlen += ROUNDUP_cmsglen(ocmsg->cmsg_len);
2370f1702c5SYu Xiangning 		if (ocmsg->cmsg_len > 0) {
2380f1702c5SYu Xiangning 			ocmsg = (struct cmsghdr *)
2390f1702c5SYu Xiangning 			    ((uchar_t *)ocmsg + ocmsg->cmsg_len);
2400f1702c5SYu Xiangning 		} else {
2410f1702c5SYu Xiangning 			break;
2420f1702c5SYu Xiangning 		}
2430f1702c5SYu Xiangning 	}
2440f1702c5SYu Xiangning 	/* Now allocate and copy */
2450f1702c5SYu Xiangning 	msg->msg_control = kmem_zalloc(optlen, KM_SLEEP);
2460f1702c5SYu Xiangning 	msg->msg_controllen = optlen;
2470f1702c5SYu Xiangning 	if (isaligned) {
2480f1702c5SYu Xiangning 		ASSERT(optlen == len);
2490f1702c5SYu Xiangning 		bcopy(opt, msg->msg_control, len);
2500f1702c5SYu Xiangning 		return;
2510f1702c5SYu Xiangning 	}
2520f1702c5SYu Xiangning 	cmsg = (struct cmsghdr *)msg->msg_control;
2530f1702c5SYu Xiangning 	ASSERT(ISALIGNED_cmsghdr(cmsg));
2540f1702c5SYu Xiangning 	ocmsg = (struct cmsghdr *)opt;
2550f1702c5SYu Xiangning 	cend = (char *)opt + len;
2560f1702c5SYu Xiangning 	for (;;) {
2570f1702c5SYu Xiangning 		if ((char *)(ocmsg + 1) > cend ||
2580f1702c5SYu Xiangning 		    ((char *)ocmsg + ocmsg->cmsg_len) > cend) {
2590f1702c5SYu Xiangning 			break;
2600f1702c5SYu Xiangning 		}
2610f1702c5SYu Xiangning 		bcopy(ocmsg, cmsg, ocmsg->cmsg_len);
2620f1702c5SYu Xiangning 		if (ocmsg->cmsg_len > 0) {
2630f1702c5SYu Xiangning 			cmsg = (struct cmsghdr *)((uchar_t *)cmsg +
2640f1702c5SYu Xiangning 			    ROUNDUP_cmsglen(ocmsg->cmsg_len));
2650f1702c5SYu Xiangning 			ASSERT(ISALIGNED_cmsghdr(cmsg));
2660f1702c5SYu Xiangning 			ocmsg = (struct cmsghdr *)
2670f1702c5SYu Xiangning 			    ((uchar_t *)ocmsg + ocmsg->cmsg_len);
2680f1702c5SYu Xiangning 		} else {
2690f1702c5SYu Xiangning 			break;
2700f1702c5SYu Xiangning 		}
2710f1702c5SYu Xiangning 	}
2720f1702c5SYu Xiangning }
2730f1702c5SYu Xiangning 
2740f1702c5SYu Xiangning /*
2750f1702c5SYu Xiangning  * Find cmsghdr of specified type
2760f1702c5SYu Xiangning  */
2770f1702c5SYu Xiangning struct cmsghdr *
sosctp_find_cmsg(const uchar_t * control,socklen_t clen,int type)2780f1702c5SYu Xiangning sosctp_find_cmsg(const uchar_t *control, socklen_t clen, int type)
2790f1702c5SYu Xiangning {
2800f1702c5SYu Xiangning 	struct cmsghdr *cmsg;
2810f1702c5SYu Xiangning 	char *cend;
2820f1702c5SYu Xiangning 
2830f1702c5SYu Xiangning 	cmsg = (struct cmsghdr *)control;
2840f1702c5SYu Xiangning 	cend = (char *)control + clen;
2850f1702c5SYu Xiangning 
2860f1702c5SYu Xiangning 	for (;;) {
2870f1702c5SYu Xiangning 		if ((char *)(cmsg + 1) > cend ||
2880f1702c5SYu Xiangning 		    ((char *)cmsg + cmsg->cmsg_len) > cend) {
2890f1702c5SYu Xiangning 			break;
2900f1702c5SYu Xiangning 		}
2910f1702c5SYu Xiangning 		if ((cmsg->cmsg_level == IPPROTO_SCTP) &&
2920f1702c5SYu Xiangning 		    (cmsg->cmsg_type == type)) {
2930f1702c5SYu Xiangning 			return (cmsg);
2940f1702c5SYu Xiangning 		}
2950f1702c5SYu Xiangning 		if (cmsg->cmsg_len > 0) {
2960f1702c5SYu Xiangning 			cmsg = CMSG_NEXT(cmsg);
2970f1702c5SYu Xiangning 		} else {
2980f1702c5SYu Xiangning 			break;
2990f1702c5SYu Xiangning 		}
3000f1702c5SYu Xiangning 	}
3010f1702c5SYu Xiangning 	return (NULL);
3020f1702c5SYu Xiangning }
3030f1702c5SYu Xiangning 
3040f1702c5SYu Xiangning /*
3050f1702c5SYu Xiangning  * Wait until the association is connected or there is an error.
3060f1702c5SYu Xiangning  * fmode should contain any nonblocking flags.
3070f1702c5SYu Xiangning  */
3080f1702c5SYu Xiangning static int
sosctp_assoc_waitconnected(struct sctp_soassoc * ssa,int fmode)3090f1702c5SYu Xiangning sosctp_assoc_waitconnected(struct sctp_soassoc *ssa, int fmode)
3100f1702c5SYu Xiangning {
3110f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
3120f1702c5SYu Xiangning 	int error = 0;
3130f1702c5SYu Xiangning 
3140f1702c5SYu Xiangning 	ASSERT((ssa->ssa_state & (SS_ISCONNECTED|SS_ISCONNECTING)) ||
3150f1702c5SYu Xiangning 	    ssa->ssa_error != 0);
3160f1702c5SYu Xiangning 
3170f1702c5SYu Xiangning 	while ((ssa->ssa_state & (SS_ISCONNECTED|SS_ISCONNECTING)) ==
3180f1702c5SYu Xiangning 	    SS_ISCONNECTING && ssa->ssa_error == 0) {
3190f1702c5SYu Xiangning 
3200f1702c5SYu Xiangning 		dprint(3, ("waiting for SS_ISCONNECTED on %p\n", (void *)so));
3210f1702c5SYu Xiangning 		if (fmode & (FNDELAY|FNONBLOCK))
3220f1702c5SYu Xiangning 			return (EINPROGRESS);
3230f1702c5SYu Xiangning 
3240f1702c5SYu Xiangning 		if (so->so_state & SS_CLOSING)
3250f1702c5SYu Xiangning 			return (EINTR);
3260f1702c5SYu Xiangning 		if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) {
3270f1702c5SYu Xiangning 			/*
3280f1702c5SYu Xiangning 			 * Return EINTR and let the application use
3290f1702c5SYu Xiangning 			 * nonblocking techniques for detecting when
3300f1702c5SYu Xiangning 			 * the connection has been established.
3310f1702c5SYu Xiangning 			 */
3320f1702c5SYu Xiangning 			return (EINTR);
3330f1702c5SYu Xiangning 		}
3340f1702c5SYu Xiangning 		dprint(3, ("awoken on %p\n", (void *)so));
3350f1702c5SYu Xiangning 	}
3360f1702c5SYu Xiangning 	if (ssa->ssa_error != 0) {
3370f1702c5SYu Xiangning 		error = ssa->ssa_error;
3380f1702c5SYu Xiangning 		ssa->ssa_error = 0;
3390f1702c5SYu Xiangning 		dprint(3, ("sosctp_assoc_waitconnected: error %d\n", error));
3400f1702c5SYu Xiangning 		return (error);
3410f1702c5SYu Xiangning 	}
3420f1702c5SYu Xiangning 
3430f1702c5SYu Xiangning 	if (!(ssa->ssa_state & SS_ISCONNECTED)) {
3440f1702c5SYu Xiangning 		/*
3450f1702c5SYu Xiangning 		 * Another thread could have consumed so_error
3460f1702c5SYu Xiangning 		 * e.g. by calling read. - take from sowaitconnected()
3470f1702c5SYu Xiangning 		 */
3480f1702c5SYu Xiangning 		error = ECONNREFUSED;
3490f1702c5SYu Xiangning 		dprint(3, ("sosctp_waitconnected: error %d\n", error));
3500f1702c5SYu Xiangning 		return (error);
3510f1702c5SYu Xiangning 	}
3520f1702c5SYu Xiangning 	return (0);
3530f1702c5SYu Xiangning }
3540f1702c5SYu Xiangning 
3550f1702c5SYu Xiangning /*
3560f1702c5SYu Xiangning  * Called from connect(), sendmsg() when we need to create a new association.
3570f1702c5SYu Xiangning  */
3580f1702c5SYu Xiangning int
sosctp_assoc_createconn(struct sctp_sonode * ss,const struct sockaddr * name,socklen_t namelen,const uchar_t * control,socklen_t controllen,int fflag,struct cred * cr,struct sctp_soassoc ** ssap)3590f1702c5SYu Xiangning sosctp_assoc_createconn(struct sctp_sonode *ss, const struct sockaddr *name,
3600f1702c5SYu Xiangning     socklen_t namelen, const uchar_t *control, socklen_t controllen, int fflag,
3610f1702c5SYu Xiangning     struct cred *cr, struct sctp_soassoc **ssap)
3620f1702c5SYu Xiangning {
3630f1702c5SYu Xiangning 	struct sonode *so = &ss->ss_so;
3640f1702c5SYu Xiangning 	struct sctp_soassoc *ssa;
3650f1702c5SYu Xiangning 	struct sockaddr_storage laddr;
3660f1702c5SYu Xiangning 	sctp_sockbuf_limits_t sbl;
3670f1702c5SYu Xiangning 	sctp_assoc_t id;
3680f1702c5SYu Xiangning 	int error;
3690f1702c5SYu Xiangning 	struct cmsghdr *cmsg;
370bd670b35SErik Nordmark 	pid_t pid = curproc->p_pid;
3710f1702c5SYu Xiangning 
3720f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
3730f1702c5SYu Xiangning 
3740f1702c5SYu Xiangning 	/*
3750f1702c5SYu Xiangning 	 * System needs to pick local endpoint
3760f1702c5SYu Xiangning 	 */
3770f1702c5SYu Xiangning 	if (!(so->so_state & SS_ISBOUND)) {
3780f1702c5SYu Xiangning 		bzero(&laddr, sizeof (laddr));
3790f1702c5SYu Xiangning 		laddr.ss_family = so->so_family;
3800f1702c5SYu Xiangning 
3810f1702c5SYu Xiangning 		error = SOP_BIND(so, (struct sockaddr *)&laddr,
3820f1702c5SYu Xiangning 		    sizeof (laddr), _SOBIND_LOCK_HELD, cr);
3830f1702c5SYu Xiangning 		if (error) {
3840f1702c5SYu Xiangning 			*ssap = NULL;
3850f1702c5SYu Xiangning 			return (error);
3860f1702c5SYu Xiangning 		}
3870f1702c5SYu Xiangning 	}
3880f1702c5SYu Xiangning 
3890f1702c5SYu Xiangning 	/*
3900f1702c5SYu Xiangning 	 * Create a new association, and call connect on that.
3910f1702c5SYu Xiangning 	 */
3920f1702c5SYu Xiangning 	for (;;) {
3930f1702c5SYu Xiangning 		id = sosctp_aid_get(ss);
3940f1702c5SYu Xiangning 		if (id != -1) {
3950f1702c5SYu Xiangning 			break;
3960f1702c5SYu Xiangning 		}
3970f1702c5SYu Xiangning 		/*
3980f1702c5SYu Xiangning 		 * Array not large enough; increase size.
3990f1702c5SYu Xiangning 		 */
4000f1702c5SYu Xiangning 		(void) sosctp_aid_grow(ss, ss->ss_maxassoc, KM_SLEEP);
4010f1702c5SYu Xiangning 	}
4020f1702c5SYu Xiangning 	++ss->ss_assoccnt;
4030f1702c5SYu Xiangning 	sosctp_aid_reserve(ss, id, 1);
4040f1702c5SYu Xiangning 
4050f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4060f1702c5SYu Xiangning 
4070f1702c5SYu Xiangning 	ssa = sosctp_assoc_create(ss, KM_SLEEP);
4080f1702c5SYu Xiangning 	ssa->ssa_wroff = ss->ss_wroff;
4090f1702c5SYu Xiangning 	ssa->ssa_wrsize = ss->ss_wrsize;
4100f1702c5SYu Xiangning 	ssa->ssa_conn = sctp_create(ssa, (struct sctp_s *)so->so_proto_handle,
411bd670b35SErik Nordmark 	    so->so_family, so->so_type, SCTP_CAN_BLOCK, &sosctp_assoc_upcalls,
412bd670b35SErik Nordmark 	    &sbl, cr);
4130f1702c5SYu Xiangning 
4140f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4150f1702c5SYu Xiangning 	ss->ss_assocs[id].ssi_assoc = ssa;
4160f1702c5SYu Xiangning 	ssa->ssa_id = id;
4170f1702c5SYu Xiangning 	if (ssa->ssa_conn == NULL) {
4180f1702c5SYu Xiangning 		ASSERT(ssa->ssa_refcnt == 1);
4190f1702c5SYu Xiangning 		sosctp_assoc_free(ss, ssa);
4200f1702c5SYu Xiangning 		*ssap = NULL;
4210f1702c5SYu Xiangning 		return (ENOMEM);
4220f1702c5SYu Xiangning 	}
4230f1702c5SYu Xiangning 	ssa->ssa_state |= SS_ISBOUND;
4240f1702c5SYu Xiangning 
4250f1702c5SYu Xiangning 	sosctp_assoc_isconnecting(ssa);
4260f1702c5SYu Xiangning 	SSA_REFHOLD(ssa);
4270f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
4280f1702c5SYu Xiangning 
4290f1702c5SYu Xiangning 	/*
4300f1702c5SYu Xiangning 	 * Can specify special init params
4310f1702c5SYu Xiangning 	 */
4320f1702c5SYu Xiangning 	cmsg = sosctp_find_cmsg(control, controllen, SCTP_INIT);
4330f1702c5SYu Xiangning 	if (cmsg != NULL) {
4340f1702c5SYu Xiangning 		error = sctp_set_opt(ssa->ssa_conn, IPPROTO_SCTP, SCTP_INITMSG,
4350f1702c5SYu Xiangning 		    cmsg + 1, cmsg->cmsg_len - sizeof (*cmsg));
4360f1702c5SYu Xiangning 		if (error != 0)
4370f1702c5SYu Xiangning 			goto ret_err;
4380f1702c5SYu Xiangning 	}
4390f1702c5SYu Xiangning 
440bd670b35SErik Nordmark 	if ((error = sctp_connect(ssa->ssa_conn, name, namelen, cr, pid)) != 0)
4410f1702c5SYu Xiangning 		goto ret_err;
4420f1702c5SYu Xiangning 
4430f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4440f1702c5SYu Xiangning 	/*
4450f1702c5SYu Xiangning 	 * Allow other threads to access the socket
4460f1702c5SYu Xiangning 	 */
4470f1702c5SYu Xiangning 	error = sosctp_assoc_waitconnected(ssa, fflag);
4480f1702c5SYu Xiangning 
4490f1702c5SYu Xiangning 	switch (error) {
4500f1702c5SYu Xiangning 	case 0:
4510f1702c5SYu Xiangning 	case EINPROGRESS:
4520f1702c5SYu Xiangning 	case EALREADY:
4530f1702c5SYu Xiangning 	case EINTR:
4540f1702c5SYu Xiangning 		/* Non-fatal errors */
4550f1702c5SYu Xiangning 		break;
4560f1702c5SYu Xiangning 	default:
4570f1702c5SYu Xiangning 		/*
4580f1702c5SYu Xiangning 		 * Fatal errors.  It means that sctp_assoc_disconnected()
4590f1702c5SYu Xiangning 		 * must have been called.  So we only need to do a
4600f1702c5SYu Xiangning 		 * SSA_REFRELE() here to release our hold done above.
4610f1702c5SYu Xiangning 		 */
4620f1702c5SYu Xiangning 		ASSERT(ssa->ssa_state & (SS_CANTSENDMORE | SS_CANTRCVMORE));
4630f1702c5SYu Xiangning 		SSA_REFRELE(ss, ssa);
4640f1702c5SYu Xiangning 		ssa = NULL;
4650f1702c5SYu Xiangning 		break;
4660f1702c5SYu Xiangning 	}
4670f1702c5SYu Xiangning 
4680f1702c5SYu Xiangning 	*ssap = ssa;
4690f1702c5SYu Xiangning 	return (error);
4700f1702c5SYu Xiangning 
4710f1702c5SYu Xiangning ret_err:
4720f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
4730f1702c5SYu Xiangning 	/*
4740f1702c5SYu Xiangning 	 * There should not be any upcall done by SCTP.  So normally the
4750f1702c5SYu Xiangning 	 * ssa_refcnt should be 2.  And we can call sosctp_assoc_free()
4760f1702c5SYu Xiangning 	 * directly.  But since the ssa is inserted to the ss_soassocs
4770f1702c5SYu Xiangning 	 * array above, some thread can actually put a hold on it.  In
4780f1702c5SYu Xiangning 	 * this special case, we "manually" decrease the ssa_refcnt by 2.
4790f1702c5SYu Xiangning 	 */
4800f1702c5SYu Xiangning 	if (ssa->ssa_refcnt > 2)
4810f1702c5SYu Xiangning 		ssa->ssa_refcnt -= 2;
4820f1702c5SYu Xiangning 	else
4830f1702c5SYu Xiangning 		sosctp_assoc_free(ss, ssa);
4840f1702c5SYu Xiangning 	*ssap = NULL;
4850f1702c5SYu Xiangning 	return (error);
4860f1702c5SYu Xiangning }
4870f1702c5SYu Xiangning 
4880f1702c5SYu Xiangning /*
4890f1702c5SYu Xiangning  * Inherit socket properties
4900f1702c5SYu Xiangning  */
4910f1702c5SYu Xiangning void
sosctp_so_inherit(struct sctp_sonode * lss,struct sctp_sonode * nss)4920f1702c5SYu Xiangning sosctp_so_inherit(struct sctp_sonode *lss, struct sctp_sonode *nss)
4930f1702c5SYu Xiangning {
4940f1702c5SYu Xiangning 	struct sonode *nso = &nss->ss_so;
4950f1702c5SYu Xiangning 	struct sonode *lso = &lss->ss_so;
4960f1702c5SYu Xiangning 
4970f1702c5SYu Xiangning 	nso->so_options = lso->so_options & (SO_DEBUG|SO_REUSEADDR|
4980f1702c5SYu Xiangning 	    SO_KEEPALIVE|SO_DONTROUTE|SO_BROADCAST|SO_USELOOPBACK|
4990f1702c5SYu Xiangning 	    SO_OOBINLINE|SO_DGRAM_ERRIND|SO_LINGER);
5000f1702c5SYu Xiangning 	nso->so_sndbuf = lso->so_sndbuf;
5010f1702c5SYu Xiangning 	nso->so_rcvbuf = lso->so_rcvbuf;
5020f1702c5SYu Xiangning 	nso->so_pgrp = lso->so_pgrp;
5030f1702c5SYu Xiangning 
5040f1702c5SYu Xiangning 	nso->so_rcvlowat = lso->so_rcvlowat;
5050f1702c5SYu Xiangning 	nso->so_sndlowat = lso->so_sndlowat;
5060f1702c5SYu Xiangning }
5070f1702c5SYu Xiangning 
5080f1702c5SYu Xiangning /*
5090f1702c5SYu Xiangning  * Branching association to it's own socket. Inherit properties from
510e4b767e8SAnders Persson  * the parent, and move data for the association to the new socket.
5110f1702c5SYu Xiangning  */
5120f1702c5SYu Xiangning void
sosctp_assoc_move(struct sctp_sonode * ss,struct sctp_sonode * nss,struct sctp_soassoc * ssa)5130f1702c5SYu Xiangning sosctp_assoc_move(struct sctp_sonode *ss, struct sctp_sonode *nss,
5140f1702c5SYu Xiangning     struct sctp_soassoc *ssa)
5150f1702c5SYu Xiangning {
5160f1702c5SYu Xiangning 	mblk_t *mp, **nmp, *last_mp;
5170f1702c5SYu Xiangning 	struct sctp_soassoc *tmp;
518*a215d4ebSKacheong Poon 	struct sonode *nso, *sso;
5190f1702c5SYu Xiangning 
5200f1702c5SYu Xiangning 	sosctp_so_inherit(ss, nss);
5210f1702c5SYu Xiangning 
522*a215d4ebSKacheong Poon 	sso = &ss->ss_so;
523*a215d4ebSKacheong Poon 	nso = &nss->ss_so;
524*a215d4ebSKacheong Poon 
525*a215d4ebSKacheong Poon 	nso->so_state |= (sso->so_state & (SS_NDELAY|SS_NONBLOCK));
526*a215d4ebSKacheong Poon 	nso->so_state |=
5270f1702c5SYu Xiangning 	    (ssa->ssa_state & (SS_ISCONNECTED|SS_ISCONNECTING|
5280f1702c5SYu Xiangning 	    SS_ISDISCONNECTING|SS_CANTSENDMORE|SS_CANTRCVMORE|SS_ISBOUND));
529*a215d4ebSKacheong Poon 	nso->so_error = ssa->ssa_error;
530*a215d4ebSKacheong Poon 	nso->so_snd_qfull = ssa->ssa_snd_qfull;
531*a215d4ebSKacheong Poon 	nso->so_proto_props.sopp_wroff = ssa->ssa_wroff;
532*a215d4ebSKacheong Poon 	nso->so_proto_props.sopp_maxblk = ssa->ssa_wrsize;
533*a215d4ebSKacheong Poon 	nso->so_rcv_queued = ssa->ssa_rcv_queued;
534*a215d4ebSKacheong Poon 	nso->so_flowctrld = ssa->ssa_flowctrld;
535*a215d4ebSKacheong Poon 	nso->so_proto_handle = (sock_lower_handle_t)ssa->ssa_conn;
536e4b767e8SAnders Persson 	/* The peeled off socket is connection oriented */
537*a215d4ebSKacheong Poon 	nso->so_mode |= SM_CONNREQUIRED;
538e4b767e8SAnders Persson 
539e4b767e8SAnders Persson 	/* Consolidate all data on a single rcv list */
540*a215d4ebSKacheong Poon 	if (sso->so_rcv_head != NULL) {
541*a215d4ebSKacheong Poon 		so_process_new_message(&ss->ss_so, sso->so_rcv_head,
542*a215d4ebSKacheong Poon 		    sso->so_rcv_last_head);
543*a215d4ebSKacheong Poon 		sso->so_rcv_head = NULL;
544*a215d4ebSKacheong Poon 		sso->so_rcv_last_head = NULL;
545e4b767e8SAnders Persson 	}
5460f1702c5SYu Xiangning 
547*a215d4ebSKacheong Poon 	if (nso->so_rcv_queued > 0) {
548*a215d4ebSKacheong Poon 		nmp = &sso->so_rcv_q_head;
5490f1702c5SYu Xiangning 		last_mp = NULL;
5500f1702c5SYu Xiangning 		while ((mp = *nmp) != NULL) {
5510f1702c5SYu Xiangning 			tmp = *(struct sctp_soassoc **)DB_BASE(mp);
552e4b767e8SAnders Persson #ifdef DEBUG
553e4b767e8SAnders Persson 			{
554e4b767e8SAnders Persson 				/*
555e4b767e8SAnders Persson 				 * Verify that b_prev points to the last
556e4b767e8SAnders Persson 				 * mblk in the b_cont chain (as mandated
557e4b767e8SAnders Persson 				 * by so_dequeue_msg().)
558e4b767e8SAnders Persson 				 */
559e4b767e8SAnders Persson 				mblk_t *mp1 = mp;
560e4b767e8SAnders Persson 				while (mp1->b_cont != NULL)
561e4b767e8SAnders Persson 					mp1 = mp1->b_cont;
562e4b767e8SAnders Persson 				VERIFY(mp->b_prev == mp1);
563e4b767e8SAnders Persson 			}
564e4b767e8SAnders Persson #endif /* DEBUG */
5650f1702c5SYu Xiangning 			if (tmp == ssa) {
5660f1702c5SYu Xiangning 				*nmp = mp->b_next;
5670f1702c5SYu Xiangning 				ASSERT(DB_TYPE(mp) != M_DATA);
568*a215d4ebSKacheong Poon 				if (nso->so_rcv_q_last_head == NULL) {
569*a215d4ebSKacheong Poon 					nso->so_rcv_q_head = mp;
5700f1702c5SYu Xiangning 				} else {
571*a215d4ebSKacheong Poon 					nso->so_rcv_q_last_head->b_next = mp;
5720f1702c5SYu Xiangning 				}
573*a215d4ebSKacheong Poon 				nso->so_rcv_q_last_head = mp;
5740f1702c5SYu Xiangning 				mp->b_next = NULL;
5750f1702c5SYu Xiangning 			} else {
5760f1702c5SYu Xiangning 				nmp = &mp->b_next;
5770f1702c5SYu Xiangning 				last_mp = mp;
5780f1702c5SYu Xiangning 			}
5790f1702c5SYu Xiangning 		}
580e4b767e8SAnders Persson 
581*a215d4ebSKacheong Poon 		sso->so_rcv_q_last_head = last_mp;
5820f1702c5SYu Xiangning 	}
5830f1702c5SYu Xiangning }
5840f1702c5SYu Xiangning 
5850f1702c5SYu Xiangning void
sosctp_assoc_isconnecting(struct sctp_soassoc * ssa)5860f1702c5SYu Xiangning sosctp_assoc_isconnecting(struct sctp_soassoc *ssa)
5870f1702c5SYu Xiangning {
5880f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
5890f1702c5SYu Xiangning 
5900f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
5910f1702c5SYu Xiangning 
5920f1702c5SYu Xiangning 	ssa->ssa_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
5930f1702c5SYu Xiangning 	ssa->ssa_state |= SS_ISCONNECTING;
5940f1702c5SYu Xiangning 	cv_broadcast(&so->so_state_cv);
5950f1702c5SYu Xiangning }
5960f1702c5SYu Xiangning 
5970f1702c5SYu Xiangning void
sosctp_assoc_isconnected(struct sctp_soassoc * ssa)5980f1702c5SYu Xiangning sosctp_assoc_isconnected(struct sctp_soassoc *ssa)
5990f1702c5SYu Xiangning {
6000f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
6010f1702c5SYu Xiangning 
6020f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
6030f1702c5SYu Xiangning 
6040f1702c5SYu Xiangning 	ssa->ssa_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
6050f1702c5SYu Xiangning 	ssa->ssa_state |= SS_ISCONNECTED;
6060f1702c5SYu Xiangning 	cv_broadcast(&so->so_state_cv);
6070f1702c5SYu Xiangning }
6080f1702c5SYu Xiangning 
6090f1702c5SYu Xiangning void
sosctp_assoc_isdisconnecting(struct sctp_soassoc * ssa)6100f1702c5SYu Xiangning sosctp_assoc_isdisconnecting(struct sctp_soassoc *ssa)
6110f1702c5SYu Xiangning {
6120f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
6130f1702c5SYu Xiangning 
6140f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
6150f1702c5SYu Xiangning 
6160f1702c5SYu Xiangning 	ssa->ssa_state &= ~SS_ISCONNECTING;
6170f1702c5SYu Xiangning 	ssa->ssa_state |= SS_CANTSENDMORE;
6180f1702c5SYu Xiangning 	cv_broadcast(&so->so_state_cv);
6190f1702c5SYu Xiangning }
6200f1702c5SYu Xiangning 
6210f1702c5SYu Xiangning void
sosctp_assoc_isdisconnected(struct sctp_soassoc * ssa,int error)6220f1702c5SYu Xiangning sosctp_assoc_isdisconnected(struct sctp_soassoc *ssa, int error)
6230f1702c5SYu Xiangning {
6240f1702c5SYu Xiangning 	struct sonode *so = &ssa->ssa_sonode->ss_so;
6250f1702c5SYu Xiangning 
6260f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
6270f1702c5SYu Xiangning 
6280f1702c5SYu Xiangning 	ssa->ssa_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
6290f1702c5SYu Xiangning 	ssa->ssa_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
6300f1702c5SYu Xiangning 	if (error != 0)
6310f1702c5SYu Xiangning 		ssa->ssa_error = (ushort_t)error;
6320f1702c5SYu Xiangning 	cv_broadcast(&so->so_state_cv);
6330f1702c5SYu Xiangning }
634