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 /* 23*11849SErik.Nordmark@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/systm.h> 290Sstevel@tonic-gate #include <sys/stream.h> 300Sstevel@tonic-gate #include <sys/cmn_err.h> 310Sstevel@tonic-gate #include <sys/kmem.h> 320Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 330Sstevel@tonic-gate #include <sys/tihdr.h> 340Sstevel@tonic-gate #include <sys/stropts.h> 350Sstevel@tonic-gate #include <sys/strsubr.h> 360Sstevel@tonic-gate #include <sys/socket.h> 371676Sjpk #include <sys/tsol/tndb.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include <netinet/in.h> 400Sstevel@tonic-gate #include <netinet/ip6.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <inet/common.h> 430Sstevel@tonic-gate #include <inet/ip.h> 440Sstevel@tonic-gate #include <inet/ip6.h> 450Sstevel@tonic-gate #include <inet/ipclassifier.h> 460Sstevel@tonic-gate #include <inet/ipsec_impl.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include "sctp_impl.h" 490Sstevel@tonic-gate #include "sctp_addr.h" 500Sstevel@tonic-gate 510Sstevel@tonic-gate /* 520Sstevel@tonic-gate * Common accept code. Called by sctp_conn_request. 530Sstevel@tonic-gate * cr_pkt is the INIT / INIT ACK packet. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate static int 560Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, 570Sstevel@tonic-gate uint_t ip_hdr_len, sctp_init_chunk_t *iack) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate 600Sstevel@tonic-gate sctp_hdr_t *sctph; 610Sstevel@tonic-gate sctp_chunk_hdr_t *ich; 620Sstevel@tonic-gate sctp_init_chunk_t *init; 630Sstevel@tonic-gate int err; 640Sstevel@tonic-gate uint_t sctp_options; 652776Skp158701 conn_t *aconnp; 661676Sjpk conn_t *lconnp; 673448Sdh155122 sctp_stack_t *sctps = listener->sctp_sctps; 680Sstevel@tonic-gate 690Sstevel@tonic-gate sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len); 700Sstevel@tonic-gate ASSERT(OK_32PTR(sctph)); 710Sstevel@tonic-gate 7211042SErik.Nordmark@Sun.COM aconnp = acceptor->sctp_connp; 7311042SErik.Nordmark@Sun.COM lconnp = listener->sctp_connp; 7411042SErik.Nordmark@Sun.COM aconnp->conn_lport = lconnp->conn_lport; 7511042SErik.Nordmark@Sun.COM aconnp->conn_fport = sctph->sh_sport; 760Sstevel@tonic-gate 770Sstevel@tonic-gate ich = (sctp_chunk_hdr_t *)(iack + 1); 780Sstevel@tonic-gate init = (sctp_init_chunk_t *)(ich + 1); 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* acceptor isn't in any fanouts yet, so don't need to hold locks */ 810Sstevel@tonic-gate ASSERT(acceptor->sctp_faddrs == NULL); 820Sstevel@tonic-gate err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich, 830Sstevel@tonic-gate &sctp_options); 840Sstevel@tonic-gate if (err != 0) 850Sstevel@tonic-gate return (err); 860Sstevel@tonic-gate 871735Skcpoon if ((err = sctp_set_hdraddrs(acceptor)) != 0) 881676Sjpk return (err); 891676Sjpk 9011042SErik.Nordmark@Sun.COM if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0) 9111042SErik.Nordmark@Sun.COM return (err); 9211042SErik.Nordmark@Sun.COM 930Sstevel@tonic-gate if ((sctp_options & SCTP_PRSCTP_OPTION) && 943448Sdh155122 listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 950Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_TRUE; 960Sstevel@tonic-gate } else { 970Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_FALSE; 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* Get initial TSNs */ 1010Sstevel@tonic-gate acceptor->sctp_ltsn = ntohl(iack->sic_inittsn); 1020Sstevel@tonic-gate acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd = 1030Sstevel@tonic-gate acceptor->sctp_ltsn - 1; 1040Sstevel@tonic-gate acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd; 1050Sstevel@tonic-gate /* Serial numbers are initialized to the same value as the TSNs */ 1060Sstevel@tonic-gate acceptor->sctp_lcsn = acceptor->sctp_ltsn; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate if (!sctp_initialize_params(acceptor, init, iack)) 1090Sstevel@tonic-gate return (ENOMEM); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * Copy sctp_secret from the listener in case we need to validate 1130Sstevel@tonic-gate * a possibly delayed cookie. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN); 1160Sstevel@tonic-gate bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret, 1170Sstevel@tonic-gate SCTP_SECRET_LEN); 11811066Srafael.vanoni@sun.com acceptor->sctp_last_secret_update = ddi_get_lbolt64(); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * After acceptor is inserted in the hash list, it can be found. 1220Sstevel@tonic-gate * So we need to lock it here. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate RUN_SCTP(acceptor); 1250Sstevel@tonic-gate 1263448Sdh155122 sctp_conn_hash_insert(&sctps->sctps_conn_fanout[ 12711042SErik.Nordmark@Sun.COM SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0); 1283448Sdh155122 sctp_bind_hash_insert(&sctps->sctps_bind_fanout[ 12911042SErik.Nordmark@Sun.COM SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0); 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * No need to check for multicast destination since ip will only pass 1330Sstevel@tonic-gate * up multicasts to those that have expressed interest 1340Sstevel@tonic-gate * TODO: what about rejecting broadcasts? 1350Sstevel@tonic-gate * Also check that source is not a multicast or broadcast address. 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate /* XXXSCTP */ 1380Sstevel@tonic-gate acceptor->sctp_state = SCTPS_ESTABLISHED; 13911066Srafael.vanoni@sun.com acceptor->sctp_assoc_start_time = (uint32_t)ddi_get_lbolt(); 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * listener->sctp_rwnd should be the default window size or a 1420Sstevel@tonic-gate * window size changed via SO_RCVBUF option. 1430Sstevel@tonic-gate */ 144852Svi117747 acceptor->sctp_rwnd = listener->sctp_rwnd; 145852Svi117747 acceptor->sctp_irwnd = acceptor->sctp_rwnd; 1463845Svi117747 acceptor->sctp_pd_point = acceptor->sctp_rwnd; 1478348SEric.Yu@Sun.COM acceptor->sctp_upcalls = listener->sctp_upcalls; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate return (0); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */ 1530Sstevel@tonic-gate sctp_t * 1540Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len, 15511042SErik.Nordmark@Sun.COM sctp_init_chunk_t *iack, ip_recv_attr_t *ira) 1560Sstevel@tonic-gate { 1570Sstevel@tonic-gate sctp_t *eager; 1580Sstevel@tonic-gate ip6_t *ip6h; 1590Sstevel@tonic-gate int err; 1600Sstevel@tonic-gate conn_t *connp, *econnp; 1613448Sdh155122 sctp_stack_t *sctps; 1628348SEric.Yu@Sun.COM struct sock_proto_props sopp; 1638778SErik.Nordmark@Sun.COM cred_t *cr; 1648778SErik.Nordmark@Sun.COM pid_t cpid; 16511042SErik.Nordmark@Sun.COM in6_addr_t faddr, laddr; 16611042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate /* 1690Sstevel@tonic-gate * No need to check for duplicate as this is the listener 1700Sstevel@tonic-gate * and we are holding the lock. This means that no new 1710Sstevel@tonic-gate * connection can be created out of it. And since the 1720Sstevel@tonic-gate * fanout already done cannot find a match, it means that 1730Sstevel@tonic-gate * there is no duplicate. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if ((eager = sctp_create_eager(sctp)) == NULL) { 1780Sstevel@tonic-gate return (NULL); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate connp = sctp->sctp_connp; 1823448Sdh155122 sctps = sctp->sctp_sctps; 1830Sstevel@tonic-gate econnp = eager->sctp_connp; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate if (connp->conn_policy != NULL) { 18611042SErik.Nordmark@Sun.COM /* Inherit the policy from the listener; use actions from ira */ 18711042SErik.Nordmark@Sun.COM if (!ip_ipsec_policy_inherit(econnp, connp, ira)) { 1880Sstevel@tonic-gate sctp_close_eager(eager); 1893448Sdh155122 BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 1900Sstevel@tonic-gate return (NULL); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 19411042SErik.Nordmark@Sun.COM ip6h = (ip6_t *)mp->b_rptr; 19511042SErik.Nordmark@Sun.COM if (ira->ira_flags & IXAF_IS_IPV4) { 19611042SErik.Nordmark@Sun.COM ipha_t *ipha; 19711042SErik.Nordmark@Sun.COM 19811042SErik.Nordmark@Sun.COM ipha = (ipha_t *)ip6h; 19911042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr); 20011042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr); 20111042SErik.Nordmark@Sun.COM } else { 20211042SErik.Nordmark@Sun.COM laddr = ip6h->ip6_dst; 20311042SErik.Nordmark@Sun.COM faddr = ip6h->ip6_src; 20411042SErik.Nordmark@Sun.COM } 20511042SErik.Nordmark@Sun.COM 20611042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_IPSEC_SECURE) { 2070Sstevel@tonic-gate /* 2080Sstevel@tonic-gate * XXX need to fix the cached policy issue here. 20911042SErik.Nordmark@Sun.COM * We temporarily set the conn_laddr/conn_faddr here so 2100Sstevel@tonic-gate * that IPsec can use it for the latched policy 2110Sstevel@tonic-gate * selector. This is obvioursly wrong as SCTP can 2120Sstevel@tonic-gate * use different addresses... 2130Sstevel@tonic-gate */ 21411042SErik.Nordmark@Sun.COM econnp->conn_laddr_v6 = laddr; 21511042SErik.Nordmark@Sun.COM econnp->conn_faddr_v6 = faddr; 21611042SErik.Nordmark@Sun.COM econnp->conn_saddr_v6 = laddr; 2170Sstevel@tonic-gate } 21811042SErik.Nordmark@Sun.COM if (ipsec_conn_cache_policy(econnp, 21911042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) { 2200Sstevel@tonic-gate sctp_close_eager(eager); 2213448Sdh155122 BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2220Sstevel@tonic-gate return (NULL); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2258778SErik.Nordmark@Sun.COM /* Save for getpeerucred */ 22611042SErik.Nordmark@Sun.COM cr = ira->ira_cred; 22711042SErik.Nordmark@Sun.COM cpid = ira->ira_cpid; 22811042SErik.Nordmark@Sun.COM 22911042SErik.Nordmark@Sun.COM if (is_system_labeled()) { 23011042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = econnp->conn_ixa; 23111042SErik.Nordmark@Sun.COM 23211042SErik.Nordmark@Sun.COM ASSERT(ira->ira_tsl != NULL); 23311042SErik.Nordmark@Sun.COM 23411042SErik.Nordmark@Sun.COM /* Discard any old label */ 23511042SErik.Nordmark@Sun.COM if (ixa->ixa_free_flags & IXA_FREE_TSL) { 23611042SErik.Nordmark@Sun.COM ASSERT(ixa->ixa_tsl != NULL); 23711042SErik.Nordmark@Sun.COM label_rele(ixa->ixa_tsl); 23811042SErik.Nordmark@Sun.COM ixa->ixa_free_flags &= ~IXA_FREE_TSL; 23911042SErik.Nordmark@Sun.COM ixa->ixa_tsl = NULL; 24011042SErik.Nordmark@Sun.COM } 24111042SErik.Nordmark@Sun.COM 24211042SErik.Nordmark@Sun.COM if ((connp->conn_mlp_type != mlptSingle || 24311042SErik.Nordmark@Sun.COM connp->conn_mac_mode != CONN_MAC_DEFAULT) && 24411042SErik.Nordmark@Sun.COM ira->ira_tsl != NULL) { 24511042SErik.Nordmark@Sun.COM /* 24611042SErik.Nordmark@Sun.COM * If this is an MLP connection or a MAC-Exempt 24711042SErik.Nordmark@Sun.COM * connection with an unlabeled node, packets are to be 24811042SErik.Nordmark@Sun.COM * exchanged using the security label of the received 24911042SErik.Nordmark@Sun.COM * Cookie packet instead of the server application's 25011042SErik.Nordmark@Sun.COM * label. 25111042SErik.Nordmark@Sun.COM * tsol_check_dest called from ip_set_destination 25211042SErik.Nordmark@Sun.COM * might later update TSF_UNLABELED by replacing 25311042SErik.Nordmark@Sun.COM * ixa_tsl with a new label. 25411042SErik.Nordmark@Sun.COM */ 25511042SErik.Nordmark@Sun.COM label_hold(ira->ira_tsl); 25611042SErik.Nordmark@Sun.COM ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl); 25711042SErik.Nordmark@Sun.COM } else { 25811042SErik.Nordmark@Sun.COM ixa->ixa_tsl = crgetlabel(econnp->conn_cred); 25911042SErik.Nordmark@Sun.COM } 26011042SErik.Nordmark@Sun.COM } 2618778SErik.Nordmark@Sun.COM 2620Sstevel@tonic-gate err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack); 26311042SErik.Nordmark@Sun.COM if (err != 0) { 2640Sstevel@tonic-gate sctp_close_eager(eager); 2653448Sdh155122 BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2660Sstevel@tonic-gate return (NULL); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 26911042SErik.Nordmark@Sun.COM ASSERT(eager->sctp_current->ixa != NULL); 27011042SErik.Nordmark@Sun.COM 27111042SErik.Nordmark@Sun.COM ixa = eager->sctp_current->ixa; 27211042SErik.Nordmark@Sun.COM if (!(ira->ira_flags & IXAF_IS_IPV4)) { 27311042SErik.Nordmark@Sun.COM ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4)); 27411042SErik.Nordmark@Sun.COM 27511042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) || 27611042SErik.Nordmark@Sun.COM IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) { 27711042SErik.Nordmark@Sun.COM eager->sctp_linklocal = 1; 27811042SErik.Nordmark@Sun.COM 27911042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_SCOPEID_SET; 28011042SErik.Nordmark@Sun.COM ixa->ixa_scopeid = ifindex; 28111042SErik.Nordmark@Sun.COM econnp->conn_incoming_ifindex = ifindex; 28211042SErik.Nordmark@Sun.COM } 28311042SErik.Nordmark@Sun.COM } 28411042SErik.Nordmark@Sun.COM 285852Svi117747 /* 286852Svi117747 * On a clustered note send this notification to the clustering 287852Svi117747 * subsystem. 288852Svi117747 */ 289852Svi117747 if (cl_sctp_connect != NULL) { 290852Svi117747 uchar_t *slist; 291852Svi117747 uchar_t *flist; 292852Svi117747 size_t fsize; 293852Svi117747 size_t ssize; 294852Svi117747 295852Svi117747 fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs; 296852Svi117747 ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs; 297852Svi117747 slist = kmem_alloc(ssize, KM_NOSLEEP); 298852Svi117747 flist = kmem_alloc(fsize, KM_NOSLEEP); 299852Svi117747 if (slist == NULL || flist == NULL) { 300852Svi117747 if (slist != NULL) 301852Svi117747 kmem_free(slist, ssize); 302852Svi117747 if (flist != NULL) 303852Svi117747 kmem_free(flist, fsize); 304852Svi117747 sctp_close_eager(eager); 3053448Sdh155122 BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 3063448Sdh155122 SCTP_KSTAT(sctps, sctp_cl_connect); 307852Svi117747 return (NULL); 308852Svi117747 } 309852Svi117747 /* The clustering module frees these list */ 310852Svi117747 sctp_get_saddr_list(eager, slist, ssize); 311852Svi117747 sctp_get_faddr_list(eager, flist, fsize); 31211042SErik.Nordmark@Sun.COM (*cl_sctp_connect)(econnp->conn_family, slist, 31311042SErik.Nordmark@Sun.COM eager->sctp_nsaddrs, econnp->conn_lport, flist, 31411042SErik.Nordmark@Sun.COM eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE, 315852Svi117747 (cl_sctp_handle_t)eager); 316852Svi117747 } 317852Svi117747 3180Sstevel@tonic-gate /* Connection established, so send up the conn_ind */ 3190Sstevel@tonic-gate if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd, 3208778SErik.Nordmark@Sun.COM (sock_lower_handle_t)eager, NULL, cr, cpid, 3218348SEric.Yu@Sun.COM &eager->sctp_upcalls)) == NULL) { 3220Sstevel@tonic-gate sctp_close_eager(eager); 3233448Sdh155122 BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 3240Sstevel@tonic-gate return (NULL); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate ASSERT(SCTP_IS_DETACHED(eager)); 3270Sstevel@tonic-gate eager->sctp_detached = B_FALSE; 3288348SEric.Yu@Sun.COM bzero(&sopp, sizeof (sopp)); 3298348SEric.Yu@Sun.COM sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF; 3308348SEric.Yu@Sun.COM sopp.sopp_maxblk = strmsgsz; 33111042SErik.Nordmark@Sun.COM if (econnp->conn_family == AF_INET) { 3328348SEric.Yu@Sun.COM sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3338348SEric.Yu@Sun.COM sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len; 3340Sstevel@tonic-gate } else { 3358348SEric.Yu@Sun.COM sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3368348SEric.Yu@Sun.COM sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len; 3370Sstevel@tonic-gate } 3388348SEric.Yu@Sun.COM eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp); 3390Sstevel@tonic-gate return (eager); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Connect to a peer - this function inserts the sctp in the 3440Sstevel@tonic-gate * bind and conn fanouts, sends the INIT, and replies to the client 3450Sstevel@tonic-gate * with an OK ack. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate int 34811042SErik.Nordmark@Sun.COM sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen, 34911042SErik.Nordmark@Sun.COM cred_t *cr, pid_t pid) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate sin_t *sin; 3520Sstevel@tonic-gate sin6_t *sin6; 3530Sstevel@tonic-gate in6_addr_t dstaddr; 3540Sstevel@tonic-gate in_port_t dstport; 3550Sstevel@tonic-gate mblk_t *initmp; 3560Sstevel@tonic-gate sctp_tf_t *tbf; 3570Sstevel@tonic-gate sctp_t *lsctp; 3580Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 3590Sstevel@tonic-gate int sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP; 3601676Sjpk int err; 3610Sstevel@tonic-gate sctp_faddr_t *cur_fp; 3623448Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 36311042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp; 36411042SErik.Nordmark@Sun.COM uint_t scope_id = 0; 36511042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * Determine packet type based on type of address passed in 3690Sstevel@tonic-gate * the request should contain an IPv4 or IPv6 address. 3700Sstevel@tonic-gate * Make sure that address family matches the type of 37111042SErik.Nordmark@Sun.COM * family of the address passed down. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate if (addrlen < sizeof (sin_t)) { 3740Sstevel@tonic-gate return (EINVAL); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate switch (dst->sa_family) { 3770Sstevel@tonic-gate case AF_INET: 3780Sstevel@tonic-gate sin = (sin_t *)dst; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* Check for attempt to connect to non-unicast */ 3815215Skcpoon if (CLASSD(sin->sin_addr.s_addr) || 3820Sstevel@tonic-gate (sin->sin_addr.s_addr == INADDR_BROADCAST)) { 3830Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 3840Sstevel@tonic-gate return (EINVAL); 3850Sstevel@tonic-gate } 38611042SErik.Nordmark@Sun.COM if (connp->conn_ipv6_v6only) 3870Sstevel@tonic-gate return (EAFNOSUPPORT); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* convert to v6 mapped */ 3900Sstevel@tonic-gate /* Check for attempt to connect to INADDR_ANY */ 3910Sstevel@tonic-gate if (sin->sin_addr.s_addr == INADDR_ANY) { 3920Sstevel@tonic-gate struct in_addr v4_addr; 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * SunOS 4.x and 4.3 BSD allow an application 3950Sstevel@tonic-gate * to connect a TCP socket to INADDR_ANY. 3960Sstevel@tonic-gate * When they do this, the kernel picks the 3970Sstevel@tonic-gate * address of one interface and uses it 3980Sstevel@tonic-gate * instead. The kernel usually ends up 3990Sstevel@tonic-gate * picking the address of the loopback 4000Sstevel@tonic-gate * interface. This is an undocumented feature. 4010Sstevel@tonic-gate * However, we provide the same thing here 4020Sstevel@tonic-gate * in case any TCP apps that use this feature 4030Sstevel@tonic-gate * are being ported to SCTP... 4040Sstevel@tonic-gate */ 4050Sstevel@tonic-gate v4_addr.s_addr = htonl(INADDR_LOOPBACK); 4060Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr); 4070Sstevel@tonic-gate } else { 4080Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate dstport = sin->sin_port; 4110Sstevel@tonic-gate break; 4120Sstevel@tonic-gate case AF_INET6: 4130Sstevel@tonic-gate sin6 = (sin6_t *)dst; 4140Sstevel@tonic-gate /* Check for attempt to connect to non-unicast. */ 4150Sstevel@tonic-gate if ((addrlen < sizeof (sin6_t)) || 4160Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 4170Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 4180Sstevel@tonic-gate return (EINVAL); 4190Sstevel@tonic-gate } 42011042SErik.Nordmark@Sun.COM if (connp->conn_ipv6_v6only && 4210Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 4220Sstevel@tonic-gate return (EAFNOSUPPORT); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate /* check for attempt to connect to unspec */ 4250Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4260Sstevel@tonic-gate dstaddr = ipv6_loopback; 4270Sstevel@tonic-gate } else { 4280Sstevel@tonic-gate dstaddr = sin6->sin6_addr; 42911042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) { 430432Svi117747 sctp->sctp_linklocal = 1; 43111042SErik.Nordmark@Sun.COM scope_id = sin6->sin6_scope_id; 43211042SErik.Nordmark@Sun.COM } 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate dstport = sin6->sin6_port; 43511042SErik.Nordmark@Sun.COM connp->conn_flowinfo = sin6->sin6_flowinfo; 4360Sstevel@tonic-gate break; 4370Sstevel@tonic-gate default: 4380Sstevel@tonic-gate dprint(1, ("sctp_connect: unknown family %d\n", 4394505Skcpoon dst->sa_family)); 4400Sstevel@tonic-gate return (EAFNOSUPPORT); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf)); 4440Sstevel@tonic-gate dprint(1, ("sctp_connect: attempting connect to %s...\n", buf)); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate RUN_SCTP(sctp); 4470Sstevel@tonic-gate 44811042SErik.Nordmark@Sun.COM if (connp->conn_family != dst->sa_family || 44911042SErik.Nordmark@Sun.COM (connp->conn_state_flags & CONN_CLOSING)) { 4500Sstevel@tonic-gate WAKE_SCTP(sctp); 4510Sstevel@tonic-gate return (EINVAL); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 45411042SErik.Nordmark@Sun.COM /* We update our cred/cpid based on the caller of connect */ 45511042SErik.Nordmark@Sun.COM if (connp->conn_cred != cr) { 45611042SErik.Nordmark@Sun.COM crhold(cr); 45711042SErik.Nordmark@Sun.COM crfree(connp->conn_cred); 45811042SErik.Nordmark@Sun.COM connp->conn_cred = cr; 45911042SErik.Nordmark@Sun.COM } 46011042SErik.Nordmark@Sun.COM connp->conn_cpid = pid; 46111042SErik.Nordmark@Sun.COM 46211042SErik.Nordmark@Sun.COM /* Cache things in conn_ixa without any refhold */ 46311042SErik.Nordmark@Sun.COM ixa = connp->conn_ixa; 464*11849SErik.Nordmark@Sun.COM ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED)); 46511042SErik.Nordmark@Sun.COM ixa->ixa_cred = cr; 46611042SErik.Nordmark@Sun.COM ixa->ixa_cpid = pid; 46711042SErik.Nordmark@Sun.COM if (is_system_labeled()) { 46811042SErik.Nordmark@Sun.COM /* We need to restart with a label based on the cred */ 46911042SErik.Nordmark@Sun.COM ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred); 47011042SErik.Nordmark@Sun.COM } 47111042SErik.Nordmark@Sun.COM 4720Sstevel@tonic-gate switch (sctp->sctp_state) { 4730Sstevel@tonic-gate case SCTPS_IDLE: { 474852Svi117747 struct sockaddr_storage ss; 475852Svi117747 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * We support a quick connect capability here, allowing 4780Sstevel@tonic-gate * clients to transition directly from IDLE to COOKIE_WAIT. 4790Sstevel@tonic-gate * sctp_bindi will pick an unused port, insert the connection 4800Sstevel@tonic-gate * in the bind hash and transition to BOUND state. SCTP 4810Sstevel@tonic-gate * picks and uses what it considers the optimal local address 4820Sstevel@tonic-gate * set (just like specifiying INADDR_ANY to bind()). 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate dprint(1, ("sctp_connect: idle, attempting bind...\n")); 4850Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs == 0); 4860Sstevel@tonic-gate 487852Svi117747 bzero(&ss, sizeof (ss)); 48811042SErik.Nordmark@Sun.COM ss.ss_family = connp->conn_family; 489852Svi117747 WAKE_SCTP(sctp); 490852Svi117747 if ((err = sctp_bind(sctp, (struct sockaddr *)&ss, 491852Svi117747 sizeof (ss))) != 0) { 4920Sstevel@tonic-gate return (err); 4930Sstevel@tonic-gate } 494852Svi117747 RUN_SCTP(sctp); 4950Sstevel@tonic-gate /* FALLTHRU */ 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate case SCTPS_BOUND: 4990Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs > 0); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* do the connect */ 5020Sstevel@tonic-gate /* XXX check for attempt to connect to self */ 50311042SErik.Nordmark@Sun.COM connp->conn_fport = dstport; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate ASSERT(sctp->sctp_iphc); 5060Sstevel@tonic-gate ASSERT(sctp->sctp_iphc6); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * Don't allow this connection to completely duplicate 5100Sstevel@tonic-gate * an existing connection. 5110Sstevel@tonic-gate * 5120Sstevel@tonic-gate * Ensure that the duplicate check and insertion is atomic. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 5153448Sdh155122 tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, 51611042SErik.Nordmark@Sun.COM connp->conn_ports)]; 5170Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 51811042SErik.Nordmark@Sun.COM lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports, 5190Sstevel@tonic-gate SCTPS_COOKIE_WAIT); 5200Sstevel@tonic-gate if (lsctp != NULL) { 5210Sstevel@tonic-gate /* found a duplicate connection */ 5220Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5230Sstevel@tonic-gate SCTP_REFRELE(lsctp); 5240Sstevel@tonic-gate WAKE_SCTP(sctp); 5250Sstevel@tonic-gate return (EADDRINUSE); 5260Sstevel@tonic-gate } 52711042SErik.Nordmark@Sun.COM 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * OK; set up the peer addr (this may grow after we get 5300Sstevel@tonic-gate * the INIT ACK from the peer with additional addresses). 5310Sstevel@tonic-gate */ 5321735Skcpoon if ((err = sctp_add_faddr(sctp, &dstaddr, sleep, 5331735Skcpoon B_FALSE)) != 0) { 5340Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5350Sstevel@tonic-gate WAKE_SCTP(sctp); 5361676Sjpk return (err); 5370Sstevel@tonic-gate } 5384818Skcpoon cur_fp = sctp->sctp_faddrs; 53911042SErik.Nordmark@Sun.COM ASSERT(cur_fp->ixa != NULL); 5404818Skcpoon 5410Sstevel@tonic-gate /* No valid src addr, return. */ 5424818Skcpoon if (cur_fp->state == SCTP_FADDRS_UNREACH) { 5430Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5440Sstevel@tonic-gate WAKE_SCTP(sctp); 5450Sstevel@tonic-gate return (EADDRNOTAVAIL); 5460Sstevel@tonic-gate } 5474818Skcpoon 5484818Skcpoon sctp->sctp_primary = cur_fp; 5494818Skcpoon sctp->sctp_current = cur_fp; 5504818Skcpoon sctp->sctp_mss = cur_fp->sfa_pmss; 5510Sstevel@tonic-gate sctp_conn_hash_insert(tbf, sctp, 1); 5520Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5530Sstevel@tonic-gate 55411042SErik.Nordmark@Sun.COM ixa = cur_fp->ixa; 55511042SErik.Nordmark@Sun.COM ASSERT(ixa->ixa_cred != NULL); 55611042SErik.Nordmark@Sun.COM 55711042SErik.Nordmark@Sun.COM if (scope_id != 0) { 55811042SErik.Nordmark@Sun.COM ixa->ixa_flags |= IXAF_SCOPEID_SET; 55911042SErik.Nordmark@Sun.COM ixa->ixa_scopeid = scope_id; 56011042SErik.Nordmark@Sun.COM } else { 56111042SErik.Nordmark@Sun.COM ixa->ixa_flags &= ~IXAF_SCOPEID_SET; 56211042SErik.Nordmark@Sun.COM } 56311042SErik.Nordmark@Sun.COM 5640Sstevel@tonic-gate /* initialize composite headers */ 5651735Skcpoon if ((err = sctp_set_hdraddrs(sctp)) != 0) { 5661676Sjpk sctp_conn_hash_remove(sctp); 5671676Sjpk WAKE_SCTP(sctp); 5681676Sjpk return (err); 5691676Sjpk } 5700Sstevel@tonic-gate 57111042SErik.Nordmark@Sun.COM if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) { 57211042SErik.Nordmark@Sun.COM sctp_conn_hash_remove(sctp); 57311042SErik.Nordmark@Sun.COM WAKE_SCTP(sctp); 57411042SErik.Nordmark@Sun.COM return (err); 5753448Sdh155122 } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * Turn off the don't fragment bit on the (only) faddr, 5790Sstevel@tonic-gate * so that if one of the messages exchanged during the 5800Sstevel@tonic-gate * initialization sequence exceeds the path mtu, it 5810Sstevel@tonic-gate * at least has a chance to get there. SCTP does no 5820Sstevel@tonic-gate * fragmentation of initialization messages. The DF bit 5830Sstevel@tonic-gate * will be turned on again in sctp_send_cookie_echo() 5840Sstevel@tonic-gate * (but the cookie echo will still be sent with the df bit 5850Sstevel@tonic-gate * off). 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate cur_fp->df = B_FALSE; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* Mark this address as alive */ 5900Sstevel@tonic-gate cur_fp->state = SCTP_FADDRS_ALIVE; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* Send the INIT to the peer */ 5930Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto); 5944818Skcpoon sctp->sctp_state = SCTPS_COOKIE_WAIT; 595432Svi117747 /* 596432Svi117747 * sctp_init_mp() could result in modifying the source 597432Svi117747 * address list, so take the hash lock. 598432Svi117747 */ 599432Svi117747 mutex_enter(&tbf->tf_lock); 60011042SErik.Nordmark@Sun.COM initmp = sctp_init_mp(sctp, cur_fp); 6010Sstevel@tonic-gate if (initmp == NULL) { 602432Svi117747 mutex_exit(&tbf->tf_lock); 6034818Skcpoon /* 6044818Skcpoon * It may happen that all the source addresses 6054818Skcpoon * (loopback/link local) are removed. In that case, 6064818Skcpoon * faile the connect. 6074818Skcpoon */ 6084818Skcpoon if (sctp->sctp_nsaddrs == 0) { 6094818Skcpoon sctp_conn_hash_remove(sctp); 6104818Skcpoon SCTP_FADDR_TIMER_STOP(cur_fp); 6114818Skcpoon WAKE_SCTP(sctp); 6124818Skcpoon return (EADDRNOTAVAIL); 6134818Skcpoon } 6144818Skcpoon 6154818Skcpoon /* Otherwise, let the retransmission timer retry */ 6160Sstevel@tonic-gate WAKE_SCTP(sctp); 6174818Skcpoon goto notify_ulp; 6180Sstevel@tonic-gate } 619432Svi117747 mutex_exit(&tbf->tf_lock); 6204818Skcpoon 621852Svi117747 /* 622852Svi117747 * On a clustered note send this notification to the clustering 623852Svi117747 * subsystem. 624852Svi117747 */ 625852Svi117747 if (cl_sctp_connect != NULL) { 626852Svi117747 uchar_t *slist; 627852Svi117747 uchar_t *flist; 628852Svi117747 size_t ssize; 629852Svi117747 size_t fsize; 630852Svi117747 631852Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 632852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 633852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 634852Svi117747 flist = kmem_alloc(fsize, KM_SLEEP); 635852Svi117747 /* The clustering module frees the lists */ 636852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 637852Svi117747 sctp_get_faddr_list(sctp, flist, fsize); 63811042SErik.Nordmark@Sun.COM (*cl_sctp_connect)(connp->conn_family, slist, 63911042SErik.Nordmark@Sun.COM sctp->sctp_nsaddrs, connp->conn_lport, 64011042SErik.Nordmark@Sun.COM flist, sctp->sctp_nfaddrs, connp->conn_fport, 641852Svi117747 B_TRUE, (cl_sctp_handle_t)sctp); 642852Svi117747 } 64311042SErik.Nordmark@Sun.COM ASSERT(ixa->ixa_cred != NULL); 64411042SErik.Nordmark@Sun.COM ASSERT(ixa->ixa_ire != NULL); 64511042SErik.Nordmark@Sun.COM 64611042SErik.Nordmark@Sun.COM (void) conn_ip_output(initmp, ixa); 64711042SErik.Nordmark@Sun.COM BUMP_LOCAL(sctp->sctp_opkts); 6480Sstevel@tonic-gate WAKE_SCTP(sctp); 6490Sstevel@tonic-gate 6504818Skcpoon notify_ulp: 65111042SErik.Nordmark@Sun.COM sctp_set_ulp_prop(sctp); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate return (0); 6540Sstevel@tonic-gate default: 6550Sstevel@tonic-gate ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state)); 6560Sstevel@tonic-gate WAKE_SCTP(sctp); 6570Sstevel@tonic-gate return (EINVAL); 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate } 660