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 /*
23*f4b3ec61Sdh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/systm.h>
317c478bd9Sstevel@tonic-gate #include <sys/stream.h>
327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
337c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
347c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
357c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
367c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
377c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
387c478bd9Sstevel@tonic-gate #include <sys/socket.h>
3945916cd2Sjpk #include <sys/tsol/tndb.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <netinet/in.h>
427c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <inet/common.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip.h>
467c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
477c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
487c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
517c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Common accept code.  Called by sctp_conn_request.
557c478bd9Sstevel@tonic-gate  * cr_pkt is the INIT / INIT ACK packet.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate static int
587c478bd9Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt,
597c478bd9Sstevel@tonic-gate     uint_t ip_hdr_len, sctp_init_chunk_t *iack)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	sctp_hdr_t		*sctph;
637c478bd9Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ich;
647c478bd9Sstevel@tonic-gate 	sctp_init_chunk_t	*init;
657c478bd9Sstevel@tonic-gate 	int			err;
667c478bd9Sstevel@tonic-gate 	uint_t			sctp_options;
67d7ab25acSkp 	conn_t			*aconnp;
6845916cd2Sjpk 	conn_t			*lconnp;
6945916cd2Sjpk 	cred_t			*cr;
70*f4b3ec61Sdh 	sctp_stack_t	*sctps = listener->sctp_sctps;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
737c478bd9Sstevel@tonic-gate 	ASSERT(OK_32PTR(sctph));
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	acceptor->sctp_lport = listener->sctp_lport;
767c478bd9Sstevel@tonic-gate 	acceptor->sctp_fport = sctph->sh_sport;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	ich = (sctp_chunk_hdr_t *)(iack + 1);
797c478bd9Sstevel@tonic-gate 	init = (sctp_init_chunk_t *)(ich + 1);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/* acceptor isn't in any fanouts yet, so don't need to hold locks */
827c478bd9Sstevel@tonic-gate 	ASSERT(acceptor->sctp_faddrs == NULL);
837c478bd9Sstevel@tonic-gate 	err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
847c478bd9Sstevel@tonic-gate 	    &sctp_options);
857c478bd9Sstevel@tonic-gate 	if (err != 0)
867c478bd9Sstevel@tonic-gate 		return (err);
877c478bd9Sstevel@tonic-gate 
88d7ab25acSkp 	aconnp = acceptor->sctp_connp;
8945916cd2Sjpk 	lconnp = listener->sctp_connp;
9045916cd2Sjpk 	if (lconnp->conn_mlp_type != mlptSingle) {
91d7ab25acSkp 		cr = aconnp->conn_peercred = DB_CRED(cr_pkt);
9245916cd2Sjpk 		if (cr != NULL)
9345916cd2Sjpk 			crhold(cr);
9445916cd2Sjpk 	}
9545916cd2Sjpk 
9677c67f2fSkcpoon 	if ((err = sctp_set_hdraddrs(acceptor)) != 0)
9745916cd2Sjpk 		return (err);
9845916cd2Sjpk 
997c478bd9Sstevel@tonic-gate 	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
100*f4b3ec61Sdh 	    listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) {
1017c478bd9Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_TRUE;
1027c478bd9Sstevel@tonic-gate 	} else {
1037c478bd9Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_FALSE;
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 	/* The new sctp_t is fully bound now. */
1067c478bd9Sstevel@tonic-gate 	acceptor->sctp_connp->conn_fully_bound = B_TRUE;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/* Get  initial TSNs */
1097c478bd9Sstevel@tonic-gate 	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
1107c478bd9Sstevel@tonic-gate 	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
1117c478bd9Sstevel@tonic-gate 	    acceptor->sctp_ltsn - 1;
1127c478bd9Sstevel@tonic-gate 	acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd;
1137c478bd9Sstevel@tonic-gate 	/* Serial numbers are initialized to the same value as the TSNs */
1147c478bd9Sstevel@tonic-gate 	acceptor->sctp_lcsn = acceptor->sctp_ltsn;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if (!sctp_initialize_params(acceptor, init, iack))
1177c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/*
1207c478bd9Sstevel@tonic-gate 	 * Copy sctp_secret from the listener in case we need to validate
1217c478bd9Sstevel@tonic-gate 	 * a possibly delayed cookie.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN);
1247c478bd9Sstevel@tonic-gate 	bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret,
1257c478bd9Sstevel@tonic-gate 	    SCTP_SECRET_LEN);
1267c478bd9Sstevel@tonic-gate 	acceptor->sctp_last_secret_update = lbolt64;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/*
1297c478bd9Sstevel@tonic-gate 	 * After acceptor is inserted in the hash list, it can be found.
1307c478bd9Sstevel@tonic-gate 	 * So we need to lock it here.
1317c478bd9Sstevel@tonic-gate 	 */
1327c478bd9Sstevel@tonic-gate 	RUN_SCTP(acceptor);
1337c478bd9Sstevel@tonic-gate 
134*f4b3ec61Sdh 	sctp_conn_hash_insert(&sctps->sctps_conn_fanout[
135*f4b3ec61Sdh 	    SCTP_CONN_HASH(sctps, acceptor->sctp_ports)], acceptor, 0);
136*f4b3ec61Sdh 	sctp_bind_hash_insert(&sctps->sctps_bind_fanout[
1377c478bd9Sstevel@tonic-gate 	    SCTP_BIND_HASH(ntohs(acceptor->sctp_lport))], acceptor, 0);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/*
1407c478bd9Sstevel@tonic-gate 	 * No need to check for multicast destination since ip will only pass
1417c478bd9Sstevel@tonic-gate 	 * up multicasts to those that have expressed interest
1427c478bd9Sstevel@tonic-gate 	 * TODO: what about rejecting broadcasts?
1437c478bd9Sstevel@tonic-gate 	 * Also check that source is not a multicast or broadcast address.
1447c478bd9Sstevel@tonic-gate 	 */
1457c478bd9Sstevel@tonic-gate 	/* XXXSCTP */
1467c478bd9Sstevel@tonic-gate 	acceptor->sctp_state = SCTPS_ESTABLISHED;
1477c478bd9Sstevel@tonic-gate 	acceptor->sctp_assoc_start_time = (uint32_t)lbolt;
1487c478bd9Sstevel@tonic-gate 	/*
1497c478bd9Sstevel@tonic-gate 	 * listener->sctp_rwnd should be the default window size or a
1507c478bd9Sstevel@tonic-gate 	 * window size changed via SO_RCVBUF option.
1517c478bd9Sstevel@tonic-gate 	 */
1521d8c4025Svi 	acceptor->sctp_rwnd = listener->sctp_rwnd;
1531d8c4025Svi 	acceptor->sctp_irwnd = acceptor->sctp_rwnd;
1547c478bd9Sstevel@tonic-gate 	bcopy(&listener->sctp_upcalls, &acceptor->sctp_upcalls,
1557c478bd9Sstevel@tonic-gate 	    sizeof (sctp_upcalls_t));
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	return (0);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */
1617c478bd9Sstevel@tonic-gate sctp_t *
1627c478bd9Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len,
1637c478bd9Sstevel@tonic-gate     sctp_init_chunk_t *iack, mblk_t *ipsec_mp)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	sctp_t	*eager;
1667c478bd9Sstevel@tonic-gate 	uint_t	ipvers;
1677c478bd9Sstevel@tonic-gate 	ip6_t	*ip6h;
1687c478bd9Sstevel@tonic-gate 	int	err;
1697c478bd9Sstevel@tonic-gate 	conn_t	*connp, *econnp;
170*f4b3ec61Sdh 	sctp_stack_t	*sctps;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * No need to check for duplicate as this is the listener
1747c478bd9Sstevel@tonic-gate 	 * and we are holding the lock.  This means that no new
1757c478bd9Sstevel@tonic-gate 	 * connection can be created out of it.  And since the
1767c478bd9Sstevel@tonic-gate 	 * fanout already done cannot find a match, it means that
1777c478bd9Sstevel@tonic-gate 	 * there is no duplicate.
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	ipvers = IPH_HDR_VERSION(mp->b_rptr);
1807c478bd9Sstevel@tonic-gate 	ASSERT(ipvers == IPV6_VERSION || ipvers == IPV4_VERSION);
1817c478bd9Sstevel@tonic-gate 	ASSERT(OK_32PTR(mp->b_rptr));
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if ((eager = sctp_create_eager(sctp)) == NULL) {
1847c478bd9Sstevel@tonic-gate 		return (NULL);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (ipvers != IPV4_VERSION) {
1887c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
189f551bb10Svi 		if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src))
190f551bb10Svi 			eager->sctp_linklocal = 1;
1917c478bd9Sstevel@tonic-gate 		/*
1927c478bd9Sstevel@tonic-gate 		 * Record ifindex (might be zero) to tie this connection to
1937c478bd9Sstevel@tonic-gate 		 * that interface if either the listener was bound or
1947c478bd9Sstevel@tonic-gate 		 * if the connection is using link-local addresses.
1957c478bd9Sstevel@tonic-gate 		 */
1967c478bd9Sstevel@tonic-gate 		if (sctp->sctp_bound_if == ifindex ||
1977c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src))
1987c478bd9Sstevel@tonic-gate 			eager->sctp_bound_if = ifindex;
1997c478bd9Sstevel@tonic-gate 		/*
2007c478bd9Sstevel@tonic-gate 		 * XXX broken. bound_if is always overwritten by statement
2017c478bd9Sstevel@tonic-gate 		 * below. What is the right thing to do here?
2027c478bd9Sstevel@tonic-gate 		 */
2037c478bd9Sstevel@tonic-gate 		eager->sctp_bound_if = sctp->sctp_bound_if;
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	connp = sctp->sctp_connp;
207*f4b3ec61Sdh 	sctps = sctp->sctp_sctps;
2087c478bd9Sstevel@tonic-gate 	econnp = eager->sctp_connp;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (connp->conn_policy != NULL) {
2117c478bd9Sstevel@tonic-gate 		ipsec_in_t *ii;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 		ASSERT(ipsec_mp != NULL);
2147c478bd9Sstevel@tonic-gate 		ii = (ipsec_in_t *)(ipsec_mp->b_rptr);
2157c478bd9Sstevel@tonic-gate 		ASSERT(ii->ipsec_in_policy == NULL);
2167c478bd9Sstevel@tonic-gate 		IPPH_REFHOLD(connp->conn_policy);
2177c478bd9Sstevel@tonic-gate 		ii->ipsec_in_policy = connp->conn_policy;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		ipsec_mp->b_datap->db_type = IPSEC_POLICY_SET;
2207c478bd9Sstevel@tonic-gate 		if (!ip_bind_ipsec_policy_set(econnp, ipsec_mp)) {
2217c478bd9Sstevel@tonic-gate 			sctp_close_eager(eager);
222*f4b3ec61Sdh 			BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
2237c478bd9Sstevel@tonic-gate 			return (NULL);
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (ipsec_mp != NULL) {
2287c478bd9Sstevel@tonic-gate 		/*
2297c478bd9Sstevel@tonic-gate 		 * XXX need to fix the cached policy issue here.
2307c478bd9Sstevel@tonic-gate 		 * We temporarily set the conn_src/conn_rem here so
2317c478bd9Sstevel@tonic-gate 		 * that IPsec can use it for the latched policy
2327c478bd9Sstevel@tonic-gate 		 * selector.  This is obvioursly wrong as SCTP can
2337c478bd9Sstevel@tonic-gate 		 * use different addresses...
2347c478bd9Sstevel@tonic-gate 		 */
2357c478bd9Sstevel@tonic-gate 		if (ipvers == IPV4_VERSION) {
2367c478bd9Sstevel@tonic-gate 			ipha_t	*ipha;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 			ipha = (ipha_t *)mp->b_rptr;
2397c478bd9Sstevel@tonic-gate 			econnp->conn_src = ipha->ipha_dst;
2407c478bd9Sstevel@tonic-gate 			econnp->conn_rem = ipha->ipha_src;
2417c478bd9Sstevel@tonic-gate 		} else {
2427c478bd9Sstevel@tonic-gate 			econnp->conn_srcv6 = ip6h->ip6_dst;
2437c478bd9Sstevel@tonic-gate 			econnp->conn_remv6 = ip6h->ip6_src;
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	if (ipsec_conn_cache_policy(econnp, ipvers == IPV4_VERSION) != 0) {
2477c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
248*f4b3ec61Sdh 		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
2497c478bd9Sstevel@tonic-gate 		return (NULL);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack);
2537c478bd9Sstevel@tonic-gate 	if (err) {
2547c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
255*f4b3ec61Sdh 		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
2567c478bd9Sstevel@tonic-gate 		return (NULL);
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2591d8c4025Svi 	/*
2601d8c4025Svi 	 * On a clustered note send this notification to the clustering
2611d8c4025Svi 	 * subsystem.
2621d8c4025Svi 	 */
2631d8c4025Svi 	if (cl_sctp_connect != NULL) {
2641d8c4025Svi 		uchar_t	*slist;
2651d8c4025Svi 		uchar_t	*flist;
2661d8c4025Svi 		size_t	fsize;
2671d8c4025Svi 		size_t	ssize;
2681d8c4025Svi 
2691d8c4025Svi 		fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs;
2701d8c4025Svi 		ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs;
2711d8c4025Svi 		slist = kmem_alloc(ssize, KM_NOSLEEP);
2721d8c4025Svi 		flist = kmem_alloc(fsize, KM_NOSLEEP);
2731d8c4025Svi 		if (slist == NULL || flist == NULL) {
2741d8c4025Svi 			if (slist != NULL)
2751d8c4025Svi 				kmem_free(slist, ssize);
2761d8c4025Svi 			if (flist != NULL)
2771d8c4025Svi 				kmem_free(flist, fsize);
2781d8c4025Svi 			sctp_close_eager(eager);
279*f4b3ec61Sdh 			BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
280*f4b3ec61Sdh 			SCTP_KSTAT(sctps, sctp_cl_connect);
2811d8c4025Svi 			return (NULL);
2821d8c4025Svi 		}
2831d8c4025Svi 		/* The clustering module frees these list */
2841d8c4025Svi 		sctp_get_saddr_list(eager, slist, ssize);
2851d8c4025Svi 		sctp_get_faddr_list(eager, flist, fsize);
2861d8c4025Svi 		(*cl_sctp_connect)(eager->sctp_family, slist,
2871d8c4025Svi 		    eager->sctp_nsaddrs, eager->sctp_lport, flist,
2881d8c4025Svi 		    eager->sctp_nfaddrs, eager->sctp_fport, B_FALSE,
2891d8c4025Svi 		    (cl_sctp_handle_t)eager);
2901d8c4025Svi 	}
2911d8c4025Svi 
2927c478bd9Sstevel@tonic-gate 	/* Connection established, so send up the conn_ind */
2937c478bd9Sstevel@tonic-gate 	if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd,
2947c478bd9Sstevel@tonic-gate 	    eager)) == NULL) {
2957c478bd9Sstevel@tonic-gate 		sctp_close_eager(eager);
296*f4b3ec61Sdh 		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
2977c478bd9Sstevel@tonic-gate 		return (NULL);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	ASSERT(SCTP_IS_DETACHED(eager));
3007c478bd9Sstevel@tonic-gate 	eager->sctp_detached = B_FALSE;
3017c478bd9Sstevel@tonic-gate 	if (eager->sctp_family == AF_INET) {
3027c478bd9Sstevel@tonic-gate 		eager->sctp_ulp_prop(eager->sctp_ulpd,
303*f4b3ec61Sdh 		    sctps->sctps_wroff_xtra + sizeof (sctp_data_hdr_t) +
3047c478bd9Sstevel@tonic-gate 		    sctp->sctp_hdr_len, strmsgsz);
3057c478bd9Sstevel@tonic-gate 	} else {
3067c478bd9Sstevel@tonic-gate 		eager->sctp_ulp_prop(eager->sctp_ulpd,
307*f4b3ec61Sdh 		    sctps->sctps_wroff_xtra + sizeof (sctp_data_hdr_t) +
3087c478bd9Sstevel@tonic-gate 		    sctp->sctp_hdr6_len, strmsgsz);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	return (eager);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Connect to a peer - this function inserts the sctp in the
3157c478bd9Sstevel@tonic-gate  * bind and conn fanouts, sends the INIT, and replies to the client
3167c478bd9Sstevel@tonic-gate  * with an OK ack.
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate int
3197c478bd9Sstevel@tonic-gate sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	sin_t		*sin;
3227c478bd9Sstevel@tonic-gate 	sin6_t		*sin6;
3237c478bd9Sstevel@tonic-gate 	in6_addr_t	dstaddr;
3247c478bd9Sstevel@tonic-gate 	in_port_t	dstport;
3257c478bd9Sstevel@tonic-gate 	mblk_t		*initmp;
3267c478bd9Sstevel@tonic-gate 	sctp_tf_t	*tbf;
3277c478bd9Sstevel@tonic-gate 	sctp_t		*lsctp;
3287c478bd9Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
3297c478bd9Sstevel@tonic-gate 	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
3307c478bd9Sstevel@tonic-gate 	int 		hdrlen;
3317c478bd9Sstevel@tonic-gate 	ip6_rthdr_t	*rth;
33245916cd2Sjpk 	int		err;
3337c478bd9Sstevel@tonic-gate 	sctp_faddr_t	*cur_fp;
334*f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * Determine packet type based on type of address passed in
3387c478bd9Sstevel@tonic-gate 	 * the request should contain an IPv4 or IPv6 address.
3397c478bd9Sstevel@tonic-gate 	 * Make sure that address family matches the type of
3407c478bd9Sstevel@tonic-gate 	 * family of the the address passed down
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	if (addrlen < sizeof (sin_t)) {
3437c478bd9Sstevel@tonic-gate 		return (EINVAL);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	switch (dst->sa_family) {
3467c478bd9Sstevel@tonic-gate 	case AF_INET:
3477c478bd9Sstevel@tonic-gate 		sin = (sin_t *)dst;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast */
3507c478bd9Sstevel@tonic-gate 		if (IN_MULTICAST(sin->sin_addr.s_addr) ||
3517c478bd9Sstevel@tonic-gate 		    (sin->sin_addr.s_addr == INADDR_BROADCAST)) {
3527c478bd9Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
3537c478bd9Sstevel@tonic-gate 			return (EINVAL);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 		if (sctp->sctp_connp->conn_ipv6_v6only)
3567c478bd9Sstevel@tonic-gate 			return (EAFNOSUPPORT);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		/* convert to v6 mapped */
3597c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to INADDR_ANY */
3607c478bd9Sstevel@tonic-gate 		if (sin->sin_addr.s_addr == INADDR_ANY)  {
3617c478bd9Sstevel@tonic-gate 			struct in_addr v4_addr;
3627c478bd9Sstevel@tonic-gate 			/*
3637c478bd9Sstevel@tonic-gate 			 * SunOS 4.x and 4.3 BSD allow an application
3647c478bd9Sstevel@tonic-gate 			 * to connect a TCP socket to INADDR_ANY.
3657c478bd9Sstevel@tonic-gate 			 * When they do this, the kernel picks the
3667c478bd9Sstevel@tonic-gate 			 * address of one interface and uses it
3677c478bd9Sstevel@tonic-gate 			 * instead.  The kernel usually ends up
3687c478bd9Sstevel@tonic-gate 			 * picking the address of the loopback
3697c478bd9Sstevel@tonic-gate 			 * interface.  This is an undocumented feature.
3707c478bd9Sstevel@tonic-gate 			 * However, we provide the same thing here
3717c478bd9Sstevel@tonic-gate 			 * in case any TCP apps that use this feature
3727c478bd9Sstevel@tonic-gate 			 * are being ported to SCTP...
3737c478bd9Sstevel@tonic-gate 			 */
3747c478bd9Sstevel@tonic-gate 			v4_addr.s_addr = htonl(INADDR_LOOPBACK);
3757c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr);
3767c478bd9Sstevel@tonic-gate 		} else {
3777c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr);
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 		dstport = sin->sin_port;
3807c478bd9Sstevel@tonic-gate 		if (sin->sin_family == AF_INET) {
3817c478bd9Sstevel@tonic-gate 			hdrlen = sctp->sctp_hdr_len;
3827c478bd9Sstevel@tonic-gate 		} else {
3837c478bd9Sstevel@tonic-gate 			hdrlen = sctp->sctp_hdr6_len;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 		break;
3867c478bd9Sstevel@tonic-gate 	case AF_INET6:
3877c478bd9Sstevel@tonic-gate 		sin6 = (sin6_t *)dst;
3887c478bd9Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast. */
3897c478bd9Sstevel@tonic-gate 		if ((addrlen < sizeof (sin6_t)) ||
3907c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
3917c478bd9Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
3927c478bd9Sstevel@tonic-gate 			return (EINVAL);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 		if (sctp->sctp_connp->conn_ipv6_v6only &&
3957c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3967c478bd9Sstevel@tonic-gate 			return (EAFNOSUPPORT);
3977c478bd9Sstevel@tonic-gate 		}
3987c478bd9Sstevel@tonic-gate 		/* check for attempt to connect to unspec */
3997c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4007c478bd9Sstevel@tonic-gate 			dstaddr = ipv6_loopback;
4017c478bd9Sstevel@tonic-gate 		} else {
4027c478bd9Sstevel@tonic-gate 			dstaddr = sin6->sin6_addr;
403f551bb10Svi 			if (IN6_IS_ADDR_LINKLOCAL(&dstaddr))
404f551bb10Svi 				sctp->sctp_linklocal = 1;
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 		dstport = sin6->sin6_port;
4077c478bd9Sstevel@tonic-gate 		hdrlen = sctp->sctp_hdr6_len;
4087c478bd9Sstevel@tonic-gate 		break;
4097c478bd9Sstevel@tonic-gate 	default:
4107c478bd9Sstevel@tonic-gate 		dprint(1, ("sctp_connect: unknown family %d\n",
4117c478bd9Sstevel@tonic-gate 			dst->sa_family));
4127c478bd9Sstevel@tonic-gate 		return (EAFNOSUPPORT);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf));
4167c478bd9Sstevel@tonic-gate 	dprint(1, ("sctp_connect: attempting connect to %s...\n", buf));
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	RUN_SCTP(sctp);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (sctp->sctp_family != dst->sa_family) {
4217c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
4227c478bd9Sstevel@tonic-gate 		return (EINVAL);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	switch (sctp->sctp_state) {
4267c478bd9Sstevel@tonic-gate 	case SCTPS_IDLE: {
4271d8c4025Svi 		struct sockaddr_storage	ss;
4281d8c4025Svi 
4297c478bd9Sstevel@tonic-gate 		/*
4307c478bd9Sstevel@tonic-gate 		 * We support a quick connect capability here, allowing
4317c478bd9Sstevel@tonic-gate 		 * clients to transition directly from IDLE to COOKIE_WAIT.
4327c478bd9Sstevel@tonic-gate 		 * sctp_bindi will pick an unused port, insert the connection
4337c478bd9Sstevel@tonic-gate 		 * in the bind hash and transition to BOUND state. SCTP
4347c478bd9Sstevel@tonic-gate 		 * picks and uses what it considers the optimal local address
4357c478bd9Sstevel@tonic-gate 		 * set (just like specifiying INADDR_ANY to bind()).
4367c478bd9Sstevel@tonic-gate 		 */
4377c478bd9Sstevel@tonic-gate 		dprint(1, ("sctp_connect: idle, attempting bind...\n"));
4387c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs == 0);
4397c478bd9Sstevel@tonic-gate 
4401d8c4025Svi 		bzero(&ss, sizeof (ss));
4411d8c4025Svi 		ss.ss_family = sctp->sctp_family;
4421d8c4025Svi 		WAKE_SCTP(sctp);
4431d8c4025Svi 		if ((err = sctp_bind(sctp, (struct sockaddr *)&ss,
4441d8c4025Svi 		    sizeof (ss))) != 0) {
4457c478bd9Sstevel@tonic-gate 			return (err);
4467c478bd9Sstevel@tonic-gate 		}
4471d8c4025Svi 		RUN_SCTP(sctp);
4487c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
4497c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	case SCTPS_BOUND:
4537c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs > 0);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 		/* do the connect */
4567c478bd9Sstevel@tonic-gate 		/* XXX check for attempt to connect to self */
4577c478bd9Sstevel@tonic-gate 		sctp->sctp_fport = dstport;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_iphc);
4607c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_iphc6);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 		/*
4637c478bd9Sstevel@tonic-gate 		 * Don't allow this connection to completely duplicate
4647c478bd9Sstevel@tonic-gate 		 * an existing connection.
4657c478bd9Sstevel@tonic-gate 		 *
4667c478bd9Sstevel@tonic-gate 		 * Ensure that the duplicate check and insertion is atomic.
4677c478bd9Sstevel@tonic-gate 		 */
4687c478bd9Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
469*f4b3ec61Sdh 		tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps,
470*f4b3ec61Sdh 						    sctp->sctp_ports)];
4717c478bd9Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
4727c478bd9Sstevel@tonic-gate 		lsctp = sctp_lookup(sctp, &dstaddr, tbf, &sctp->sctp_ports,
4737c478bd9Sstevel@tonic-gate 		    SCTPS_COOKIE_WAIT);
4747c478bd9Sstevel@tonic-gate 		if (lsctp != NULL) {
4757c478bd9Sstevel@tonic-gate 			/* found a duplicate connection */
4767c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
4777c478bd9Sstevel@tonic-gate 			SCTP_REFRELE(lsctp);
4787c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
4797c478bd9Sstevel@tonic-gate 			return (EADDRINUSE);
4807c478bd9Sstevel@tonic-gate 		}
4817c478bd9Sstevel@tonic-gate 		/*
4827c478bd9Sstevel@tonic-gate 		 * OK; set up the peer addr (this may grow after we get
4837c478bd9Sstevel@tonic-gate 		 * the INIT ACK from the peer with additional addresses).
4847c478bd9Sstevel@tonic-gate 		 */
48577c67f2fSkcpoon 		if ((err = sctp_add_faddr(sctp, &dstaddr, sleep,
48677c67f2fSkcpoon 		    B_FALSE)) != 0) {
4877c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
4887c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
48945916cd2Sjpk 			return (err);
4907c478bd9Sstevel@tonic-gate 		}
4917c478bd9Sstevel@tonic-gate 		/* No valid src addr, return. */
4927c478bd9Sstevel@tonic-gate 		if (sctp->sctp_faddrs->state == SCTP_FADDRS_UNREACH) {
4937c478bd9Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
4947c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
4957c478bd9Sstevel@tonic-gate 			return (EADDRNOTAVAIL);
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 		sctp->sctp_primary = sctp->sctp_faddrs;
4987c478bd9Sstevel@tonic-gate 		sctp->sctp_current = sctp->sctp_faddrs;
4997c478bd9Sstevel@tonic-gate 		cur_fp = sctp->sctp_current;
5007c478bd9Sstevel@tonic-gate 		sctp->sctp_mss = sctp->sctp_faddrs->sfa_pmss;
5017c478bd9Sstevel@tonic-gate 		sctp_conn_hash_insert(tbf, sctp, 1);
5027c478bd9Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		/* initialize composite headers */
50577c67f2fSkcpoon 		if ((err = sctp_set_hdraddrs(sctp)) != 0) {
50645916cd2Sjpk 			sctp_conn_hash_remove(sctp);
50745916cd2Sjpk 			WAKE_SCTP(sctp);
50845916cd2Sjpk 			return (err);
50945916cd2Sjpk 		}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		/*
5127c478bd9Sstevel@tonic-gate 		 * Massage a routing header (if present) putting the first hop
5137c478bd9Sstevel@tonic-gate 		 * in ip6_dst.
5147c478bd9Sstevel@tonic-gate 		 */
5157c478bd9Sstevel@tonic-gate 		rth = ip_find_rthdr_v6(sctp->sctp_ip6h,
5167c478bd9Sstevel@tonic-gate 		    (uint8_t *)sctp->sctp_sctph6);
517*f4b3ec61Sdh 		if (rth != NULL) {
518*f4b3ec61Sdh 			(void) ip_massage_options_v6(sctp->sctp_ip6h, rth,
519*f4b3ec61Sdh 			    sctps->sctps_netstack);
520*f4b3ec61Sdh 		}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 		/*
5237c478bd9Sstevel@tonic-gate 		 * Turn off the don't fragment bit on the (only) faddr,
5247c478bd9Sstevel@tonic-gate 		 * so that if one of the messages exchanged during the
5257c478bd9Sstevel@tonic-gate 		 * initialization sequence exceeds the path mtu, it
5267c478bd9Sstevel@tonic-gate 		 * at least has a chance to get there. SCTP does no
5277c478bd9Sstevel@tonic-gate 		 * fragmentation of initialization messages.  The DF bit
5287c478bd9Sstevel@tonic-gate 		 * will be turned on again in sctp_send_cookie_echo()
5297c478bd9Sstevel@tonic-gate 		 * (but the cookie echo will still be sent with the df bit
5307c478bd9Sstevel@tonic-gate 		 * off).
5317c478bd9Sstevel@tonic-gate 		 */
5327c478bd9Sstevel@tonic-gate 		cur_fp->df = B_FALSE;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		/* Mark this address as alive */
5357c478bd9Sstevel@tonic-gate 		cur_fp->state = SCTP_FADDRS_ALIVE;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		/* This sctp_t is fully bound now. */
5387c478bd9Sstevel@tonic-gate 		sctp->sctp_connp->conn_fully_bound = B_TRUE;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		/* Send the INIT to the peer */
5417c478bd9Sstevel@tonic-gate 		SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto);
542f551bb10Svi 		/*
543f551bb10Svi 		 * sctp_init_mp() could result in modifying the source
544f551bb10Svi 		 * address list, so take the hash lock.
545f551bb10Svi 		 */
546f551bb10Svi 		mutex_enter(&tbf->tf_lock);
5477c478bd9Sstevel@tonic-gate 		initmp = sctp_init_mp(sctp);
5487c478bd9Sstevel@tonic-gate 		if (initmp == NULL) {
549f551bb10Svi 			mutex_exit(&tbf->tf_lock);
5507c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
5517c478bd9Sstevel@tonic-gate 			/* let timer retry */
5527c478bd9Sstevel@tonic-gate 			return (0);
5537c478bd9Sstevel@tonic-gate 		}
554f551bb10Svi 		mutex_exit(&tbf->tf_lock);
5557c478bd9Sstevel@tonic-gate 		sctp->sctp_state = SCTPS_COOKIE_WAIT;
5561d8c4025Svi 		/*
5571d8c4025Svi 		 * On a clustered note send this notification to the clustering
5581d8c4025Svi 		 * subsystem.
5591d8c4025Svi 		 */
5601d8c4025Svi 		if (cl_sctp_connect != NULL) {
5611d8c4025Svi 			uchar_t		*slist;
5621d8c4025Svi 			uchar_t		*flist;
5631d8c4025Svi 			size_t		ssize;
5641d8c4025Svi 			size_t		fsize;
5651d8c4025Svi 
5661d8c4025Svi 			fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
5671d8c4025Svi 			ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
5681d8c4025Svi 			slist = kmem_alloc(ssize, KM_SLEEP);
5691d8c4025Svi 			flist = kmem_alloc(fsize, KM_SLEEP);
5701d8c4025Svi 			/* The clustering module frees the lists */
5711d8c4025Svi 			sctp_get_saddr_list(sctp, slist, ssize);
5721d8c4025Svi 			sctp_get_faddr_list(sctp, flist, fsize);
5731d8c4025Svi 			(*cl_sctp_connect)(sctp->sctp_family, slist,
5741d8c4025Svi 			    sctp->sctp_nsaddrs, sctp->sctp_lport,
5751d8c4025Svi 			    flist, sctp->sctp_nfaddrs, sctp->sctp_fport,
5761d8c4025Svi 			    B_TRUE, (cl_sctp_handle_t)sctp);
5771d8c4025Svi 		}
5787c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
5797c478bd9Sstevel@tonic-gate 		/* OK to call IP_PUT() here instead of sctp_add_sendq(). */
5807c478bd9Sstevel@tonic-gate 		CONN_INC_REF(sctp->sctp_connp);
5817c478bd9Sstevel@tonic-gate 		initmp->b_flag |= MSGHASREF;
5827c478bd9Sstevel@tonic-gate 		IP_PUT(initmp, sctp->sctp_connp, sctp->sctp_current->isv4);
5837c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_opkts);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		sctp->sctp_ulp_prop(sctp->sctp_ulpd,
586*f4b3ec61Sdh 		    sctps->sctps_wroff_xtra + hdrlen + sizeof (sctp_data_hdr_t),
587*f4b3ec61Sdh 		    0);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		return (0);
5907c478bd9Sstevel@tonic-gate 	default:
5917c478bd9Sstevel@tonic-gate 		ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state));
5927c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
5937c478bd9Sstevel@tonic-gate 		return (EINVAL);
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate }
596