1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/stream.h>
32*0Sstevel@tonic-gate #include <sys/cmn_err.h>
33*0Sstevel@tonic-gate #include <sys/kmem.h>
34*0Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
35*0Sstevel@tonic-gate #include <sys/tihdr.h>
36*0Sstevel@tonic-gate #include <sys/stropts.h>
37*0Sstevel@tonic-gate #include <sys/strsubr.h>
38*0Sstevel@tonic-gate #include <sys/socket.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <netinet/in.h>
41*0Sstevel@tonic-gate #include <netinet/ip6.h>
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include <inet/common.h>
44*0Sstevel@tonic-gate #include <inet/ip.h>
45*0Sstevel@tonic-gate #include <inet/ip6.h>
46*0Sstevel@tonic-gate #include <inet/ipclassifier.h>
47*0Sstevel@tonic-gate #include <inet/ipsec_impl.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include "sctp_impl.h"
50*0Sstevel@tonic-gate #include "sctp_addr.h"
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * Common accept code.  Called by sctp_conn_request.
54*0Sstevel@tonic-gate  * cr_pkt is the INIT / INIT ACK packet.
55*0Sstevel@tonic-gate  */
56*0Sstevel@tonic-gate static int
57*0Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt,
58*0Sstevel@tonic-gate     uint_t ip_hdr_len, sctp_init_chunk_t *iack)
59*0Sstevel@tonic-gate {
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	sctp_hdr_t		*sctph;
62*0Sstevel@tonic-gate 	sctp_chunk_hdr_t	*ich;
63*0Sstevel@tonic-gate 	sctp_init_chunk_t	*init;
64*0Sstevel@tonic-gate 	int			err;
65*0Sstevel@tonic-gate 	uint_t			sctp_options;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
68*0Sstevel@tonic-gate 	ASSERT(OK_32PTR(sctph));
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	acceptor->sctp_lport = listener->sctp_lport;
71*0Sstevel@tonic-gate 	acceptor->sctp_fport = sctph->sh_sport;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	ich = (sctp_chunk_hdr_t *)(iack + 1);
74*0Sstevel@tonic-gate 	init = (sctp_init_chunk_t *)(ich + 1);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	/* acceptor isn't in any fanouts yet, so don't need to hold locks */
77*0Sstevel@tonic-gate 	ASSERT(acceptor->sctp_faddrs == NULL);
78*0Sstevel@tonic-gate 	err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
79*0Sstevel@tonic-gate 	    &sctp_options);
80*0Sstevel@tonic-gate 	if (err != 0)
81*0Sstevel@tonic-gate 		return (err);
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
84*0Sstevel@tonic-gate 	    listener->sctp_prsctp_aware && sctp_prsctp_enabled) {
85*0Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_TRUE;
86*0Sstevel@tonic-gate 	} else {
87*0Sstevel@tonic-gate 		acceptor->sctp_prsctp_aware = B_FALSE;
88*0Sstevel@tonic-gate 	}
89*0Sstevel@tonic-gate 	/* The new sctp_t is fully bound now. */
90*0Sstevel@tonic-gate 	acceptor->sctp_connp->conn_fully_bound = B_TRUE;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	sctp_set_hdraddrs(acceptor);
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	/* Get  initial TSNs */
95*0Sstevel@tonic-gate 	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
96*0Sstevel@tonic-gate 	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
97*0Sstevel@tonic-gate 	    acceptor->sctp_ltsn - 1;
98*0Sstevel@tonic-gate 	acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd;
99*0Sstevel@tonic-gate 	/* Serial numbers are initialized to the same value as the TSNs */
100*0Sstevel@tonic-gate 	acceptor->sctp_lcsn = acceptor->sctp_ltsn;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	if (!sctp_initialize_params(acceptor, init, iack))
103*0Sstevel@tonic-gate 		return (ENOMEM);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	/*
106*0Sstevel@tonic-gate 	 * Copy sctp_secret from the listener in case we need to validate
107*0Sstevel@tonic-gate 	 * a possibly delayed cookie.
108*0Sstevel@tonic-gate 	 */
109*0Sstevel@tonic-gate 	bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN);
110*0Sstevel@tonic-gate 	bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret,
111*0Sstevel@tonic-gate 	    SCTP_SECRET_LEN);
112*0Sstevel@tonic-gate 	acceptor->sctp_last_secret_update = lbolt64;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	/*
115*0Sstevel@tonic-gate 	 * After acceptor is inserted in the hash list, it can be found.
116*0Sstevel@tonic-gate 	 * So we need to lock it here.
117*0Sstevel@tonic-gate 	 */
118*0Sstevel@tonic-gate 	RUN_SCTP(acceptor);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	sctp_conn_hash_insert(&sctp_conn_fanout[
121*0Sstevel@tonic-gate 	    SCTP_CONN_HASH(acceptor->sctp_ports)], acceptor, 0);
122*0Sstevel@tonic-gate 	sctp_bind_hash_insert(&sctp_bind_fanout[
123*0Sstevel@tonic-gate 	    SCTP_BIND_HASH(ntohs(acceptor->sctp_lport))], acceptor, 0);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	/*
126*0Sstevel@tonic-gate 	 * No need to check for multicast destination since ip will only pass
127*0Sstevel@tonic-gate 	 * up multicasts to those that have expressed interest
128*0Sstevel@tonic-gate 	 * TODO: what about rejecting broadcasts?
129*0Sstevel@tonic-gate 	 * Also check that source is not a multicast or broadcast address.
130*0Sstevel@tonic-gate 	 */
131*0Sstevel@tonic-gate 	/* XXXSCTP */
132*0Sstevel@tonic-gate 	acceptor->sctp_state = SCTPS_ESTABLISHED;
133*0Sstevel@tonic-gate 	acceptor->sctp_assoc_start_time = (uint32_t)lbolt;
134*0Sstevel@tonic-gate 	/*
135*0Sstevel@tonic-gate 	 * listener->sctp_rwnd should be the default window size or a
136*0Sstevel@tonic-gate 	 * window size changed via SO_RCVBUF option.
137*0Sstevel@tonic-gate 	 */
138*0Sstevel@tonic-gate 	acceptor->sctp_rwnd = MSS_ROUNDUP(listener->sctp_rwnd,
139*0Sstevel@tonic-gate 	    (acceptor->sctp_mss - sizeof (sctp_data_hdr_t)));
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	bcopy(&listener->sctp_upcalls, &acceptor->sctp_upcalls,
142*0Sstevel@tonic-gate 	    sizeof (sctp_upcalls_t));
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	return (0);
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */
148*0Sstevel@tonic-gate sctp_t *
149*0Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len,
150*0Sstevel@tonic-gate     sctp_init_chunk_t *iack, mblk_t *ipsec_mp)
151*0Sstevel@tonic-gate {
152*0Sstevel@tonic-gate 	sctp_t	*eager;
153*0Sstevel@tonic-gate 	uint_t	ipvers;
154*0Sstevel@tonic-gate 	ip6_t	*ip6h;
155*0Sstevel@tonic-gate 	int	err;
156*0Sstevel@tonic-gate 	conn_t	*connp, *econnp;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	/*
159*0Sstevel@tonic-gate 	 * No need to check for duplicate as this is the listener
160*0Sstevel@tonic-gate 	 * and we are holding the lock.  This means that no new
161*0Sstevel@tonic-gate 	 * connection can be created out of it.  And since the
162*0Sstevel@tonic-gate 	 * fanout already done cannot find a match, it means that
163*0Sstevel@tonic-gate 	 * there is no duplicate.
164*0Sstevel@tonic-gate 	 */
165*0Sstevel@tonic-gate 	ipvers = IPH_HDR_VERSION(mp->b_rptr);
166*0Sstevel@tonic-gate 	ASSERT(ipvers == IPV6_VERSION || ipvers == IPV4_VERSION);
167*0Sstevel@tonic-gate 	ASSERT(OK_32PTR(mp->b_rptr));
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if ((eager = sctp_create_eager(sctp)) == NULL) {
170*0Sstevel@tonic-gate 		return (NULL);
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	if (ipvers != IPV4_VERSION) {
174*0Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
175*0Sstevel@tonic-gate 		/*
176*0Sstevel@tonic-gate 		 * Record ifindex (might be zero) to tie this connection to
177*0Sstevel@tonic-gate 		 * that interface if either the listener was bound or
178*0Sstevel@tonic-gate 		 * if the connection is using link-local addresses.
179*0Sstevel@tonic-gate 		 */
180*0Sstevel@tonic-gate 		if (sctp->sctp_bound_if == ifindex ||
181*0Sstevel@tonic-gate 		    IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src))
182*0Sstevel@tonic-gate 			eager->sctp_bound_if = ifindex;
183*0Sstevel@tonic-gate 		/*
184*0Sstevel@tonic-gate 		 * XXX broken. bound_if is always overwritten by statement
185*0Sstevel@tonic-gate 		 * below. What is the right thing to do here?
186*0Sstevel@tonic-gate 		 */
187*0Sstevel@tonic-gate 		eager->sctp_bound_if = sctp->sctp_bound_if;
188*0Sstevel@tonic-gate 	}
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	connp = sctp->sctp_connp;
191*0Sstevel@tonic-gate 	econnp = eager->sctp_connp;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (connp->conn_policy != NULL) {
194*0Sstevel@tonic-gate 		ipsec_in_t *ii;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 		ASSERT(ipsec_mp != NULL);
197*0Sstevel@tonic-gate 		ii = (ipsec_in_t *)(ipsec_mp->b_rptr);
198*0Sstevel@tonic-gate 		ASSERT(ii->ipsec_in_policy == NULL);
199*0Sstevel@tonic-gate 		IPPH_REFHOLD(connp->conn_policy);
200*0Sstevel@tonic-gate 		ii->ipsec_in_policy = connp->conn_policy;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 		ipsec_mp->b_datap->db_type = IPSEC_POLICY_SET;
203*0Sstevel@tonic-gate 		if (!ip_bind_ipsec_policy_set(econnp, ipsec_mp)) {
204*0Sstevel@tonic-gate 			sctp_close_eager(eager);
205*0Sstevel@tonic-gate 			BUMP_MIB(&sctp_mib, sctpListenDrop);
206*0Sstevel@tonic-gate 			return (NULL);
207*0Sstevel@tonic-gate 		}
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	if (ipsec_mp != NULL) {
211*0Sstevel@tonic-gate 		/*
212*0Sstevel@tonic-gate 		 * XXX need to fix the cached policy issue here.
213*0Sstevel@tonic-gate 		 * We temporarily set the conn_src/conn_rem here so
214*0Sstevel@tonic-gate 		 * that IPsec can use it for the latched policy
215*0Sstevel@tonic-gate 		 * selector.  This is obvioursly wrong as SCTP can
216*0Sstevel@tonic-gate 		 * use different addresses...
217*0Sstevel@tonic-gate 		 */
218*0Sstevel@tonic-gate 		if (ipvers == IPV4_VERSION) {
219*0Sstevel@tonic-gate 			ipha_t	*ipha;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 			ipha = (ipha_t *)mp->b_rptr;
222*0Sstevel@tonic-gate 			econnp->conn_src = ipha->ipha_dst;
223*0Sstevel@tonic-gate 			econnp->conn_rem = ipha->ipha_src;
224*0Sstevel@tonic-gate 		} else {
225*0Sstevel@tonic-gate 			econnp->conn_srcv6 = ip6h->ip6_dst;
226*0Sstevel@tonic-gate 			econnp->conn_remv6 = ip6h->ip6_src;
227*0Sstevel@tonic-gate 		}
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 	if (ipsec_conn_cache_policy(econnp, ipvers == IPV4_VERSION) != 0) {
230*0Sstevel@tonic-gate 		sctp_close_eager(eager);
231*0Sstevel@tonic-gate 		BUMP_MIB(&sctp_mib, sctpListenDrop);
232*0Sstevel@tonic-gate 		return (NULL);
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack);
236*0Sstevel@tonic-gate 	if (err) {
237*0Sstevel@tonic-gate 		sctp_close_eager(eager);
238*0Sstevel@tonic-gate 		BUMP_MIB(&sctp_mib, sctpListenDrop);
239*0Sstevel@tonic-gate 		return (NULL);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/* Connection established, so send up the conn_ind */
243*0Sstevel@tonic-gate 	if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd,
244*0Sstevel@tonic-gate 	    eager)) == NULL) {
245*0Sstevel@tonic-gate 		sctp_close_eager(eager);
246*0Sstevel@tonic-gate 		BUMP_MIB(&sctp_mib, sctpListenDrop);
247*0Sstevel@tonic-gate 		return (NULL);
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 	ASSERT(SCTP_IS_DETACHED(eager));
250*0Sstevel@tonic-gate 	eager->sctp_detached = B_FALSE;
251*0Sstevel@tonic-gate 	if (eager->sctp_family == AF_INET) {
252*0Sstevel@tonic-gate 		eager->sctp_ulp_prop(eager->sctp_ulpd,
253*0Sstevel@tonic-gate 		    sctp_wroff_xtra + sizeof (sctp_data_hdr_t) +
254*0Sstevel@tonic-gate 		    sctp->sctp_hdr_len, strmsgsz);
255*0Sstevel@tonic-gate 	} else {
256*0Sstevel@tonic-gate 		eager->sctp_ulp_prop(eager->sctp_ulpd,
257*0Sstevel@tonic-gate 		    sctp_wroff_xtra + sizeof (sctp_data_hdr_t) +
258*0Sstevel@tonic-gate 		    sctp->sctp_hdr6_len, strmsgsz);
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 	return (eager);
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate /*
264*0Sstevel@tonic-gate  * Connect to a peer - this function inserts the sctp in the
265*0Sstevel@tonic-gate  * bind and conn fanouts, sends the INIT, and replies to the client
266*0Sstevel@tonic-gate  * with an OK ack.
267*0Sstevel@tonic-gate  */
268*0Sstevel@tonic-gate /* ARGSUSED */
269*0Sstevel@tonic-gate int
270*0Sstevel@tonic-gate sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen)
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate 	sin_t		*sin;
273*0Sstevel@tonic-gate 	sin6_t		*sin6;
274*0Sstevel@tonic-gate 	in_port_t	lport;
275*0Sstevel@tonic-gate 	in6_addr_t	dstaddr;
276*0Sstevel@tonic-gate 	in_port_t	dstport;
277*0Sstevel@tonic-gate 	mblk_t		*initmp;
278*0Sstevel@tonic-gate 	sctp_tf_t	*tbf;
279*0Sstevel@tonic-gate 	sctp_t		*lsctp;
280*0Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
281*0Sstevel@tonic-gate 	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
282*0Sstevel@tonic-gate 	int 		hdrlen;
283*0Sstevel@tonic-gate 	ip6_rthdr_t	*rth;
284*0Sstevel@tonic-gate 	sctp_faddr_t	*cur_fp;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	/*
287*0Sstevel@tonic-gate 	 * Determine packet type based on type of address passed in
288*0Sstevel@tonic-gate 	 * the request should contain an IPv4 or IPv6 address.
289*0Sstevel@tonic-gate 	 * Make sure that address family matches the type of
290*0Sstevel@tonic-gate 	 * family of the the address passed down
291*0Sstevel@tonic-gate 	 */
292*0Sstevel@tonic-gate 	if (addrlen < sizeof (sin_t)) {
293*0Sstevel@tonic-gate 		return (EINVAL);
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 	switch (dst->sa_family) {
296*0Sstevel@tonic-gate 	case AF_INET:
297*0Sstevel@tonic-gate 		sin = (sin_t *)dst;
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast */
300*0Sstevel@tonic-gate 		if (IN_MULTICAST(sin->sin_addr.s_addr) ||
301*0Sstevel@tonic-gate 		    (sin->sin_addr.s_addr == INADDR_BROADCAST)) {
302*0Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
303*0Sstevel@tonic-gate 			return (EINVAL);
304*0Sstevel@tonic-gate 		}
305*0Sstevel@tonic-gate 		if (sctp->sctp_connp->conn_ipv6_v6only)
306*0Sstevel@tonic-gate 			return (EAFNOSUPPORT);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 		/* convert to v6 mapped */
309*0Sstevel@tonic-gate 		/* Check for attempt to connect to INADDR_ANY */
310*0Sstevel@tonic-gate 		if (sin->sin_addr.s_addr == INADDR_ANY)  {
311*0Sstevel@tonic-gate 			struct in_addr v4_addr;
312*0Sstevel@tonic-gate 			/*
313*0Sstevel@tonic-gate 			 * SunOS 4.x and 4.3 BSD allow an application
314*0Sstevel@tonic-gate 			 * to connect a TCP socket to INADDR_ANY.
315*0Sstevel@tonic-gate 			 * When they do this, the kernel picks the
316*0Sstevel@tonic-gate 			 * address of one interface and uses it
317*0Sstevel@tonic-gate 			 * instead.  The kernel usually ends up
318*0Sstevel@tonic-gate 			 * picking the address of the loopback
319*0Sstevel@tonic-gate 			 * interface.  This is an undocumented feature.
320*0Sstevel@tonic-gate 			 * However, we provide the same thing here
321*0Sstevel@tonic-gate 			 * in case any TCP apps that use this feature
322*0Sstevel@tonic-gate 			 * are being ported to SCTP...
323*0Sstevel@tonic-gate 			 */
324*0Sstevel@tonic-gate 			v4_addr.s_addr = htonl(INADDR_LOOPBACK);
325*0Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr);
326*0Sstevel@tonic-gate 		} else {
327*0Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr);
328*0Sstevel@tonic-gate 		}
329*0Sstevel@tonic-gate 		dstport = sin->sin_port;
330*0Sstevel@tonic-gate 		if (sin->sin_family == AF_INET) {
331*0Sstevel@tonic-gate 			hdrlen = sctp->sctp_hdr_len;
332*0Sstevel@tonic-gate 		} else {
333*0Sstevel@tonic-gate 			hdrlen = sctp->sctp_hdr6_len;
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 		break;
336*0Sstevel@tonic-gate 	case AF_INET6:
337*0Sstevel@tonic-gate 		sin6 = (sin6_t *)dst;
338*0Sstevel@tonic-gate 		/* Check for attempt to connect to non-unicast. */
339*0Sstevel@tonic-gate 		if ((addrlen < sizeof (sin6_t)) ||
340*0Sstevel@tonic-gate 		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
341*0Sstevel@tonic-gate 			ip0dbg(("sctp_connect: non-unicast\n"));
342*0Sstevel@tonic-gate 			return (EINVAL);
343*0Sstevel@tonic-gate 		}
344*0Sstevel@tonic-gate 		if (sctp->sctp_connp->conn_ipv6_v6only &&
345*0Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
346*0Sstevel@tonic-gate 			return (EAFNOSUPPORT);
347*0Sstevel@tonic-gate 		}
348*0Sstevel@tonic-gate 		/* check for attempt to connect to unspec */
349*0Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
350*0Sstevel@tonic-gate 			dstaddr = ipv6_loopback;
351*0Sstevel@tonic-gate 		} else {
352*0Sstevel@tonic-gate 			dstaddr = sin6->sin6_addr;
353*0Sstevel@tonic-gate 		}
354*0Sstevel@tonic-gate 		dstport = sin6->sin6_port;
355*0Sstevel@tonic-gate 		hdrlen = sctp->sctp_hdr6_len;
356*0Sstevel@tonic-gate 		break;
357*0Sstevel@tonic-gate 	default:
358*0Sstevel@tonic-gate 		dprint(1, ("sctp_connect: unknown family %d\n",
359*0Sstevel@tonic-gate 			dst->sa_family));
360*0Sstevel@tonic-gate 		return (EAFNOSUPPORT);
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf));
364*0Sstevel@tonic-gate 	dprint(1, ("sctp_connect: attempting connect to %s...\n", buf));
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	RUN_SCTP(sctp);
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (sctp->sctp_family != dst->sa_family) {
369*0Sstevel@tonic-gate 		WAKE_SCTP(sctp);
370*0Sstevel@tonic-gate 		return (EINVAL);
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	switch (sctp->sctp_state) {
374*0Sstevel@tonic-gate 	case SCTPS_IDLE: {
375*0Sstevel@tonic-gate 		int	err;
376*0Sstevel@tonic-gate 		/*
377*0Sstevel@tonic-gate 		 * We support a quick connect capability here, allowing
378*0Sstevel@tonic-gate 		 * clients to transition directly from IDLE to COOKIE_WAIT.
379*0Sstevel@tonic-gate 		 * sctp_bindi will pick an unused port, insert the connection
380*0Sstevel@tonic-gate 		 * in the bind hash and transition to BOUND state. SCTP
381*0Sstevel@tonic-gate 		 * picks and uses what it considers the optimal local address
382*0Sstevel@tonic-gate 		 * set (just like specifiying INADDR_ANY to bind()).
383*0Sstevel@tonic-gate 		 */
384*0Sstevel@tonic-gate 		dprint(1, ("sctp_connect: idle, attempting bind...\n"));
385*0Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs == 0);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 		err = sctp_dup_saddrs(NULL, sctp, sleep);
388*0Sstevel@tonic-gate 		if (err != 0) {
389*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
390*0Sstevel@tonic-gate 			return (err);
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 		lport = sctp_update_next_port(sctp_next_port_to_try);
393*0Sstevel@tonic-gate 		lport = sctp_bindi(sctp, lport, 0, 0);
394*0Sstevel@tonic-gate 		if (lport == 0) {
395*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
396*0Sstevel@tonic-gate 			sctp_free_saddrs(sctp);
397*0Sstevel@tonic-gate 			return (EADDRNOTAVAIL);
398*0Sstevel@tonic-gate 		}
399*0Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
400*0Sstevel@tonic-gate 		/* FALLTHRU */
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	case SCTPS_BOUND:
404*0Sstevel@tonic-gate 		ASSERT(sctp->sctp_nsaddrs > 0);
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 		/* do the connect */
407*0Sstevel@tonic-gate 		/* XXX check for attempt to connect to self */
408*0Sstevel@tonic-gate 		sctp->sctp_fport = dstport;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		ASSERT(sctp->sctp_iphc);
411*0Sstevel@tonic-gate 		ASSERT(sctp->sctp_iphc6);
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 		/*
414*0Sstevel@tonic-gate 		 * Don't allow this connection to completely duplicate
415*0Sstevel@tonic-gate 		 * an existing connection.
416*0Sstevel@tonic-gate 		 *
417*0Sstevel@tonic-gate 		 * Ensure that the duplicate check and insertion is atomic.
418*0Sstevel@tonic-gate 		 */
419*0Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
420*0Sstevel@tonic-gate 		tbf = &sctp_conn_fanout[SCTP_CONN_HASH(sctp->sctp_ports)];
421*0Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
422*0Sstevel@tonic-gate 		lsctp = sctp_lookup(sctp, &dstaddr, tbf, &sctp->sctp_ports,
423*0Sstevel@tonic-gate 		    SCTPS_COOKIE_WAIT);
424*0Sstevel@tonic-gate 		if (lsctp != NULL) {
425*0Sstevel@tonic-gate 			/* found a duplicate connection */
426*0Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
427*0Sstevel@tonic-gate 			SCTP_REFRELE(lsctp);
428*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
429*0Sstevel@tonic-gate 			return (EADDRINUSE);
430*0Sstevel@tonic-gate 		}
431*0Sstevel@tonic-gate 		/*
432*0Sstevel@tonic-gate 		 * OK; set up the peer addr (this may grow after we get
433*0Sstevel@tonic-gate 		 * the INIT ACK from the peer with additional addresses).
434*0Sstevel@tonic-gate 		 */
435*0Sstevel@tonic-gate 		if (sctp_add_faddr(sctp, &dstaddr, sleep) < 0) {
436*0Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
437*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
438*0Sstevel@tonic-gate 			return (ENOMEM);
439*0Sstevel@tonic-gate 		}
440*0Sstevel@tonic-gate 		/* No valid src addr, return. */
441*0Sstevel@tonic-gate 		if (sctp->sctp_faddrs->state == SCTP_FADDRS_UNREACH) {
442*0Sstevel@tonic-gate 			mutex_exit(&tbf->tf_lock);
443*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
444*0Sstevel@tonic-gate 			return (EADDRNOTAVAIL);
445*0Sstevel@tonic-gate 		}
446*0Sstevel@tonic-gate 		sctp->sctp_primary = sctp->sctp_faddrs;
447*0Sstevel@tonic-gate 		sctp->sctp_current = sctp->sctp_faddrs;
448*0Sstevel@tonic-gate 		cur_fp = sctp->sctp_current;
449*0Sstevel@tonic-gate 		sctp->sctp_mss = sctp->sctp_faddrs->sfa_pmss;
450*0Sstevel@tonic-gate 		sctp_conn_hash_insert(tbf, sctp, 1);
451*0Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 		/* initialize composite headers */
454*0Sstevel@tonic-gate 		sctp_set_hdraddrs(sctp);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 		/*
457*0Sstevel@tonic-gate 		 * Massage a routing header (if present) putting the first hop
458*0Sstevel@tonic-gate 		 * in ip6_dst.
459*0Sstevel@tonic-gate 		 */
460*0Sstevel@tonic-gate 		rth = ip_find_rthdr_v6(sctp->sctp_ip6h,
461*0Sstevel@tonic-gate 		    (uint8_t *)sctp->sctp_sctph6);
462*0Sstevel@tonic-gate 		if (rth != NULL)
463*0Sstevel@tonic-gate 			(void) ip_massage_options_v6(sctp->sctp_ip6h, rth);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		/*
466*0Sstevel@tonic-gate 		 * Turn off the don't fragment bit on the (only) faddr,
467*0Sstevel@tonic-gate 		 * so that if one of the messages exchanged during the
468*0Sstevel@tonic-gate 		 * initialization sequence exceeds the path mtu, it
469*0Sstevel@tonic-gate 		 * at least has a chance to get there. SCTP does no
470*0Sstevel@tonic-gate 		 * fragmentation of initialization messages.  The DF bit
471*0Sstevel@tonic-gate 		 * will be turned on again in sctp_send_cookie_echo()
472*0Sstevel@tonic-gate 		 * (but the cookie echo will still be sent with the df bit
473*0Sstevel@tonic-gate 		 * off).
474*0Sstevel@tonic-gate 		 */
475*0Sstevel@tonic-gate 		cur_fp->df = B_FALSE;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 		/* Mark this address as alive */
478*0Sstevel@tonic-gate 		cur_fp->state = SCTP_FADDRS_ALIVE;
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 		/* This sctp_t is fully bound now. */
481*0Sstevel@tonic-gate 		sctp->sctp_connp->conn_fully_bound = B_TRUE;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 		/* Send the INIT to the peer */
484*0Sstevel@tonic-gate 		SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto);
485*0Sstevel@tonic-gate 		initmp = sctp_init_mp(sctp);
486*0Sstevel@tonic-gate 		if (initmp == NULL) {
487*0Sstevel@tonic-gate 			WAKE_SCTP(sctp);
488*0Sstevel@tonic-gate 			/* let timer retry */
489*0Sstevel@tonic-gate 			return (0);
490*0Sstevel@tonic-gate 		}
491*0Sstevel@tonic-gate 		sctp->sctp_state = SCTPS_COOKIE_WAIT;
492*0Sstevel@tonic-gate 		WAKE_SCTP(sctp);
493*0Sstevel@tonic-gate 		/* OK to call IP_PUT() here instead of sctp_add_sendq(). */
494*0Sstevel@tonic-gate 		CONN_INC_REF(sctp->sctp_connp);
495*0Sstevel@tonic-gate 		initmp->b_flag |= MSGHASREF;
496*0Sstevel@tonic-gate 		IP_PUT(initmp, sctp->sctp_connp, sctp->sctp_current->isv4);
497*0Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_opkts);
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 		sctp->sctp_ulp_prop(sctp->sctp_ulpd,
500*0Sstevel@tonic-gate 		    sctp_wroff_xtra + hdrlen + sizeof (sctp_data_hdr_t), 0);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 		return (0);
503*0Sstevel@tonic-gate 	default:
504*0Sstevel@tonic-gate 		ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state));
505*0Sstevel@tonic-gate 		WAKE_SCTP(sctp);
506*0Sstevel@tonic-gate 		return (EINVAL);
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate }
509