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