17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2177c67f2fSkcpoon 
227c478bd9Sstevel@tonic-gate /*
23481845d8SGeorge Shepherd  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/stream.h>
297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
317c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
327c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
337c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
347c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
357c478bd9Sstevel@tonic-gate #include <sys/socket.h>
3645916cd2Sjpk #include <sys/tsol/tndb.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <netinet/in.h>
397c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <inet/common.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip.h>
437c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
447c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
457c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
487c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Common accept code.  Called by sctp_conn_request.
527c478bd9Sstevel@tonic-gate  * cr_pkt is the INIT / INIT ACK packet.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate static int
557c478bd9Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt,
567c478bd9Sstevel@tonic-gate     uint_t ip_hdr_len, sctp_init_chunk_t *iack)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	sctp_hdr_t		*sctph;
607c478bd9Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ich;
617c478bd9Sstevel@tonic-gate 	sctp_init_chunk_t	*init;
627c478bd9Sstevel@tonic-gate 	int			err;
637c478bd9Sstevel@tonic-gate 	uint_t			sctp_options;
64d7ab25acSkp 	conn_t			*aconnp;
6545916cd2Sjpk 	conn_t			*lconnp;
66*5dd46ab5SKacheong Poon 	sctp_stack_t		*sctps = listener->sctp_sctps;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
697c478bd9Sstevel@tonic-gate 	ASSERT(OK_32PTR(sctph));
707c478bd9Sstevel@tonic-gate 
71bd670b35SErik Nordmark 	aconnp = acceptor->sctp_connp;
72bd670b35SErik Nordmark 	lconnp = listener->sctp_connp;
73bd670b35SErik Nordmark 	aconnp->conn_lport = lconnp->conn_lport;
74bd670b35SErik Nordmark 	aconnp->conn_fport = sctph->sh_sport;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	ich = (sctp_chunk_hdr_t *)(iack + 1);
777c478bd9Sstevel@tonic-gate 	init = (sctp_init_chunk_t *)(ich + 1);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/* acceptor isn't in any fanouts yet, so don't need to hold locks */
807c478bd9Sstevel@tonic-gate 	ASSERT(acceptor->sctp_faddrs == NULL);
817c478bd9Sstevel@tonic-gate 	err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
827c478bd9Sstevel@tonic-gate 	    &sctp_options);
837c478bd9Sstevel@tonic-gate 	if (err != 0)
847c478bd9Sstevel@tonic-gate 		return (err);
857c478bd9Sstevel@tonic-gate 
8677c67f2fSkcpoon 	if ((err = sctp_set_hdraddrs(acceptor)) != 0)
8745916cd2Sjpk 		return (err);
8845916cd2Sjpk 
89bd670b35SErik Nordmark 	if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0)
90bd670b35SErik Nordmark 		return (err);
91bd670b35SErik Nordmark 
927c478bd9Sstevel@tonic-gate 	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
93f4b3ec61Sdh 	    listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) {
947c478bd9Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_TRUE;
957c478bd9Sstevel@tonic-gate 	} else {
967c478bd9Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_FALSE;
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	/* Get  initial TSNs */
1007c478bd9Sstevel@tonic-gate 	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
1017c478bd9Sstevel@tonic-gate 	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
1027c478bd9Sstevel@tonic-gate 	    acceptor->sctp_ltsn - 1;
1037c478bd9Sstevel@tonic-gate 	acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd;
1047c478bd9Sstevel@tonic-gate 	/* Serial numbers are initialized to the same value as the TSNs */
1057c478bd9Sstevel@tonic-gate 	acceptor->sctp_lcsn = acceptor->sctp_ltsn;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	if (!sctp_initialize_params(acceptor, init, iack))
1087c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/*
1117c478bd9Sstevel@tonic-gate 	 * Copy sctp_secret from the listener in case we need to validate
1127c478bd9Sstevel@tonic-gate 	 * a possibly delayed cookie.
1137c478bd9Sstevel@tonic-gate 	 */
1147c478bd9Sstevel@tonic-gate 	bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN);
1157c478bd9Sstevel@tonic-gate 	bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret,
1167c478bd9Sstevel@tonic-gate 	    SCTP_SECRET_LEN);
117d3d50737SRafael Vanoni 	acceptor->sctp_last_secret_update = ddi_get_lbolt64();
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/*
1207c478bd9Sstevel@tonic-gate 	 * After acceptor is inserted in the hash list, it can be found.
1217c478bd9Sstevel@tonic-gate 	 * So we need to lock it here.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	RUN_SCTP(acceptor);
1247c478bd9Sstevel@tonic-gate 
125f4b3ec61Sdh 	sctp_conn_hash_insert(&sctps->sctps_conn_fanout[
126bd670b35SErik Nordmark 	    SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0);
127f4b3ec61Sdh 	sctp_bind_hash_insert(&sctps->sctps_bind_fanout[
128bd670b35SErik Nordmark 	    SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0);
1297c478bd9Sstevel@tonic-gate 
130*5dd46ab5SKacheong Poon 	SCTP_ASSOC_EST(sctps, acceptor);
131*5dd46ab5SKacheong Poon 
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * listener->sctp_rwnd should be the default window size or a
1347c478bd9Sstevel@tonic-gate 	 * window size changed via SO_RCVBUF option.
1357c478bd9Sstevel@tonic-gate 	 */
1361d8c4025Svi 	acceptor->sctp_rwnd = listener->sctp_rwnd;
1371d8c4025Svi 	acceptor->sctp_irwnd = acceptor->sctp_rwnd;
1387d546a59Svi 	acceptor->sctp_pd_point = acceptor->sctp_rwnd;
1390f1702c5SYu Xiangning 	acceptor->sctp_upcalls = listener->sctp_upcalls;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	return (0);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */
1457c478bd9Sstevel@tonic-gate sctp_t *
1467c478bd9Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len,
147bd670b35SErik Nordmark     sctp_init_chunk_t *iack, ip_recv_attr_t *ira)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	sctp_t	*eager;
1507c478bd9Sstevel@tonic-gate 	ip6_t	*ip6h;
1517c478bd9Sstevel@tonic-gate 	int	err;
1527c478bd9Sstevel@tonic-gate 	conn_t	*connp, *econnp;
153f4b3ec61Sdh 	sctp_stack_t	*sctps;
1540f1702c5SYu Xiangning 	struct sock_proto_props sopp;
155de8c4a14SErik Nordmark 	cred_t		*cr;
156de8c4a14SErik Nordmark 	pid_t		cpid;
157bd670b35SErik Nordmark 	in6_addr_t	faddr, laddr;
158bd670b35SErik Nordmark 	ip_xmit_attr_t	*ixa;
159*5dd46ab5SKacheong Poon 	sctp_listen_cnt_t *slc = sctp->sctp_listen_cnt;
160*5dd46ab5SKacheong Poon 	boolean_t	slc_set = B_FALSE;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * No need to check for duplicate as this is the listener
1647c478bd9Sstevel@tonic-gate 	 * and we are holding the lock.  This means that no new
1657c478bd9Sstevel@tonic-gate 	 * connection can be created out of it.  And since the
1667c478bd9Sstevel@tonic-gate 	 * fanout already done cannot find a match, it means that
1677c478bd9Sstevel@tonic-gate 	 * there is no duplicate.
1687c478bd9Sstevel@tonic-gate 	 */
1697c478bd9Sstevel@tonic-gate 	ASSERT(OK_32PTR(mp->b_rptr));
1707c478bd9Sstevel@tonic-gate 
171*5dd46ab5SKacheong Poon 	connp = sctp->sctp_connp;
172*5dd46ab5SKacheong Poon 	sctps = sctp->sctp_sctps;
173*5dd46ab5SKacheong Poon 
174*5dd46ab5SKacheong Poon 	/*
175*5dd46ab5SKacheong Poon 	 * Enforce the limit set on the number of connections per listener.
176*5dd46ab5SKacheong Poon 	 * Note that tlc_cnt starts with 1.  So need to add 1 to tlc_max
177*5dd46ab5SKacheong Poon 	 * for comparison.
178*5dd46ab5SKacheong Poon 	 */
179*5dd46ab5SKacheong Poon 	if (slc != NULL) {
180*5dd46ab5SKacheong Poon 		int64_t now;
181*5dd46ab5SKacheong Poon 
182*5dd46ab5SKacheong Poon 		if (atomic_add_32_nv(&slc->slc_cnt, 1) > slc->slc_max + 1) {
183*5dd46ab5SKacheong Poon 			now = ddi_get_lbolt64();
184*5dd46ab5SKacheong Poon 			atomic_add_32(&slc->slc_cnt, -1);
185*5dd46ab5SKacheong Poon 			SCTP_KSTAT(sctps, sctp_listen_cnt_drop);
186*5dd46ab5SKacheong Poon 			slc->slc_drop++;
187*5dd46ab5SKacheong Poon 			if (now - slc->slc_report_time >
188*5dd46ab5SKacheong Poon 			    MSEC_TO_TICK(SCTP_SLC_REPORT_INTERVAL)) {
189*5dd46ab5SKacheong Poon 				zcmn_err(connp->conn_zoneid, CE_WARN,
190*5dd46ab5SKacheong Poon 				    "SCTP listener (port %d) association max "
191*5dd46ab5SKacheong Poon 				    "(%u) reached: %u attempts dropped total\n",
192*5dd46ab5SKacheong Poon 				    ntohs(connp->conn_lport),
193*5dd46ab5SKacheong Poon 				    slc->slc_max, slc->slc_drop);
194*5dd46ab5SKacheong Poon 				slc->slc_report_time = now;
195*5dd46ab5SKacheong Poon 			}
196*5dd46ab5SKacheong Poon 			return (NULL);
197*5dd46ab5SKacheong Poon 		}
198*5dd46ab5SKacheong Poon 		slc_set = B_TRUE;
199*5dd46ab5SKacheong Poon 	}
200*5dd46ab5SKacheong Poon 
2017c478bd9Sstevel@tonic-gate 	if ((eager = sctp_create_eager(sctp)) == NULL) {
202*5dd46ab5SKacheong Poon 		if (slc_set)
203*5dd46ab5SKacheong Poon 			atomic_add_32(&slc->slc_cnt, -1);
2047c478bd9Sstevel@tonic-gate 		return (NULL);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 	econnp = eager->sctp_connp;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (connp->conn_policy != NULL) {
209bd670b35SErik Nordmark 		/* Inherit the policy from the listener; use actions from ira */
210bd670b35SErik Nordmark 		if (!ip_ipsec_policy_inherit(econnp, connp, ira)) {
2117c478bd9Sstevel@tonic-gate 			sctp_close_eager(eager);
212*5dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2137c478bd9Sstevel@tonic-gate 			return (NULL);
2147c478bd9Sstevel@tonic-gate 		}
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
217bd670b35SErik Nordmark 	ip6h = (ip6_t *)mp->b_rptr;
218bd670b35SErik Nordmark 	if (ira->ira_flags & IXAF_IS_IPV4) {
219bd670b35SErik Nordmark 		ipha_t	*ipha;
220bd670b35SErik Nordmark 
221bd670b35SErik Nordmark 		ipha = (ipha_t *)ip6h;
222bd670b35SErik Nordmark 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr);
223bd670b35SErik Nordmark 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr);
224bd670b35SErik Nordmark 	} else {
225bd670b35SErik Nordmark 		laddr = ip6h->ip6_dst;
226bd670b35SErik Nordmark 		faddr = ip6h->ip6_src;
227bd670b35SErik Nordmark 	}
228bd670b35SErik Nordmark 
229bd670b35SErik Nordmark 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
2307c478bd9Sstevel@tonic-gate 		/*
2317c478bd9Sstevel@tonic-gate 		 * XXX need to fix the cached policy issue here.
232bd670b35SErik Nordmark 		 * We temporarily set the conn_laddr/conn_faddr here so
2337c478bd9Sstevel@tonic-gate 		 * that IPsec can use it for the latched policy
2347c478bd9Sstevel@tonic-gate 		 * selector.  This is obvioursly wrong as SCTP can
2357c478bd9Sstevel@tonic-gate 		 * use different addresses...
2367c478bd9Sstevel@tonic-gate 		 */
237bd670b35SErik Nordmark 		econnp->conn_laddr_v6 = laddr;
238bd670b35SErik Nordmark 		econnp->conn_faddr_v6 = faddr;
239bd670b35SErik Nordmark 		econnp->conn_saddr_v6 = laddr;
2407c478bd9Sstevel@tonic-gate 	}
241bd670b35SErik Nordmark 	if (ipsec_conn_cache_policy(econnp,
242bd670b35SErik Nordmark 	    (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) {
2437c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
244*5dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2457c478bd9Sstevel@tonic-gate 		return (NULL);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
248de8c4a14SErik Nordmark 	/* Save for getpeerucred */
249bd670b35SErik Nordmark 	cr = ira->ira_cred;
250bd670b35SErik Nordmark 	cpid = ira->ira_cpid;
251bd670b35SErik Nordmark 
252bd670b35SErik Nordmark 	if (is_system_labeled()) {
253bd670b35SErik Nordmark 		ip_xmit_attr_t *ixa = econnp->conn_ixa;
254bd670b35SErik Nordmark 
255bd670b35SErik Nordmark 		ASSERT(ira->ira_tsl != NULL);
256bd670b35SErik Nordmark 
257bd670b35SErik Nordmark 		/* Discard any old label */
258bd670b35SErik Nordmark 		if (ixa->ixa_free_flags & IXA_FREE_TSL) {
259bd670b35SErik Nordmark 			ASSERT(ixa->ixa_tsl != NULL);
260bd670b35SErik Nordmark 			label_rele(ixa->ixa_tsl);
261bd670b35SErik Nordmark 			ixa->ixa_free_flags &= ~IXA_FREE_TSL;
262bd670b35SErik Nordmark 			ixa->ixa_tsl = NULL;
263bd670b35SErik Nordmark 		}
264bd670b35SErik Nordmark 
265bd670b35SErik Nordmark 		if ((connp->conn_mlp_type != mlptSingle ||
266bd670b35SErik Nordmark 		    connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
267bd670b35SErik Nordmark 		    ira->ira_tsl != NULL) {
268bd670b35SErik Nordmark 			/*
269bd670b35SErik Nordmark 			 * If this is an MLP connection or a MAC-Exempt
270bd670b35SErik Nordmark 			 * connection with an unlabeled node, packets are to be
271bd670b35SErik Nordmark 			 * exchanged using the security label of the received
272bd670b35SErik Nordmark 			 * Cookie packet instead of the server application's
273bd670b35SErik Nordmark 			 * label.
274bd670b35SErik Nordmark 			 * tsol_check_dest called from ip_set_destination
275bd670b35SErik Nordmark 			 * might later update TSF_UNLABELED by replacing
276bd670b35SErik Nordmark 			 * ixa_tsl with a new label.
277bd670b35SErik Nordmark 			 */
278bd670b35SErik Nordmark 			label_hold(ira->ira_tsl);
279bd670b35SErik Nordmark 			ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl);
280bd670b35SErik Nordmark 		} else {
281bd670b35SErik Nordmark 			ixa->ixa_tsl = crgetlabel(econnp->conn_cred);
282bd670b35SErik Nordmark 		}
283bd670b35SErik Nordmark 	}
284de8c4a14SErik Nordmark 
2857c478bd9Sstevel@tonic-gate 	err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack);
286bd670b35SErik Nordmark 	if (err != 0) {
2877c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
288*5dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2897c478bd9Sstevel@tonic-gate 		return (NULL);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
292bd670b35SErik Nordmark 	ASSERT(eager->sctp_current->ixa != NULL);
293bd670b35SErik Nordmark 
294bd670b35SErik Nordmark 	ixa = eager->sctp_current->ixa;
295bd670b35SErik Nordmark 	if (!(ira->ira_flags & IXAF_IS_IPV4)) {
296bd670b35SErik Nordmark 		ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4));
297bd670b35SErik Nordmark 
298bd670b35SErik Nordmark 		if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ||
299bd670b35SErik Nordmark 		    IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) {
300bd670b35SErik Nordmark 			eager->sctp_linklocal = 1;
301bd670b35SErik Nordmark 
302bd670b35SErik Nordmark 			ixa->ixa_flags |= IXAF_SCOPEID_SET;
303bd670b35SErik Nordmark 			ixa->ixa_scopeid = ifindex;
304bd670b35SErik Nordmark 			econnp->conn_incoming_ifindex = ifindex;
305bd670b35SErik Nordmark 		}
306bd670b35SErik Nordmark 	}
307bd670b35SErik Nordmark 
3081d8c4025Svi 	/*
3091d8c4025Svi 	 * On a clustered note send this notification to the clustering
3101d8c4025Svi 	 * subsystem.
3111d8c4025Svi 	 */
3121d8c4025Svi 	if (cl_sctp_connect != NULL) {
3131d8c4025Svi 		uchar_t	*slist;
3141d8c4025Svi 		uchar_t	*flist;
3151d8c4025Svi 		size_t	fsize;
3161d8c4025Svi 		size_t	ssize;
3171d8c4025Svi 
3181d8c4025Svi 		fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs;
3191d8c4025Svi 		ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs;
3201d8c4025Svi 		slist = kmem_alloc(ssize, KM_NOSLEEP);
3211d8c4025Svi 		flist = kmem_alloc(fsize, KM_NOSLEEP);
3221d8c4025Svi 		if (slist == NULL || flist == NULL) {
3231d8c4025Svi 			if (slist != NULL)
3241d8c4025Svi 				kmem_free(slist, ssize);
3251d8c4025Svi 			if (flist != NULL)
3261d8c4025Svi 				kmem_free(flist, fsize);
3271d8c4025Svi 			sctp_close_eager(eager);
328*5dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpListenDrop);
329f4b3ec61Sdh 			SCTP_KSTAT(sctps, sctp_cl_connect);
3301d8c4025Svi 			return (NULL);
3311d8c4025Svi 		}
3321d8c4025Svi 		/* The clustering module frees these list */
3331d8c4025Svi 		sctp_get_saddr_list(eager, slist, ssize);
3341d8c4025Svi 		sctp_get_faddr_list(eager, flist, fsize);
335bd670b35SErik Nordmark 		(*cl_sctp_connect)(econnp->conn_family, slist,
336bd670b35SErik Nordmark 		    eager->sctp_nsaddrs, econnp->conn_lport, flist,
337bd670b35SErik Nordmark 		    eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE,
3381d8c4025Svi 		    (cl_sctp_handle_t)eager);
3391d8c4025Svi 	}
3401d8c4025Svi 
3417c478bd9Sstevel@tonic-gate 	/* Connection established, so send up the conn_ind */
3427c478bd9Sstevel@tonic-gate 	if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd,
343de8c4a14SErik Nordmark 	    (sock_lower_handle_t)eager, NULL, cr, cpid,
3440f1702c5SYu Xiangning 	    &eager->sctp_upcalls)) == NULL) {
3457c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
346*5dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
3477c478bd9Sstevel@tonic-gate 		return (NULL);
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 	ASSERT(SCTP_IS_DETACHED(eager));
3507c478bd9Sstevel@tonic-gate 	eager->sctp_detached = B_FALSE;
3510f1702c5SYu Xiangning 	bzero(&sopp, sizeof (sopp));
3520f1702c5SYu Xiangning 	sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF;
3530f1702c5SYu Xiangning 	sopp.sopp_maxblk = strmsgsz;
354bd670b35SErik Nordmark 	if (econnp->conn_family == AF_INET) {
3550f1702c5SYu Xiangning 		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
3560f1702c5SYu Xiangning 		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len;
3577c478bd9Sstevel@tonic-gate 	} else {
3580f1702c5SYu Xiangning 		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
3590f1702c5SYu Xiangning 		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len;
3607c478bd9Sstevel@tonic-gate 	}
3610f1702c5SYu Xiangning 	eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp);
3627c478bd9Sstevel@tonic-gate 	return (eager);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate  * Connect to a peer - this function inserts the sctp in the
3677c478bd9Sstevel@tonic-gate  * bind and conn fanouts, sends the INIT, and replies to the client
3687c478bd9Sstevel@tonic-gate  * with an OK ack.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate int
371bd670b35SErik Nordmark sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen,
372bd670b35SErik Nordmark     cred_t *cr, pid_t pid)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	sin_t		*sin;
3757c478bd9Sstevel@tonic-gate 	sin6_t		*sin6;
3767c478bd9Sstevel@tonic-gate 	in6_addr_t	dstaddr;
3777c478bd9Sstevel@tonic-gate 	in_port_t	dstport;
3787c478bd9Sstevel@tonic-gate 	mblk_t		*initmp;
3797c478bd9Sstevel@tonic-gate 	sctp_tf_t	*tbf;
3807c478bd9Sstevel@tonic-gate 	sctp_t		*lsctp;
3817c478bd9Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
3827c478bd9Sstevel@tonic-gate 	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
38345916cd2Sjpk 	int		err;
3847c478bd9Sstevel@tonic-gate 	sctp_faddr_t	*cur_fp;
385f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
386bd670b35SErik Nordmark 	conn_t		*connp = sctp->sctp_connp;
387bd670b35SErik Nordmark 	uint_t		scope_id = 0;
388bd670b35SErik Nordmark 	ip_xmit_attr_t	*ixa;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/*
3917c478bd9Sstevel@tonic-gate 	 * Determine packet type based on type of address passed in
3927c478bd9Sstevel@tonic-gate 	 * the request should contain an IPv4 or IPv6 address.
3937c478bd9Sstevel@tonic-gate 	 * Make sure that address family matches the type of
394bd670b35SErik Nordmark 	 * family of the address passed down.
3957c478bd9Sstevel@tonic-gate 	 */
3967c478bd9Sstevel@tonic-gate 	if (addrlen < sizeof (sin_t)) {
3977c478bd9Sstevel@tonic-gate 		return (EINVAL);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 	switch (dst->sa_family) {
4007c478bd9Sstevel@tonic-gate 	case AF_INET:
4017c478bd9Sstevel@tonic-gate 		sin = (sin_t *)dst;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast */
404c4f4b3c8Skcpoon 		if (CLASSD(sin->sin_addr.s_addr) ||
4057c478bd9Sstevel@tonic-gate 		    (sin->sin_addr.s_addr == INADDR_BROADCAST)) {
4067c478bd9Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
4077c478bd9Sstevel@tonic-gate 			return (EINVAL);
4087c478bd9Sstevel@tonic-gate 		}
409bd670b35SErik Nordmark 		if (connp->conn_ipv6_v6only)
4107c478bd9Sstevel@tonic-gate 			return (EAFNOSUPPORT);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 		/* convert to v6 mapped */
4137c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to INADDR_ANY */
4147c478bd9Sstevel@tonic-gate 		if (sin->sin_addr.s_addr == INADDR_ANY)  {
4157c478bd9Sstevel@tonic-gate 			struct in_addr v4_addr;
4167c478bd9Sstevel@tonic-gate 			/*
4177c478bd9Sstevel@tonic-gate 			 * SunOS 4.x and 4.3 BSD allow an application
4187c478bd9Sstevel@tonic-gate 			 * to connect a TCP socket to INADDR_ANY.
4197c478bd9Sstevel@tonic-gate 			 * When they do this, the kernel picks the
4207c478bd9Sstevel@tonic-gate 			 * address of one interface and uses it
4217c478bd9Sstevel@tonic-gate 			 * instead.  The kernel usually ends up
4227c478bd9Sstevel@tonic-gate 			 * picking the address of the loopback
4237c478bd9Sstevel@tonic-gate 			 * interface.  This is an undocumented feature.
4247c478bd9Sstevel@tonic-gate 			 * However, we provide the same thing here
4257c478bd9Sstevel@tonic-gate 			 * in case any TCP apps that use this feature
4267c478bd9Sstevel@tonic-gate 			 * are being ported to SCTP...
4277c478bd9Sstevel@tonic-gate 			 */
4287c478bd9Sstevel@tonic-gate 			v4_addr.s_addr = htonl(INADDR_LOOPBACK);
4297c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr);
4307c478bd9Sstevel@tonic-gate 		} else {
4317c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr);
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate 		dstport = sin->sin_port;
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 	case AF_INET6:
4367c478bd9Sstevel@tonic-gate 		sin6 = (sin6_t *)dst;
4377c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast. */
4387c478bd9Sstevel@tonic-gate 		if ((addrlen < sizeof (sin6_t)) ||
4397c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
4407c478bd9Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
4417c478bd9Sstevel@tonic-gate 			return (EINVAL);
4427c478bd9Sstevel@tonic-gate 		}
443bd670b35SErik Nordmark 		if (connp->conn_ipv6_v6only &&
4447c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
4457c478bd9Sstevel@tonic-gate 			return (EAFNOSUPPORT);
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 		/* check for attempt to connect to unspec */
4487c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4497c478bd9Sstevel@tonic-gate 			dstaddr = ipv6_loopback;
4507c478bd9Sstevel@tonic-gate 		} else {
4517c478bd9Sstevel@tonic-gate 			dstaddr = sin6->sin6_addr;
452bd670b35SErik Nordmark 			if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) {
453f551bb10Svi 				sctp->sctp_linklocal = 1;
454bd670b35SErik Nordmark 				scope_id = sin6->sin6_scope_id;
455bd670b35SErik Nordmark 			}
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 		dstport = sin6->sin6_port;
458bd670b35SErik Nordmark 		connp->conn_flowinfo = sin6->sin6_flowinfo;
4597c478bd9Sstevel@tonic-gate 		break;
4607c478bd9Sstevel@tonic-gate 	default:
4617c478bd9Sstevel@tonic-gate 		dprint(1, ("sctp_connect: unknown family %d\n",
462b34b8d1aSkcpoon 		    dst->sa_family));
4637c478bd9Sstevel@tonic-gate 		return (EAFNOSUPPORT);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf));
4677c478bd9Sstevel@tonic-gate 	dprint(1, ("sctp_connect: attempting connect to %s...\n", buf));
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
4707c478bd9Sstevel@tonic-gate 
471bd670b35SErik Nordmark 	if (connp->conn_family != dst->sa_family ||
472bd670b35SErik Nordmark 	    (connp->conn_state_flags & CONN_CLOSING)) {
4737c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
4747c478bd9Sstevel@tonic-gate 		return (EINVAL);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
477bd670b35SErik Nordmark 	/* We update our cred/cpid based on the caller of connect */
478bd670b35SErik Nordmark 	if (connp->conn_cred != cr) {
479bd670b35SErik Nordmark 		crhold(cr);
480bd670b35SErik Nordmark 		crfree(connp->conn_cred);
481bd670b35SErik Nordmark 		connp->conn_cred = cr;
482bd670b35SErik Nordmark 	}
483bd670b35SErik Nordmark 	connp->conn_cpid = pid;
484bd670b35SErik Nordmark 
485bd670b35SErik Nordmark 	/* Cache things in conn_ixa without any refhold */
486bd670b35SErik Nordmark 	ixa = connp->conn_ixa;
487be4c8f74SErik Nordmark 	ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
488bd670b35SErik Nordmark 	ixa->ixa_cred = cr;
489bd670b35SErik Nordmark 	ixa->ixa_cpid = pid;
490bd670b35SErik Nordmark 	if (is_system_labeled()) {
491bd670b35SErik Nordmark 		/* We need to restart with a label based on the cred */
492bd670b35SErik Nordmark 		ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
493bd670b35SErik Nordmark 	}
494bd670b35SErik Nordmark 
4957c478bd9Sstevel@tonic-gate 	switch (sctp->sctp_state) {
4967c478bd9Sstevel@tonic-gate 	case SCTPS_IDLE: {
4971d8c4025Svi 		struct sockaddr_storage	ss;
4981d8c4025Svi 
4997c478bd9Sstevel@tonic-gate 		/*
5007c478bd9Sstevel@tonic-gate 		 * We support a quick connect capability here, allowing
5017c478bd9Sstevel@tonic-gate 		 * clients to transition directly from IDLE to COOKIE_WAIT.
5027c478bd9Sstevel@tonic-gate 		 * sctp_bindi will pick an unused port, insert the connection
5037c478bd9Sstevel@tonic-gate 		 * in the bind hash and transition to BOUND state. SCTP
5047c478bd9Sstevel@tonic-gate 		 * picks and uses what it considers the optimal local address
5057c478bd9Sstevel@tonic-gate 		 * set (just like specifiying INADDR_ANY to bind()).
5067c478bd9Sstevel@tonic-gate 		 */
5077c478bd9Sstevel@tonic-gate 		dprint(1, ("sctp_connect: idle, attempting bind...\n"));
5087c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs == 0);
5097c478bd9Sstevel@tonic-gate 
5101d8c4025Svi 		bzero(&ss, sizeof (ss));
511bd670b35SErik Nordmark 		ss.ss_family = connp->conn_family;
5121d8c4025Svi 		WAKE_SCTP(sctp);
5131d8c4025Svi 		if ((err = sctp_bind(sctp, (struct sockaddr *)&ss,
5141d8c4025Svi 		    sizeof (ss))) != 0) {
5157c478bd9Sstevel@tonic-gate 			return (err);
5167c478bd9Sstevel@tonic-gate 		}
5171d8c4025Svi 		RUN_SCTP(sctp);
5187c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	case SCTPS_BOUND:
5227c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs > 0);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/* do the connect */
5257c478bd9Sstevel@tonic-gate 		/* XXX check for attempt to connect to self */
526bd670b35SErik Nordmark 		connp->conn_fport = dstport;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		/*
5297c478bd9Sstevel@tonic-gate 		 * Don't allow this connection to completely duplicate
5307c478bd9Sstevel@tonic-gate 		 * an existing connection.
5317c478bd9Sstevel@tonic-gate 		 *
5327c478bd9Sstevel@tonic-gate 		 * Ensure that the duplicate check and insertion is atomic.
5337c478bd9Sstevel@tonic-gate 		 */
5347c478bd9Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
535f4b3ec61Sdh 		tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps,
536bd670b35SErik Nordmark 		    connp->conn_ports)];
5377c478bd9Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
538bd670b35SErik Nordmark 		lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports,
5397c478bd9Sstevel@tonic-gate 		    SCTPS_COOKIE_WAIT);
5407c478bd9Sstevel@tonic-gate 		if (lsctp != NULL) {
5417c478bd9Sstevel@tonic-gate 			/* found a duplicate connection */
5427c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5437c478bd9Sstevel@tonic-gate 			SCTP_REFRELE(lsctp);
5447c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5457c478bd9Sstevel@tonic-gate 			return (EADDRINUSE);
5467c478bd9Sstevel@tonic-gate 		}
547bd670b35SErik Nordmark 
5487c478bd9Sstevel@tonic-gate 		/*
5497c478bd9Sstevel@tonic-gate 		 * OK; set up the peer addr (this may grow after we get
5507c478bd9Sstevel@tonic-gate 		 * the INIT ACK from the peer with additional addresses).
5517c478bd9Sstevel@tonic-gate 		 */
55277c67f2fSkcpoon 		if ((err = sctp_add_faddr(sctp, &dstaddr, sleep,
55377c67f2fSkcpoon 		    B_FALSE)) != 0) {
5547c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5557c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
55645916cd2Sjpk 			return (err);
5577c478bd9Sstevel@tonic-gate 		}
558c31292eeSkcpoon 		cur_fp = sctp->sctp_faddrs;
559bd670b35SErik Nordmark 		ASSERT(cur_fp->ixa != NULL);
560c31292eeSkcpoon 
5617c478bd9Sstevel@tonic-gate 		/* No valid src addr, return. */
562c31292eeSkcpoon 		if (cur_fp->state == SCTP_FADDRS_UNREACH) {
5637c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5647c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5657c478bd9Sstevel@tonic-gate 			return (EADDRNOTAVAIL);
5667c478bd9Sstevel@tonic-gate 		}
567c31292eeSkcpoon 
568c31292eeSkcpoon 		sctp->sctp_primary = cur_fp;
569c31292eeSkcpoon 		sctp->sctp_current = cur_fp;
570c31292eeSkcpoon 		sctp->sctp_mss = cur_fp->sfa_pmss;
5717c478bd9Sstevel@tonic-gate 		sctp_conn_hash_insert(tbf, sctp, 1);
5727c478bd9Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
5737c478bd9Sstevel@tonic-gate 
574bd670b35SErik Nordmark 		ixa = cur_fp->ixa;
575bd670b35SErik Nordmark 		ASSERT(ixa->ixa_cred != NULL);
576bd670b35SErik Nordmark 
577bd670b35SErik Nordmark 		if (scope_id != 0) {
578bd670b35SErik Nordmark 			ixa->ixa_flags |= IXAF_SCOPEID_SET;
579bd670b35SErik Nordmark 			ixa->ixa_scopeid = scope_id;
580bd670b35SErik Nordmark 		} else {
581bd670b35SErik Nordmark 			ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
582bd670b35SErik Nordmark 		}
583bd670b35SErik Nordmark 
5847c478bd9Sstevel@tonic-gate 		/* initialize composite headers */
58577c67f2fSkcpoon 		if ((err = sctp_set_hdraddrs(sctp)) != 0) {
58645916cd2Sjpk 			sctp_conn_hash_remove(sctp);
58745916cd2Sjpk 			WAKE_SCTP(sctp);
58845916cd2Sjpk 			return (err);
58945916cd2Sjpk 		}
5907c478bd9Sstevel@tonic-gate 
591bd670b35SErik Nordmark 		if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) {
592bd670b35SErik Nordmark 			sctp_conn_hash_remove(sctp);
593bd670b35SErik Nordmark 			WAKE_SCTP(sctp);
594bd670b35SErik Nordmark 			return (err);
595f4b3ec61Sdh 		}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		/*
5987c478bd9Sstevel@tonic-gate 		 * Turn off the don't fragment bit on the (only) faddr,
5997c478bd9Sstevel@tonic-gate 		 * so that if one of the messages exchanged during the
6007c478bd9Sstevel@tonic-gate 		 * initialization sequence exceeds the path mtu, it
6017c478bd9Sstevel@tonic-gate 		 * at least has a chance to get there. SCTP does no
6027c478bd9Sstevel@tonic-gate 		 * fragmentation of initialization messages.  The DF bit
6037c478bd9Sstevel@tonic-gate 		 * will be turned on again in sctp_send_cookie_echo()
6047c478bd9Sstevel@tonic-gate 		 * (but the cookie echo will still be sent with the df bit
6057c478bd9Sstevel@tonic-gate 		 * off).
6067c478bd9Sstevel@tonic-gate 		 */
6077c478bd9Sstevel@tonic-gate 		cur_fp->df = B_FALSE;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		/* Mark this address as alive */
6107c478bd9Sstevel@tonic-gate 		cur_fp->state = SCTP_FADDRS_ALIVE;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		/* Send the INIT to the peer */
6137c478bd9Sstevel@tonic-gate 		SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto);
614c31292eeSkcpoon 		sctp->sctp_state = SCTPS_COOKIE_WAIT;
615f551bb10Svi 		/*
616f551bb10Svi 		 * sctp_init_mp() could result in modifying the source
617f551bb10Svi 		 * address list, so take the hash lock.
618f551bb10Svi 		 */
619f551bb10Svi 		mutex_enter(&tbf->tf_lock);
620bd670b35SErik Nordmark 		initmp = sctp_init_mp(sctp, cur_fp);
6217c478bd9Sstevel@tonic-gate 		if (initmp == NULL) {
622f551bb10Svi 			mutex_exit(&tbf->tf_lock);
623c31292eeSkcpoon 			/*
624c31292eeSkcpoon 			 * It may happen that all the source addresses
625c31292eeSkcpoon 			 * (loopback/link local) are removed.  In that case,
626c31292eeSkcpoon 			 * faile the connect.
627c31292eeSkcpoon 			 */
628c31292eeSkcpoon 			if (sctp->sctp_nsaddrs == 0) {
629c31292eeSkcpoon 				sctp_conn_hash_remove(sctp);
630c31292eeSkcpoon 				SCTP_FADDR_TIMER_STOP(cur_fp);
631c31292eeSkcpoon 				WAKE_SCTP(sctp);
632c31292eeSkcpoon 				return (EADDRNOTAVAIL);
633c31292eeSkcpoon 			}
634c31292eeSkcpoon 
635c31292eeSkcpoon 			/* Otherwise, let the retransmission timer retry */
6367c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
637c31292eeSkcpoon 			goto notify_ulp;
6387c478bd9Sstevel@tonic-gate 		}
639f551bb10Svi 		mutex_exit(&tbf->tf_lock);
640c31292eeSkcpoon 
6411d8c4025Svi 		/*
6421d8c4025Svi 		 * On a clustered note send this notification to the clustering
6431d8c4025Svi 		 * subsystem.
6441d8c4025Svi 		 */
6451d8c4025Svi 		if (cl_sctp_connect != NULL) {
6461d8c4025Svi 			uchar_t		*slist;
6471d8c4025Svi 			uchar_t		*flist;
6481d8c4025Svi 			size_t		ssize;
6491d8c4025Svi 			size_t		fsize;
6501d8c4025Svi 
6511d8c4025Svi 			fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
6521d8c4025Svi 			ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
6531d8c4025Svi 			slist = kmem_alloc(ssize, KM_SLEEP);
6541d8c4025Svi 			flist = kmem_alloc(fsize, KM_SLEEP);
6551d8c4025Svi 			/* The clustering module frees the lists */
6561d8c4025Svi 			sctp_get_saddr_list(sctp, slist, ssize);
6571d8c4025Svi 			sctp_get_faddr_list(sctp, flist, fsize);
658bd670b35SErik Nordmark 			(*cl_sctp_connect)(connp->conn_family, slist,
659bd670b35SErik Nordmark 			    sctp->sctp_nsaddrs, connp->conn_lport,
660bd670b35SErik Nordmark 			    flist, sctp->sctp_nfaddrs, connp->conn_fport,
6611d8c4025Svi 			    B_TRUE, (cl_sctp_handle_t)sctp);
6621d8c4025Svi 		}
663bd670b35SErik Nordmark 		ASSERT(ixa->ixa_cred != NULL);
664bd670b35SErik Nordmark 		ASSERT(ixa->ixa_ire != NULL);
665bd670b35SErik Nordmark 
666bd670b35SErik Nordmark 		(void) conn_ip_output(initmp, ixa);
6677c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_opkts);
668bd670b35SErik Nordmark 		WAKE_SCTP(sctp);
6697c478bd9Sstevel@tonic-gate 
670c31292eeSkcpoon notify_ulp:
671bd670b35SErik Nordmark 		sctp_set_ulp_prop(sctp);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 		return (0);
6747c478bd9Sstevel@tonic-gate 	default:
6757c478bd9Sstevel@tonic-gate 		ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state));
6767c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
6777c478bd9Sstevel@tonic-gate 		return (EINVAL);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate }
680