10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211735Skcpoon 
220Sstevel@tonic-gate /*
2312534SGeorge.Shepherd@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/systm.h>
280Sstevel@tonic-gate #include <sys/stream.h>
290Sstevel@tonic-gate #include <sys/cmn_err.h>
300Sstevel@tonic-gate #include <sys/kmem.h>
310Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
320Sstevel@tonic-gate #include <sys/tihdr.h>
330Sstevel@tonic-gate #include <sys/stropts.h>
340Sstevel@tonic-gate #include <sys/strsubr.h>
350Sstevel@tonic-gate #include <sys/socket.h>
361676Sjpk #include <sys/tsol/tndb.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <netinet/in.h>
390Sstevel@tonic-gate #include <netinet/ip6.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <inet/common.h>
420Sstevel@tonic-gate #include <inet/ip.h>
430Sstevel@tonic-gate #include <inet/ip6.h>
440Sstevel@tonic-gate #include <inet/ipclassifier.h>
450Sstevel@tonic-gate #include <inet/ipsec_impl.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include "sctp_impl.h"
480Sstevel@tonic-gate #include "sctp_addr.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * Common accept code.  Called by sctp_conn_request.
520Sstevel@tonic-gate  * cr_pkt is the INIT / INIT ACK packet.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate static int
550Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt,
560Sstevel@tonic-gate     uint_t ip_hdr_len, sctp_init_chunk_t *iack)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	sctp_hdr_t		*sctph;
600Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ich;
610Sstevel@tonic-gate 	sctp_init_chunk_t	*init;
620Sstevel@tonic-gate 	int			err;
630Sstevel@tonic-gate 	uint_t			sctp_options;
642776Skp158701 	conn_t			*aconnp;
651676Sjpk 	conn_t			*lconnp;
66*12869SKacheong.Poon@Sun.COM 	sctp_stack_t		*sctps = listener->sctp_sctps;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
690Sstevel@tonic-gate 	ASSERT(OK_32PTR(sctph));
700Sstevel@tonic-gate 
7111042SErik.Nordmark@Sun.COM 	aconnp = acceptor->sctp_connp;
7211042SErik.Nordmark@Sun.COM 	lconnp = listener->sctp_connp;
7311042SErik.Nordmark@Sun.COM 	aconnp->conn_lport = lconnp->conn_lport;
7411042SErik.Nordmark@Sun.COM 	aconnp->conn_fport = sctph->sh_sport;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	ich = (sctp_chunk_hdr_t *)(iack + 1);
770Sstevel@tonic-gate 	init = (sctp_init_chunk_t *)(ich + 1);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	/* acceptor isn't in any fanouts yet, so don't need to hold locks */
800Sstevel@tonic-gate 	ASSERT(acceptor->sctp_faddrs == NULL);
810Sstevel@tonic-gate 	err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
820Sstevel@tonic-gate 	    &sctp_options);
830Sstevel@tonic-gate 	if (err != 0)
840Sstevel@tonic-gate 		return (err);
850Sstevel@tonic-gate 
861735Skcpoon 	if ((err = sctp_set_hdraddrs(acceptor)) != 0)
871676Sjpk 		return (err);
881676Sjpk 
8911042SErik.Nordmark@Sun.COM 	if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0)
9011042SErik.Nordmark@Sun.COM 		return (err);
9111042SErik.Nordmark@Sun.COM 
920Sstevel@tonic-gate 	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
933448Sdh155122 	    listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) {
940Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_TRUE;
950Sstevel@tonic-gate 	} else {
960Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_FALSE;
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	/* Get  initial TSNs */
1000Sstevel@tonic-gate 	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
1010Sstevel@tonic-gate 	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
1020Sstevel@tonic-gate 	    acceptor->sctp_ltsn - 1;
1030Sstevel@tonic-gate 	acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd;
1040Sstevel@tonic-gate 	/* Serial numbers are initialized to the same value as the TSNs */
1050Sstevel@tonic-gate 	acceptor->sctp_lcsn = acceptor->sctp_ltsn;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	if (!sctp_initialize_params(acceptor, init, iack))
1080Sstevel@tonic-gate 		return (ENOMEM);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	/*
1110Sstevel@tonic-gate 	 * Copy sctp_secret from the listener in case we need to validate
1120Sstevel@tonic-gate 	 * a possibly delayed cookie.
1130Sstevel@tonic-gate 	 */
1140Sstevel@tonic-gate 	bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN);
1150Sstevel@tonic-gate 	bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret,
1160Sstevel@tonic-gate 	    SCTP_SECRET_LEN);
11711066Srafael.vanoni@sun.com 	acceptor->sctp_last_secret_update = ddi_get_lbolt64();
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/*
1200Sstevel@tonic-gate 	 * After acceptor is inserted in the hash list, it can be found.
1210Sstevel@tonic-gate 	 * So we need to lock it here.
1220Sstevel@tonic-gate 	 */
1230Sstevel@tonic-gate 	RUN_SCTP(acceptor);
1240Sstevel@tonic-gate 
1253448Sdh155122 	sctp_conn_hash_insert(&sctps->sctps_conn_fanout[
12611042SErik.Nordmark@Sun.COM 	    SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0);
1273448Sdh155122 	sctp_bind_hash_insert(&sctps->sctps_bind_fanout[
12811042SErik.Nordmark@Sun.COM 	    SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0);
1290Sstevel@tonic-gate 
130*12869SKacheong.Poon@Sun.COM 	SCTP_ASSOC_EST(sctps, acceptor);
131*12869SKacheong.Poon@Sun.COM 
1320Sstevel@tonic-gate 	/*
1330Sstevel@tonic-gate 	 * listener->sctp_rwnd should be the default window size or a
1340Sstevel@tonic-gate 	 * window size changed via SO_RCVBUF option.
1350Sstevel@tonic-gate 	 */
136852Svi117747 	acceptor->sctp_rwnd = listener->sctp_rwnd;
137852Svi117747 	acceptor->sctp_irwnd = acceptor->sctp_rwnd;
1383845Svi117747 	acceptor->sctp_pd_point = acceptor->sctp_rwnd;
1398348SEric.Yu@Sun.COM 	acceptor->sctp_upcalls = listener->sctp_upcalls;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	return (0);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */
1450Sstevel@tonic-gate sctp_t *
1460Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len,
14711042SErik.Nordmark@Sun.COM     sctp_init_chunk_t *iack, ip_recv_attr_t *ira)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate 	sctp_t	*eager;
1500Sstevel@tonic-gate 	ip6_t	*ip6h;
1510Sstevel@tonic-gate 	int	err;
1520Sstevel@tonic-gate 	conn_t	*connp, *econnp;
1533448Sdh155122 	sctp_stack_t	*sctps;
1548348SEric.Yu@Sun.COM 	struct sock_proto_props sopp;
1558778SErik.Nordmark@Sun.COM 	cred_t		*cr;
1568778SErik.Nordmark@Sun.COM 	pid_t		cpid;
15711042SErik.Nordmark@Sun.COM 	in6_addr_t	faddr, laddr;
15811042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t	*ixa;
159*12869SKacheong.Poon@Sun.COM 	sctp_listen_cnt_t *slc = sctp->sctp_listen_cnt;
160*12869SKacheong.Poon@Sun.COM 	boolean_t	slc_set = B_FALSE;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * No need to check for duplicate as this is the listener
1640Sstevel@tonic-gate 	 * and we are holding the lock.  This means that no new
1650Sstevel@tonic-gate 	 * connection can be created out of it.  And since the
1660Sstevel@tonic-gate 	 * fanout already done cannot find a match, it means that
1670Sstevel@tonic-gate 	 * there is no duplicate.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	ASSERT(OK_32PTR(mp->b_rptr));
1700Sstevel@tonic-gate 
171*12869SKacheong.Poon@Sun.COM 	connp = sctp->sctp_connp;
172*12869SKacheong.Poon@Sun.COM 	sctps = sctp->sctp_sctps;
173*12869SKacheong.Poon@Sun.COM 
174*12869SKacheong.Poon@Sun.COM 	/*
175*12869SKacheong.Poon@Sun.COM 	 * Enforce the limit set on the number of connections per listener.
176*12869SKacheong.Poon@Sun.COM 	 * Note that tlc_cnt starts with 1.  So need to add 1 to tlc_max
177*12869SKacheong.Poon@Sun.COM 	 * for comparison.
178*12869SKacheong.Poon@Sun.COM 	 */
179*12869SKacheong.Poon@Sun.COM 	if (slc != NULL) {
180*12869SKacheong.Poon@Sun.COM 		int64_t now;
181*12869SKacheong.Poon@Sun.COM 
182*12869SKacheong.Poon@Sun.COM 		if (atomic_add_32_nv(&slc->slc_cnt, 1) > slc->slc_max + 1) {
183*12869SKacheong.Poon@Sun.COM 			now = ddi_get_lbolt64();
184*12869SKacheong.Poon@Sun.COM 			atomic_add_32(&slc->slc_cnt, -1);
185*12869SKacheong.Poon@Sun.COM 			SCTP_KSTAT(sctps, sctp_listen_cnt_drop);
186*12869SKacheong.Poon@Sun.COM 			slc->slc_drop++;
187*12869SKacheong.Poon@Sun.COM 			if (now - slc->slc_report_time >
188*12869SKacheong.Poon@Sun.COM 			    MSEC_TO_TICK(SCTP_SLC_REPORT_INTERVAL)) {
189*12869SKacheong.Poon@Sun.COM 				zcmn_err(connp->conn_zoneid, CE_WARN,
190*12869SKacheong.Poon@Sun.COM 				    "SCTP listener (port %d) association max "
191*12869SKacheong.Poon@Sun.COM 				    "(%u) reached: %u attempts dropped total\n",
192*12869SKacheong.Poon@Sun.COM 				    ntohs(connp->conn_lport),
193*12869SKacheong.Poon@Sun.COM 				    slc->slc_max, slc->slc_drop);
194*12869SKacheong.Poon@Sun.COM 				slc->slc_report_time = now;
195*12869SKacheong.Poon@Sun.COM 			}
196*12869SKacheong.Poon@Sun.COM 			return (NULL);
197*12869SKacheong.Poon@Sun.COM 		}
198*12869SKacheong.Poon@Sun.COM 		slc_set = B_TRUE;
199*12869SKacheong.Poon@Sun.COM 	}
200*12869SKacheong.Poon@Sun.COM 
2010Sstevel@tonic-gate 	if ((eager = sctp_create_eager(sctp)) == NULL) {
202*12869SKacheong.Poon@Sun.COM 		if (slc_set)
203*12869SKacheong.Poon@Sun.COM 			atomic_add_32(&slc->slc_cnt, -1);
2040Sstevel@tonic-gate 		return (NULL);
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 	econnp = eager->sctp_connp;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (connp->conn_policy != NULL) {
20911042SErik.Nordmark@Sun.COM 		/* Inherit the policy from the listener; use actions from ira */
21011042SErik.Nordmark@Sun.COM 		if (!ip_ipsec_policy_inherit(econnp, connp, ira)) {
2110Sstevel@tonic-gate 			sctp_close_eager(eager);
212*12869SKacheong.Poon@Sun.COM 			SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2130Sstevel@tonic-gate 			return (NULL);
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
21711042SErik.Nordmark@Sun.COM 	ip6h = (ip6_t *)mp->b_rptr;
21811042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IXAF_IS_IPV4) {
21911042SErik.Nordmark@Sun.COM 		ipha_t	*ipha;
22011042SErik.Nordmark@Sun.COM 
22111042SErik.Nordmark@Sun.COM 		ipha = (ipha_t *)ip6h;
22211042SErik.Nordmark@Sun.COM 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr);
22311042SErik.Nordmark@Sun.COM 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr);
22411042SErik.Nordmark@Sun.COM 	} else {
22511042SErik.Nordmark@Sun.COM 		laddr = ip6h->ip6_dst;
22611042SErik.Nordmark@Sun.COM 		faddr = ip6h->ip6_src;
22711042SErik.Nordmark@Sun.COM 	}
22811042SErik.Nordmark@Sun.COM 
22911042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
2300Sstevel@tonic-gate 		/*
2310Sstevel@tonic-gate 		 * XXX need to fix the cached policy issue here.
23211042SErik.Nordmark@Sun.COM 		 * We temporarily set the conn_laddr/conn_faddr here so
2330Sstevel@tonic-gate 		 * that IPsec can use it for the latched policy
2340Sstevel@tonic-gate 		 * selector.  This is obvioursly wrong as SCTP can
2350Sstevel@tonic-gate 		 * use different addresses...
2360Sstevel@tonic-gate 		 */
23711042SErik.Nordmark@Sun.COM 		econnp->conn_laddr_v6 = laddr;
23811042SErik.Nordmark@Sun.COM 		econnp->conn_faddr_v6 = faddr;
23911042SErik.Nordmark@Sun.COM 		econnp->conn_saddr_v6 = laddr;
2400Sstevel@tonic-gate 	}
24111042SErik.Nordmark@Sun.COM 	if (ipsec_conn_cache_policy(econnp,
24211042SErik.Nordmark@Sun.COM 	    (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) {
2430Sstevel@tonic-gate 		sctp_close_eager(eager);
244*12869SKacheong.Poon@Sun.COM 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2450Sstevel@tonic-gate 		return (NULL);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2488778SErik.Nordmark@Sun.COM 	/* Save for getpeerucred */
24911042SErik.Nordmark@Sun.COM 	cr = ira->ira_cred;
25011042SErik.Nordmark@Sun.COM 	cpid = ira->ira_cpid;
25111042SErik.Nordmark@Sun.COM 
25211042SErik.Nordmark@Sun.COM 	if (is_system_labeled()) {
25311042SErik.Nordmark@Sun.COM 		ip_xmit_attr_t *ixa = econnp->conn_ixa;
25411042SErik.Nordmark@Sun.COM 
25511042SErik.Nordmark@Sun.COM 		ASSERT(ira->ira_tsl != NULL);
25611042SErik.Nordmark@Sun.COM 
25711042SErik.Nordmark@Sun.COM 		/* Discard any old label */
25811042SErik.Nordmark@Sun.COM 		if (ixa->ixa_free_flags & IXA_FREE_TSL) {
25911042SErik.Nordmark@Sun.COM 			ASSERT(ixa->ixa_tsl != NULL);
26011042SErik.Nordmark@Sun.COM 			label_rele(ixa->ixa_tsl);
26111042SErik.Nordmark@Sun.COM 			ixa->ixa_free_flags &= ~IXA_FREE_TSL;
26211042SErik.Nordmark@Sun.COM 			ixa->ixa_tsl = NULL;
26311042SErik.Nordmark@Sun.COM 		}
26411042SErik.Nordmark@Sun.COM 
26511042SErik.Nordmark@Sun.COM 		if ((connp->conn_mlp_type != mlptSingle ||
26611042SErik.Nordmark@Sun.COM 		    connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
26711042SErik.Nordmark@Sun.COM 		    ira->ira_tsl != NULL) {
26811042SErik.Nordmark@Sun.COM 			/*
26911042SErik.Nordmark@Sun.COM 			 * If this is an MLP connection or a MAC-Exempt
27011042SErik.Nordmark@Sun.COM 			 * connection with an unlabeled node, packets are to be
27111042SErik.Nordmark@Sun.COM 			 * exchanged using the security label of the received
27211042SErik.Nordmark@Sun.COM 			 * Cookie packet instead of the server application's
27311042SErik.Nordmark@Sun.COM 			 * label.
27411042SErik.Nordmark@Sun.COM 			 * tsol_check_dest called from ip_set_destination
27511042SErik.Nordmark@Sun.COM 			 * might later update TSF_UNLABELED by replacing
27611042SErik.Nordmark@Sun.COM 			 * ixa_tsl with a new label.
27711042SErik.Nordmark@Sun.COM 			 */
27811042SErik.Nordmark@Sun.COM 			label_hold(ira->ira_tsl);
27911042SErik.Nordmark@Sun.COM 			ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl);
28011042SErik.Nordmark@Sun.COM 		} else {
28111042SErik.Nordmark@Sun.COM 			ixa->ixa_tsl = crgetlabel(econnp->conn_cred);
28211042SErik.Nordmark@Sun.COM 		}
28311042SErik.Nordmark@Sun.COM 	}
2848778SErik.Nordmark@Sun.COM 
2850Sstevel@tonic-gate 	err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack);
28611042SErik.Nordmark@Sun.COM 	if (err != 0) {
2870Sstevel@tonic-gate 		sctp_close_eager(eager);
288*12869SKacheong.Poon@Sun.COM 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
2890Sstevel@tonic-gate 		return (NULL);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
29211042SErik.Nordmark@Sun.COM 	ASSERT(eager->sctp_current->ixa != NULL);
29311042SErik.Nordmark@Sun.COM 
29411042SErik.Nordmark@Sun.COM 	ixa = eager->sctp_current->ixa;
29511042SErik.Nordmark@Sun.COM 	if (!(ira->ira_flags & IXAF_IS_IPV4)) {
29611042SErik.Nordmark@Sun.COM 		ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4));
29711042SErik.Nordmark@Sun.COM 
29811042SErik.Nordmark@Sun.COM 		if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ||
29911042SErik.Nordmark@Sun.COM 		    IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) {
30011042SErik.Nordmark@Sun.COM 			eager->sctp_linklocal = 1;
30111042SErik.Nordmark@Sun.COM 
30211042SErik.Nordmark@Sun.COM 			ixa->ixa_flags |= IXAF_SCOPEID_SET;
30311042SErik.Nordmark@Sun.COM 			ixa->ixa_scopeid = ifindex;
30411042SErik.Nordmark@Sun.COM 			econnp->conn_incoming_ifindex = ifindex;
30511042SErik.Nordmark@Sun.COM 		}
30611042SErik.Nordmark@Sun.COM 	}
30711042SErik.Nordmark@Sun.COM 
308852Svi117747 	/*
309852Svi117747 	 * On a clustered note send this notification to the clustering
310852Svi117747 	 * subsystem.
311852Svi117747 	 */
312852Svi117747 	if (cl_sctp_connect != NULL) {
313852Svi117747 		uchar_t	*slist;
314852Svi117747 		uchar_t	*flist;
315852Svi117747 		size_t	fsize;
316852Svi117747 		size_t	ssize;
317852Svi117747 
318852Svi117747 		fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs;
319852Svi117747 		ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs;
320852Svi117747 		slist = kmem_alloc(ssize, KM_NOSLEEP);
321852Svi117747 		flist = kmem_alloc(fsize, KM_NOSLEEP);
322852Svi117747 		if (slist == NULL || flist == NULL) {
323852Svi117747 			if (slist != NULL)
324852Svi117747 				kmem_free(slist, ssize);
325852Svi117747 			if (flist != NULL)
326852Svi117747 				kmem_free(flist, fsize);
327852Svi117747 			sctp_close_eager(eager);
328*12869SKacheong.Poon@Sun.COM 			SCTPS_BUMP_MIB(sctps, sctpListenDrop);
3293448Sdh155122 			SCTP_KSTAT(sctps, sctp_cl_connect);
330852Svi117747 			return (NULL);
331852Svi117747 		}
332852Svi117747 		/* The clustering module frees these list */
333852Svi117747 		sctp_get_saddr_list(eager, slist, ssize);
334852Svi117747 		sctp_get_faddr_list(eager, flist, fsize);
33511042SErik.Nordmark@Sun.COM 		(*cl_sctp_connect)(econnp->conn_family, slist,
33611042SErik.Nordmark@Sun.COM 		    eager->sctp_nsaddrs, econnp->conn_lport, flist,
33711042SErik.Nordmark@Sun.COM 		    eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE,
338852Svi117747 		    (cl_sctp_handle_t)eager);
339852Svi117747 	}
340852Svi117747 
3410Sstevel@tonic-gate 	/* Connection established, so send up the conn_ind */
3420Sstevel@tonic-gate 	if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd,
3438778SErik.Nordmark@Sun.COM 	    (sock_lower_handle_t)eager, NULL, cr, cpid,
3448348SEric.Yu@Sun.COM 	    &eager->sctp_upcalls)) == NULL) {
3450Sstevel@tonic-gate 		sctp_close_eager(eager);
346*12869SKacheong.Poon@Sun.COM 		SCTPS_BUMP_MIB(sctps, sctpListenDrop);
3470Sstevel@tonic-gate 		return (NULL);
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 	ASSERT(SCTP_IS_DETACHED(eager));
3500Sstevel@tonic-gate 	eager->sctp_detached = B_FALSE;
3518348SEric.Yu@Sun.COM 	bzero(&sopp, sizeof (sopp));
3528348SEric.Yu@Sun.COM 	sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF;
3538348SEric.Yu@Sun.COM 	sopp.sopp_maxblk = strmsgsz;
35411042SErik.Nordmark@Sun.COM 	if (econnp->conn_family == AF_INET) {
3558348SEric.Yu@Sun.COM 		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
3568348SEric.Yu@Sun.COM 		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len;
3570Sstevel@tonic-gate 	} else {
3588348SEric.Yu@Sun.COM 		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
3598348SEric.Yu@Sun.COM 		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len;
3600Sstevel@tonic-gate 	}
3618348SEric.Yu@Sun.COM 	eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp);
3620Sstevel@tonic-gate 	return (eager);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate  * Connect to a peer - this function inserts the sctp in the
3670Sstevel@tonic-gate  * bind and conn fanouts, sends the INIT, and replies to the client
3680Sstevel@tonic-gate  * with an OK ack.
3690Sstevel@tonic-gate  */
3700Sstevel@tonic-gate int
37111042SErik.Nordmark@Sun.COM sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen,
37211042SErik.Nordmark@Sun.COM     cred_t *cr, pid_t pid)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate 	sin_t		*sin;
3750Sstevel@tonic-gate 	sin6_t		*sin6;
3760Sstevel@tonic-gate 	in6_addr_t	dstaddr;
3770Sstevel@tonic-gate 	in_port_t	dstport;
3780Sstevel@tonic-gate 	mblk_t		*initmp;
3790Sstevel@tonic-gate 	sctp_tf_t	*tbf;
3800Sstevel@tonic-gate 	sctp_t		*lsctp;
3810Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
3820Sstevel@tonic-gate 	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
3831676Sjpk 	int		err;
3840Sstevel@tonic-gate 	sctp_faddr_t	*cur_fp;
3853448Sdh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
38611042SErik.Nordmark@Sun.COM 	conn_t		*connp = sctp->sctp_connp;
38711042SErik.Nordmark@Sun.COM 	uint_t		scope_id = 0;
38811042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t	*ixa;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/*
3910Sstevel@tonic-gate 	 * Determine packet type based on type of address passed in
3920Sstevel@tonic-gate 	 * the request should contain an IPv4 or IPv6 address.
3930Sstevel@tonic-gate 	 * Make sure that address family matches the type of
39411042SErik.Nordmark@Sun.COM 	 * family of the address passed down.
3950Sstevel@tonic-gate 	 */
3960Sstevel@tonic-gate 	if (addrlen < sizeof (sin_t)) {
3970Sstevel@tonic-gate 		return (EINVAL);
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 	switch (dst->sa_family) {
4000Sstevel@tonic-gate 	case AF_INET:
4010Sstevel@tonic-gate 		sin = (sin_t *)dst;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast */
4045215Skcpoon 		if (CLASSD(sin->sin_addr.s_addr) ||
4050Sstevel@tonic-gate 		    (sin->sin_addr.s_addr == INADDR_BROADCAST)) {
4060Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
4070Sstevel@tonic-gate 			return (EINVAL);
4080Sstevel@tonic-gate 		}
40911042SErik.Nordmark@Sun.COM 		if (connp->conn_ipv6_v6only)
4100Sstevel@tonic-gate 			return (EAFNOSUPPORT);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 		/* convert to v6 mapped */
4130Sstevel@tonic-gate 		/* Check for attempt to connect to INADDR_ANY */
4140Sstevel@tonic-gate 		if (sin->sin_addr.s_addr == INADDR_ANY)  {
4150Sstevel@tonic-gate 			struct in_addr v4_addr;
4160Sstevel@tonic-gate 			/*
4170Sstevel@tonic-gate 			 * SunOS 4.x and 4.3 BSD allow an application
4180Sstevel@tonic-gate 			 * to connect a TCP socket to INADDR_ANY.
4190Sstevel@tonic-gate 			 * When they do this, the kernel picks the
4200Sstevel@tonic-gate 			 * address of one interface and uses it
4210Sstevel@tonic-gate 			 * instead.  The kernel usually ends up
4220Sstevel@tonic-gate 			 * picking the address of the loopback
4230Sstevel@tonic-gate 			 * interface.  This is an undocumented feature.
4240Sstevel@tonic-gate 			 * However, we provide the same thing here
4250Sstevel@tonic-gate 			 * in case any TCP apps that use this feature
4260Sstevel@tonic-gate 			 * are being ported to SCTP...
4270Sstevel@tonic-gate 			 */
4280Sstevel@tonic-gate 			v4_addr.s_addr = htonl(INADDR_LOOPBACK);
4290Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr);
4300Sstevel@tonic-gate 		} else {
4310Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr);
4320Sstevel@tonic-gate 		}
4330Sstevel@tonic-gate 		dstport = sin->sin_port;
4340Sstevel@tonic-gate 		break;
4350Sstevel@tonic-gate 	case AF_INET6:
4360Sstevel@tonic-gate 		sin6 = (sin6_t *)dst;
4370Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast. */
4380Sstevel@tonic-gate 		if ((addrlen < sizeof (sin6_t)) ||
4390Sstevel@tonic-gate 		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
4400Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
4410Sstevel@tonic-gate 			return (EINVAL);
4420Sstevel@tonic-gate 		}
44311042SErik.Nordmark@Sun.COM 		if (connp->conn_ipv6_v6only &&
4440Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
4450Sstevel@tonic-gate 			return (EAFNOSUPPORT);
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 		/* check for attempt to connect to unspec */
4480Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4490Sstevel@tonic-gate 			dstaddr = ipv6_loopback;
4500Sstevel@tonic-gate 		} else {
4510Sstevel@tonic-gate 			dstaddr = sin6->sin6_addr;
45211042SErik.Nordmark@Sun.COM 			if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) {
453432Svi117747 				sctp->sctp_linklocal = 1;
45411042SErik.Nordmark@Sun.COM 				scope_id = sin6->sin6_scope_id;
45511042SErik.Nordmark@Sun.COM 			}
4560Sstevel@tonic-gate 		}
4570Sstevel@tonic-gate 		dstport = sin6->sin6_port;
45811042SErik.Nordmark@Sun.COM 		connp->conn_flowinfo = sin6->sin6_flowinfo;
4590Sstevel@tonic-gate 		break;
4600Sstevel@tonic-gate 	default:
4610Sstevel@tonic-gate 		dprint(1, ("sctp_connect: unknown family %d\n",
4624505Skcpoon 		    dst->sa_family));
4630Sstevel@tonic-gate 		return (EAFNOSUPPORT);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf));
4670Sstevel@tonic-gate 	dprint(1, ("sctp_connect: attempting connect to %s...\n", buf));
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	RUN_SCTP(sctp);
4700Sstevel@tonic-gate 
47111042SErik.Nordmark@Sun.COM 	if (connp->conn_family != dst->sa_family ||
47211042SErik.Nordmark@Sun.COM 	    (connp->conn_state_flags & CONN_CLOSING)) {
4730Sstevel@tonic-gate 		WAKE_SCTP(sctp);
4740Sstevel@tonic-gate 		return (EINVAL);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
47711042SErik.Nordmark@Sun.COM 	/* We update our cred/cpid based on the caller of connect */
47811042SErik.Nordmark@Sun.COM 	if (connp->conn_cred != cr) {
47911042SErik.Nordmark@Sun.COM 		crhold(cr);
48011042SErik.Nordmark@Sun.COM 		crfree(connp->conn_cred);
48111042SErik.Nordmark@Sun.COM 		connp->conn_cred = cr;
48211042SErik.Nordmark@Sun.COM 	}
48311042SErik.Nordmark@Sun.COM 	connp->conn_cpid = pid;
48411042SErik.Nordmark@Sun.COM 
48511042SErik.Nordmark@Sun.COM 	/* Cache things in conn_ixa without any refhold */
48611042SErik.Nordmark@Sun.COM 	ixa = connp->conn_ixa;
48711849SErik.Nordmark@Sun.COM 	ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
48811042SErik.Nordmark@Sun.COM 	ixa->ixa_cred = cr;
48911042SErik.Nordmark@Sun.COM 	ixa->ixa_cpid = pid;
49011042SErik.Nordmark@Sun.COM 	if (is_system_labeled()) {
49111042SErik.Nordmark@Sun.COM 		/* We need to restart with a label based on the cred */
49211042SErik.Nordmark@Sun.COM 		ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
49311042SErik.Nordmark@Sun.COM 	}
49411042SErik.Nordmark@Sun.COM 
4950Sstevel@tonic-gate 	switch (sctp->sctp_state) {
4960Sstevel@tonic-gate 	case SCTPS_IDLE: {
497852Svi117747 		struct sockaddr_storage	ss;
498852Svi117747 
4990Sstevel@tonic-gate 		/*
5000Sstevel@tonic-gate 		 * We support a quick connect capability here, allowing
5010Sstevel@tonic-gate 		 * clients to transition directly from IDLE to COOKIE_WAIT.
5020Sstevel@tonic-gate 		 * sctp_bindi will pick an unused port, insert the connection
5030Sstevel@tonic-gate 		 * in the bind hash and transition to BOUND state. SCTP
5040Sstevel@tonic-gate 		 * picks and uses what it considers the optimal local address
5050Sstevel@tonic-gate 		 * set (just like specifiying INADDR_ANY to bind()).
5060Sstevel@tonic-gate 		 */
5070Sstevel@tonic-gate 		dprint(1, ("sctp_connect: idle, attempting bind...\n"));
5080Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs == 0);
5090Sstevel@tonic-gate 
510852Svi117747 		bzero(&ss, sizeof (ss));
51111042SErik.Nordmark@Sun.COM 		ss.ss_family = connp->conn_family;
512852Svi117747 		WAKE_SCTP(sctp);
513852Svi117747 		if ((err = sctp_bind(sctp, (struct sockaddr *)&ss,
514852Svi117747 		    sizeof (ss))) != 0) {
5150Sstevel@tonic-gate 			return (err);
5160Sstevel@tonic-gate 		}
517852Svi117747 		RUN_SCTP(sctp);
5180Sstevel@tonic-gate 		/* FALLTHRU */
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	case SCTPS_BOUND:
5220Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs > 0);
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 		/* do the connect */
5250Sstevel@tonic-gate 		/* XXX check for attempt to connect to self */
52611042SErik.Nordmark@Sun.COM 		connp->conn_fport = dstport;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		/*
5290Sstevel@tonic-gate 		 * Don't allow this connection to completely duplicate
5300Sstevel@tonic-gate 		 * an existing connection.
5310Sstevel@tonic-gate 		 *
5320Sstevel@tonic-gate 		 * Ensure that the duplicate check and insertion is atomic.
5330Sstevel@tonic-gate 		 */
5340Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
5353448Sdh155122 		tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps,
53611042SErik.Nordmark@Sun.COM 		    connp->conn_ports)];
5370Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
53811042SErik.Nordmark@Sun.COM 		lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports,
5390Sstevel@tonic-gate 		    SCTPS_COOKIE_WAIT);
5400Sstevel@tonic-gate 		if (lsctp != NULL) {
5410Sstevel@tonic-gate 			/* found a duplicate connection */
5420Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5430Sstevel@tonic-gate 			SCTP_REFRELE(lsctp);
5440Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5450Sstevel@tonic-gate 			return (EADDRINUSE);
5460Sstevel@tonic-gate 		}
54711042SErik.Nordmark@Sun.COM 
5480Sstevel@tonic-gate 		/*
5490Sstevel@tonic-gate 		 * OK; set up the peer addr (this may grow after we get
5500Sstevel@tonic-gate 		 * the INIT ACK from the peer with additional addresses).
5510Sstevel@tonic-gate 		 */
5521735Skcpoon 		if ((err = sctp_add_faddr(sctp, &dstaddr, sleep,
5531735Skcpoon 		    B_FALSE)) != 0) {
5540Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5550Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5561676Sjpk 			return (err);
5570Sstevel@tonic-gate 		}
5584818Skcpoon 		cur_fp = sctp->sctp_faddrs;
55911042SErik.Nordmark@Sun.COM 		ASSERT(cur_fp->ixa != NULL);
5604818Skcpoon 
5610Sstevel@tonic-gate 		/* No valid src addr, return. */
5624818Skcpoon 		if (cur_fp->state == SCTP_FADDRS_UNREACH) {
5630Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
5640Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5650Sstevel@tonic-gate 			return (EADDRNOTAVAIL);
5660Sstevel@tonic-gate 		}
5674818Skcpoon 
5684818Skcpoon 		sctp->sctp_primary = cur_fp;
5694818Skcpoon 		sctp->sctp_current = cur_fp;
5704818Skcpoon 		sctp->sctp_mss = cur_fp->sfa_pmss;
5710Sstevel@tonic-gate 		sctp_conn_hash_insert(tbf, sctp, 1);
5720Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
5730Sstevel@tonic-gate 
57411042SErik.Nordmark@Sun.COM 		ixa = cur_fp->ixa;
57511042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_cred != NULL);
57611042SErik.Nordmark@Sun.COM 
57711042SErik.Nordmark@Sun.COM 		if (scope_id != 0) {
57811042SErik.Nordmark@Sun.COM 			ixa->ixa_flags |= IXAF_SCOPEID_SET;
57911042SErik.Nordmark@Sun.COM 			ixa->ixa_scopeid = scope_id;
58011042SErik.Nordmark@Sun.COM 		} else {
58111042SErik.Nordmark@Sun.COM 			ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
58211042SErik.Nordmark@Sun.COM 		}
58311042SErik.Nordmark@Sun.COM 
5840Sstevel@tonic-gate 		/* initialize composite headers */
5851735Skcpoon 		if ((err = sctp_set_hdraddrs(sctp)) != 0) {
5861676Sjpk 			sctp_conn_hash_remove(sctp);
5871676Sjpk 			WAKE_SCTP(sctp);
5881676Sjpk 			return (err);
5891676Sjpk 		}
5900Sstevel@tonic-gate 
59111042SErik.Nordmark@Sun.COM 		if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) {
59211042SErik.Nordmark@Sun.COM 			sctp_conn_hash_remove(sctp);
59311042SErik.Nordmark@Sun.COM 			WAKE_SCTP(sctp);
59411042SErik.Nordmark@Sun.COM 			return (err);
5953448Sdh155122 		}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		/*
5980Sstevel@tonic-gate 		 * Turn off the don't fragment bit on the (only) faddr,
5990Sstevel@tonic-gate 		 * so that if one of the messages exchanged during the
6000Sstevel@tonic-gate 		 * initialization sequence exceeds the path mtu, it
6010Sstevel@tonic-gate 		 * at least has a chance to get there. SCTP does no
6020Sstevel@tonic-gate 		 * fragmentation of initialization messages.  The DF bit
6030Sstevel@tonic-gate 		 * will be turned on again in sctp_send_cookie_echo()
6040Sstevel@tonic-gate 		 * (but the cookie echo will still be sent with the df bit
6050Sstevel@tonic-gate 		 * off).
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		cur_fp->df = B_FALSE;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 		/* Mark this address as alive */
6100Sstevel@tonic-gate 		cur_fp->state = SCTP_FADDRS_ALIVE;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 		/* Send the INIT to the peer */
6130Sstevel@tonic-gate 		SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto);
6144818Skcpoon 		sctp->sctp_state = SCTPS_COOKIE_WAIT;
615432Svi117747 		/*
616432Svi117747 		 * sctp_init_mp() could result in modifying the source
617432Svi117747 		 * address list, so take the hash lock.
618432Svi117747 		 */
619432Svi117747 		mutex_enter(&tbf->tf_lock);
62011042SErik.Nordmark@Sun.COM 		initmp = sctp_init_mp(sctp, cur_fp);
6210Sstevel@tonic-gate 		if (initmp == NULL) {
622432Svi117747 			mutex_exit(&tbf->tf_lock);
6234818Skcpoon 			/*
6244818Skcpoon 			 * It may happen that all the source addresses
6254818Skcpoon 			 * (loopback/link local) are removed.  In that case,
6264818Skcpoon 			 * faile the connect.
6274818Skcpoon 			 */
6284818Skcpoon 			if (sctp->sctp_nsaddrs == 0) {
6294818Skcpoon 				sctp_conn_hash_remove(sctp);
6304818Skcpoon 				SCTP_FADDR_TIMER_STOP(cur_fp);
6314818Skcpoon 				WAKE_SCTP(sctp);
6324818Skcpoon 				return (EADDRNOTAVAIL);
6334818Skcpoon 			}
6344818Skcpoon 
6354818Skcpoon 			/* Otherwise, let the retransmission timer retry */
6360Sstevel@tonic-gate 			WAKE_SCTP(sctp);
6374818Skcpoon 			goto notify_ulp;
6380Sstevel@tonic-gate 		}
639432Svi117747 		mutex_exit(&tbf->tf_lock);
6404818Skcpoon 
641852Svi117747 		/*
642852Svi117747 		 * On a clustered note send this notification to the clustering
643852Svi117747 		 * subsystem.
644852Svi117747 		 */
645852Svi117747 		if (cl_sctp_connect != NULL) {
646852Svi117747 			uchar_t		*slist;
647852Svi117747 			uchar_t		*flist;
648852Svi117747 			size_t		ssize;
649852Svi117747 			size_t		fsize;
650852Svi117747 
651852Svi117747 			fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
652852Svi117747 			ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
653852Svi117747 			slist = kmem_alloc(ssize, KM_SLEEP);
654852Svi117747 			flist = kmem_alloc(fsize, KM_SLEEP);
655852Svi117747 			/* The clustering module frees the lists */
656852Svi117747 			sctp_get_saddr_list(sctp, slist, ssize);
657852Svi117747 			sctp_get_faddr_list(sctp, flist, fsize);
65811042SErik.Nordmark@Sun.COM 			(*cl_sctp_connect)(connp->conn_family, slist,
65911042SErik.Nordmark@Sun.COM 			    sctp->sctp_nsaddrs, connp->conn_lport,
66011042SErik.Nordmark@Sun.COM 			    flist, sctp->sctp_nfaddrs, connp->conn_fport,
661852Svi117747 			    B_TRUE, (cl_sctp_handle_t)sctp);
662852Svi117747 		}
66311042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_cred != NULL);
66411042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_ire != NULL);
66511042SErik.Nordmark@Sun.COM 
66611042SErik.Nordmark@Sun.COM 		(void) conn_ip_output(initmp, ixa);
66711042SErik.Nordmark@Sun.COM 		BUMP_LOCAL(sctp->sctp_opkts);
6680Sstevel@tonic-gate 		WAKE_SCTP(sctp);
6690Sstevel@tonic-gate 
6704818Skcpoon notify_ulp:
67111042SErik.Nordmark@Sun.COM 		sctp_set_ulp_prop(sctp);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		return (0);
6740Sstevel@tonic-gate 	default:
6750Sstevel@tonic-gate 		ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state));
6760Sstevel@tonic-gate 		WAKE_SCTP(sctp);
6770Sstevel@tonic-gate 		return (EINVAL);
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate }
680