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 /* 23de8c4a14SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/systm.h> 297c478bd9Sstevel@tonic-gate #include <sys/stream.h> 307c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 317c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 327c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 337c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 347c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 367c478bd9Sstevel@tonic-gate #include <sys/socket.h> 3745916cd2Sjpk #include <sys/tsol/tndb.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <inet/common.h> 437c478bd9Sstevel@tonic-gate #include <inet/ip.h> 447c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 457c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 467c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 497c478bd9Sstevel@tonic-gate #include "sctp_addr.h" 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * Common accept code. Called by sctp_conn_request. 537c478bd9Sstevel@tonic-gate * cr_pkt is the INIT / INIT ACK packet. 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate static int 567c478bd9Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, 577c478bd9Sstevel@tonic-gate uint_t ip_hdr_len, sctp_init_chunk_t *iack) 587c478bd9Sstevel@tonic-gate { 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate sctp_hdr_t *sctph; 617c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ich; 627c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 637c478bd9Sstevel@tonic-gate int err; 647c478bd9Sstevel@tonic-gate uint_t sctp_options; 65d7ab25acSkp conn_t *aconnp; 6645916cd2Sjpk conn_t *lconnp; 67f4b3ec61Sdh sctp_stack_t *sctps = listener->sctp_sctps; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len); 707c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(sctph)); 717c478bd9Sstevel@tonic-gate 72*bd670b35SErik Nordmark aconnp = acceptor->sctp_connp; 73*bd670b35SErik Nordmark lconnp = listener->sctp_connp; 74*bd670b35SErik Nordmark aconnp->conn_lport = lconnp->conn_lport; 75*bd670b35SErik Nordmark aconnp->conn_fport = sctph->sh_sport; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate ich = (sctp_chunk_hdr_t *)(iack + 1); 787c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)(ich + 1); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* acceptor isn't in any fanouts yet, so don't need to hold locks */ 817c478bd9Sstevel@tonic-gate ASSERT(acceptor->sctp_faddrs == NULL); 827c478bd9Sstevel@tonic-gate err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich, 837c478bd9Sstevel@tonic-gate &sctp_options); 847c478bd9Sstevel@tonic-gate if (err != 0) 857c478bd9Sstevel@tonic-gate return (err); 867c478bd9Sstevel@tonic-gate 8777c67f2fSkcpoon if ((err = sctp_set_hdraddrs(acceptor)) != 0) 8845916cd2Sjpk return (err); 8945916cd2Sjpk 90*bd670b35SErik Nordmark if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0) 91*bd670b35SErik Nordmark return (err); 92*bd670b35SErik Nordmark 937c478bd9Sstevel@tonic-gate if ((sctp_options & SCTP_PRSCTP_OPTION) && 94f4b3ec61Sdh listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 957c478bd9Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_TRUE; 967c478bd9Sstevel@tonic-gate } else { 977c478bd9Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_FALSE; 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* Get initial TSNs */ 1017c478bd9Sstevel@tonic-gate acceptor->sctp_ltsn = ntohl(iack->sic_inittsn); 1027c478bd9Sstevel@tonic-gate acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd = 1037c478bd9Sstevel@tonic-gate acceptor->sctp_ltsn - 1; 1047c478bd9Sstevel@tonic-gate acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd; 1057c478bd9Sstevel@tonic-gate /* Serial numbers are initialized to the same value as the TSNs */ 1067c478bd9Sstevel@tonic-gate acceptor->sctp_lcsn = acceptor->sctp_ltsn; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(acceptor, init, iack)) 1097c478bd9Sstevel@tonic-gate return (ENOMEM); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * Copy sctp_secret from the listener in case we need to validate 1137c478bd9Sstevel@tonic-gate * a possibly delayed cookie. 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN); 1167c478bd9Sstevel@tonic-gate bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret, 1177c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 1187c478bd9Sstevel@tonic-gate acceptor->sctp_last_secret_update = lbolt64; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * After acceptor is inserted in the hash list, it can be found. 1227c478bd9Sstevel@tonic-gate * So we need to lock it here. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate RUN_SCTP(acceptor); 1257c478bd9Sstevel@tonic-gate 126f4b3ec61Sdh sctp_conn_hash_insert(&sctps->sctps_conn_fanout[ 127*bd670b35SErik Nordmark SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0); 128f4b3ec61Sdh sctp_bind_hash_insert(&sctps->sctps_bind_fanout[ 129*bd670b35SErik Nordmark SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * No need to check for multicast destination since ip will only pass 1337c478bd9Sstevel@tonic-gate * up multicasts to those that have expressed interest 1347c478bd9Sstevel@tonic-gate * TODO: what about rejecting broadcasts? 1357c478bd9Sstevel@tonic-gate * Also check that source is not a multicast or broadcast address. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate /* XXXSCTP */ 1387c478bd9Sstevel@tonic-gate acceptor->sctp_state = SCTPS_ESTABLISHED; 1397c478bd9Sstevel@tonic-gate acceptor->sctp_assoc_start_time = (uint32_t)lbolt; 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * listener->sctp_rwnd should be the default window size or a 1427c478bd9Sstevel@tonic-gate * window size changed via SO_RCVBUF option. 1437c478bd9Sstevel@tonic-gate */ 1441d8c4025Svi acceptor->sctp_rwnd = listener->sctp_rwnd; 1451d8c4025Svi acceptor->sctp_irwnd = acceptor->sctp_rwnd; 1467d546a59Svi acceptor->sctp_pd_point = acceptor->sctp_rwnd; 1470f1702c5SYu Xiangning acceptor->sctp_upcalls = listener->sctp_upcalls; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate return (0); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */ 1537c478bd9Sstevel@tonic-gate sctp_t * 1547c478bd9Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len, 155*bd670b35SErik Nordmark sctp_init_chunk_t *iack, ip_recv_attr_t *ira) 1567c478bd9Sstevel@tonic-gate { 1577c478bd9Sstevel@tonic-gate sctp_t *eager; 1587c478bd9Sstevel@tonic-gate ip6_t *ip6h; 1597c478bd9Sstevel@tonic-gate int err; 1607c478bd9Sstevel@tonic-gate conn_t *connp, *econnp; 161f4b3ec61Sdh sctp_stack_t *sctps; 1620f1702c5SYu Xiangning struct sock_proto_props sopp; 163de8c4a14SErik Nordmark cred_t *cr; 164de8c4a14SErik Nordmark pid_t cpid; 165*bd670b35SErik Nordmark in6_addr_t faddr, laddr; 166*bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * No need to check for duplicate as this is the listener 1707c478bd9Sstevel@tonic-gate * and we are holding the lock. This means that no new 1717c478bd9Sstevel@tonic-gate * connection can be created out of it. And since the 1727c478bd9Sstevel@tonic-gate * fanout already done cannot find a match, it means that 1737c478bd9Sstevel@tonic-gate * there is no duplicate. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate if ((eager = sctp_create_eager(sctp)) == NULL) { 1787c478bd9Sstevel@tonic-gate return (NULL); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate connp = sctp->sctp_connp; 182f4b3ec61Sdh sctps = sctp->sctp_sctps; 1837c478bd9Sstevel@tonic-gate econnp = eager->sctp_connp; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (connp->conn_policy != NULL) { 186*bd670b35SErik Nordmark /* Inherit the policy from the listener; use actions from ira */ 187*bd670b35SErik Nordmark if (!ip_ipsec_policy_inherit(econnp, connp, ira)) { 1887c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 189f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 1907c478bd9Sstevel@tonic-gate return (NULL); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 194*bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 195*bd670b35SErik Nordmark if (ira->ira_flags & IXAF_IS_IPV4) { 196*bd670b35SErik Nordmark ipha_t *ipha; 197*bd670b35SErik Nordmark 198*bd670b35SErik Nordmark ipha = (ipha_t *)ip6h; 199*bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr); 200*bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr); 201*bd670b35SErik Nordmark } else { 202*bd670b35SErik Nordmark laddr = ip6h->ip6_dst; 203*bd670b35SErik Nordmark faddr = ip6h->ip6_src; 204*bd670b35SErik Nordmark } 205*bd670b35SErik Nordmark 206*bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) { 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * XXX need to fix the cached policy issue here. 209*bd670b35SErik Nordmark * We temporarily set the conn_laddr/conn_faddr here so 2107c478bd9Sstevel@tonic-gate * that IPsec can use it for the latched policy 2117c478bd9Sstevel@tonic-gate * selector. This is obvioursly wrong as SCTP can 2127c478bd9Sstevel@tonic-gate * use different addresses... 2137c478bd9Sstevel@tonic-gate */ 214*bd670b35SErik Nordmark econnp->conn_laddr_v6 = laddr; 215*bd670b35SErik Nordmark econnp->conn_faddr_v6 = faddr; 216*bd670b35SErik Nordmark econnp->conn_saddr_v6 = laddr; 2177c478bd9Sstevel@tonic-gate } 218*bd670b35SErik Nordmark if (ipsec_conn_cache_policy(econnp, 219*bd670b35SErik Nordmark (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) { 2207c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 221f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2227c478bd9Sstevel@tonic-gate return (NULL); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 225de8c4a14SErik Nordmark /* Save for getpeerucred */ 226*bd670b35SErik Nordmark cr = ira->ira_cred; 227*bd670b35SErik Nordmark cpid = ira->ira_cpid; 228*bd670b35SErik Nordmark 229*bd670b35SErik Nordmark if (is_system_labeled()) { 230*bd670b35SErik Nordmark ip_xmit_attr_t *ixa = econnp->conn_ixa; 231*bd670b35SErik Nordmark 232*bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 233*bd670b35SErik Nordmark 234*bd670b35SErik Nordmark /* Discard any old label */ 235*bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 236*bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 237*bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 238*bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 239*bd670b35SErik Nordmark ixa->ixa_tsl = NULL; 240*bd670b35SErik Nordmark } 241*bd670b35SErik Nordmark 242*bd670b35SErik Nordmark if ((connp->conn_mlp_type != mlptSingle || 243*bd670b35SErik Nordmark connp->conn_mac_mode != CONN_MAC_DEFAULT) && 244*bd670b35SErik Nordmark ira->ira_tsl != NULL) { 245*bd670b35SErik Nordmark /* 246*bd670b35SErik Nordmark * If this is an MLP connection or a MAC-Exempt 247*bd670b35SErik Nordmark * connection with an unlabeled node, packets are to be 248*bd670b35SErik Nordmark * exchanged using the security label of the received 249*bd670b35SErik Nordmark * Cookie packet instead of the server application's 250*bd670b35SErik Nordmark * label. 251*bd670b35SErik Nordmark * tsol_check_dest called from ip_set_destination 252*bd670b35SErik Nordmark * might later update TSF_UNLABELED by replacing 253*bd670b35SErik Nordmark * ixa_tsl with a new label. 254*bd670b35SErik Nordmark */ 255*bd670b35SErik Nordmark label_hold(ira->ira_tsl); 256*bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl); 257*bd670b35SErik Nordmark } else { 258*bd670b35SErik Nordmark ixa->ixa_tsl = crgetlabel(econnp->conn_cred); 259*bd670b35SErik Nordmark } 260*bd670b35SErik Nordmark } 261de8c4a14SErik Nordmark 2627c478bd9Sstevel@tonic-gate err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack); 263*bd670b35SErik Nordmark if (err != 0) { 2647c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 265f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2667c478bd9Sstevel@tonic-gate return (NULL); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 269*bd670b35SErik Nordmark ASSERT(eager->sctp_current->ixa != NULL); 270*bd670b35SErik Nordmark 271*bd670b35SErik Nordmark ixa = eager->sctp_current->ixa; 272*bd670b35SErik Nordmark if (!(ira->ira_flags & IXAF_IS_IPV4)) { 273*bd670b35SErik Nordmark ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4)); 274*bd670b35SErik Nordmark 275*bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) || 276*bd670b35SErik Nordmark IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) { 277*bd670b35SErik Nordmark eager->sctp_linklocal = 1; 278*bd670b35SErik Nordmark 279*bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 280*bd670b35SErik Nordmark ixa->ixa_scopeid = ifindex; 281*bd670b35SErik Nordmark econnp->conn_incoming_ifindex = ifindex; 282*bd670b35SErik Nordmark } 283*bd670b35SErik Nordmark } 284*bd670b35SErik Nordmark 2851d8c4025Svi /* 2861d8c4025Svi * On a clustered note send this notification to the clustering 2871d8c4025Svi * subsystem. 2881d8c4025Svi */ 2891d8c4025Svi if (cl_sctp_connect != NULL) { 2901d8c4025Svi uchar_t *slist; 2911d8c4025Svi uchar_t *flist; 2921d8c4025Svi size_t fsize; 2931d8c4025Svi size_t ssize; 2941d8c4025Svi 2951d8c4025Svi fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs; 2961d8c4025Svi ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs; 2971d8c4025Svi slist = kmem_alloc(ssize, KM_NOSLEEP); 2981d8c4025Svi flist = kmem_alloc(fsize, KM_NOSLEEP); 2991d8c4025Svi if (slist == NULL || flist == NULL) { 3001d8c4025Svi if (slist != NULL) 3011d8c4025Svi kmem_free(slist, ssize); 3021d8c4025Svi if (flist != NULL) 3031d8c4025Svi kmem_free(flist, fsize); 3041d8c4025Svi sctp_close_eager(eager); 305f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 306f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_cl_connect); 3071d8c4025Svi return (NULL); 3081d8c4025Svi } 3091d8c4025Svi /* The clustering module frees these list */ 3101d8c4025Svi sctp_get_saddr_list(eager, slist, ssize); 3111d8c4025Svi sctp_get_faddr_list(eager, flist, fsize); 312*bd670b35SErik Nordmark (*cl_sctp_connect)(econnp->conn_family, slist, 313*bd670b35SErik Nordmark eager->sctp_nsaddrs, econnp->conn_lport, flist, 314*bd670b35SErik Nordmark eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE, 3151d8c4025Svi (cl_sctp_handle_t)eager); 3161d8c4025Svi } 3171d8c4025Svi 3187c478bd9Sstevel@tonic-gate /* Connection established, so send up the conn_ind */ 3197c478bd9Sstevel@tonic-gate if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd, 320de8c4a14SErik Nordmark (sock_lower_handle_t)eager, NULL, cr, cpid, 3210f1702c5SYu Xiangning &eager->sctp_upcalls)) == NULL) { 3227c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 323f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 3247c478bd9Sstevel@tonic-gate return (NULL); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate ASSERT(SCTP_IS_DETACHED(eager)); 3277c478bd9Sstevel@tonic-gate eager->sctp_detached = B_FALSE; 3280f1702c5SYu Xiangning bzero(&sopp, sizeof (sopp)); 3290f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF; 3300f1702c5SYu Xiangning sopp.sopp_maxblk = strmsgsz; 331*bd670b35SErik Nordmark if (econnp->conn_family == AF_INET) { 3320f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3330f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len; 3347c478bd9Sstevel@tonic-gate } else { 3350f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3360f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len; 3377c478bd9Sstevel@tonic-gate } 3380f1702c5SYu Xiangning eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp); 3397c478bd9Sstevel@tonic-gate return (eager); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Connect to a peer - this function inserts the sctp in the 3447c478bd9Sstevel@tonic-gate * bind and conn fanouts, sends the INIT, and replies to the client 3457c478bd9Sstevel@tonic-gate * with an OK ack. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate int 348*bd670b35SErik Nordmark sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen, 349*bd670b35SErik Nordmark cred_t *cr, pid_t pid) 3507c478bd9Sstevel@tonic-gate { 3517c478bd9Sstevel@tonic-gate sin_t *sin; 3527c478bd9Sstevel@tonic-gate sin6_t *sin6; 3537c478bd9Sstevel@tonic-gate in6_addr_t dstaddr; 3547c478bd9Sstevel@tonic-gate in_port_t dstport; 3557c478bd9Sstevel@tonic-gate mblk_t *initmp; 3567c478bd9Sstevel@tonic-gate sctp_tf_t *tbf; 3577c478bd9Sstevel@tonic-gate sctp_t *lsctp; 3587c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 3597c478bd9Sstevel@tonic-gate int sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP; 36045916cd2Sjpk int err; 3617c478bd9Sstevel@tonic-gate sctp_faddr_t *cur_fp; 362f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 363*bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 364*bd670b35SErik Nordmark uint_t scope_id = 0; 365*bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Determine packet type based on type of address passed in 3697c478bd9Sstevel@tonic-gate * the request should contain an IPv4 or IPv6 address. 3707c478bd9Sstevel@tonic-gate * Make sure that address family matches the type of 371*bd670b35SErik Nordmark * family of the address passed down. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate if (addrlen < sizeof (sin_t)) { 3747c478bd9Sstevel@tonic-gate return (EINVAL); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate switch (dst->sa_family) { 3777c478bd9Sstevel@tonic-gate case AF_INET: 3787c478bd9Sstevel@tonic-gate sin = (sin_t *)dst; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast */ 381c4f4b3c8Skcpoon if (CLASSD(sin->sin_addr.s_addr) || 3827c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr == INADDR_BROADCAST)) { 3837c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 3847c478bd9Sstevel@tonic-gate return (EINVAL); 3857c478bd9Sstevel@tonic-gate } 386*bd670b35SErik Nordmark if (connp->conn_ipv6_v6only) 3877c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* convert to v6 mapped */ 3907c478bd9Sstevel@tonic-gate /* Check for attempt to connect to INADDR_ANY */ 3917c478bd9Sstevel@tonic-gate if (sin->sin_addr.s_addr == INADDR_ANY) { 3927c478bd9Sstevel@tonic-gate struct in_addr v4_addr; 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * SunOS 4.x and 4.3 BSD allow an application 3957c478bd9Sstevel@tonic-gate * to connect a TCP socket to INADDR_ANY. 3967c478bd9Sstevel@tonic-gate * When they do this, the kernel picks the 3977c478bd9Sstevel@tonic-gate * address of one interface and uses it 3987c478bd9Sstevel@tonic-gate * instead. The kernel usually ends up 3997c478bd9Sstevel@tonic-gate * picking the address of the loopback 4007c478bd9Sstevel@tonic-gate * interface. This is an undocumented feature. 4017c478bd9Sstevel@tonic-gate * However, we provide the same thing here 4027c478bd9Sstevel@tonic-gate * in case any TCP apps that use this feature 4037c478bd9Sstevel@tonic-gate * are being ported to SCTP... 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate v4_addr.s_addr = htonl(INADDR_LOOPBACK); 4067c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr); 4077c478bd9Sstevel@tonic-gate } else { 4087c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate dstport = sin->sin_port; 4117c478bd9Sstevel@tonic-gate break; 4127c478bd9Sstevel@tonic-gate case AF_INET6: 4137c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)dst; 4147c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast. */ 4157c478bd9Sstevel@tonic-gate if ((addrlen < sizeof (sin6_t)) || 4167c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 4177c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 4187c478bd9Sstevel@tonic-gate return (EINVAL); 4197c478bd9Sstevel@tonic-gate } 420*bd670b35SErik Nordmark if (connp->conn_ipv6_v6only && 4217c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 4227c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate /* check for attempt to connect to unspec */ 4257c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4267c478bd9Sstevel@tonic-gate dstaddr = ipv6_loopback; 4277c478bd9Sstevel@tonic-gate } else { 4287c478bd9Sstevel@tonic-gate dstaddr = sin6->sin6_addr; 429*bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) { 430f551bb10Svi sctp->sctp_linklocal = 1; 431*bd670b35SErik Nordmark scope_id = sin6->sin6_scope_id; 432*bd670b35SErik Nordmark } 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate dstport = sin6->sin6_port; 435*bd670b35SErik Nordmark connp->conn_flowinfo = sin6->sin6_flowinfo; 4367c478bd9Sstevel@tonic-gate break; 4377c478bd9Sstevel@tonic-gate default: 4387c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: unknown family %d\n", 439b34b8d1aSkcpoon dst->sa_family)); 4407c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf)); 4447c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: attempting connect to %s...\n", buf)); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 4477c478bd9Sstevel@tonic-gate 448*bd670b35SErik Nordmark if (connp->conn_family != dst->sa_family || 449*bd670b35SErik Nordmark (connp->conn_state_flags & CONN_CLOSING)) { 4507c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 4517c478bd9Sstevel@tonic-gate return (EINVAL); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 454*bd670b35SErik Nordmark /* We update our cred/cpid based on the caller of connect */ 455*bd670b35SErik Nordmark if (connp->conn_cred != cr) { 456*bd670b35SErik Nordmark crhold(cr); 457*bd670b35SErik Nordmark crfree(connp->conn_cred); 458*bd670b35SErik Nordmark connp->conn_cred = cr; 459*bd670b35SErik Nordmark } 460*bd670b35SErik Nordmark connp->conn_cpid = pid; 461*bd670b35SErik Nordmark 462*bd670b35SErik Nordmark /* Cache things in conn_ixa without any refhold */ 463*bd670b35SErik Nordmark ixa = connp->conn_ixa; 464*bd670b35SErik Nordmark ixa->ixa_cred = cr; 465*bd670b35SErik Nordmark ixa->ixa_cpid = pid; 466*bd670b35SErik Nordmark if (is_system_labeled()) { 467*bd670b35SErik Nordmark /* We need to restart with a label based on the cred */ 468*bd670b35SErik Nordmark ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred); 469*bd670b35SErik Nordmark } 470*bd670b35SErik Nordmark 4717c478bd9Sstevel@tonic-gate switch (sctp->sctp_state) { 4727c478bd9Sstevel@tonic-gate case SCTPS_IDLE: { 4731d8c4025Svi struct sockaddr_storage ss; 4741d8c4025Svi 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * We support a quick connect capability here, allowing 4777c478bd9Sstevel@tonic-gate * clients to transition directly from IDLE to COOKIE_WAIT. 4787c478bd9Sstevel@tonic-gate * sctp_bindi will pick an unused port, insert the connection 4797c478bd9Sstevel@tonic-gate * in the bind hash and transition to BOUND state. SCTP 4807c478bd9Sstevel@tonic-gate * picks and uses what it considers the optimal local address 4817c478bd9Sstevel@tonic-gate * set (just like specifiying INADDR_ANY to bind()). 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: idle, attempting bind...\n")); 4847c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs == 0); 4857c478bd9Sstevel@tonic-gate 4861d8c4025Svi bzero(&ss, sizeof (ss)); 487*bd670b35SErik Nordmark ss.ss_family = connp->conn_family; 4881d8c4025Svi WAKE_SCTP(sctp); 4891d8c4025Svi if ((err = sctp_bind(sctp, (struct sockaddr *)&ss, 4901d8c4025Svi sizeof (ss))) != 0) { 4917c478bd9Sstevel@tonic-gate return (err); 4927c478bd9Sstevel@tonic-gate } 4931d8c4025Svi RUN_SCTP(sctp); 4947c478bd9Sstevel@tonic-gate /* FALLTHRU */ 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate case SCTPS_BOUND: 4987c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs > 0); 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* do the connect */ 5017c478bd9Sstevel@tonic-gate /* XXX check for attempt to connect to self */ 502*bd670b35SErik Nordmark connp->conn_fport = dstport; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_iphc); 5057c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_iphc6); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate /* 5087c478bd9Sstevel@tonic-gate * Don't allow this connection to completely duplicate 5097c478bd9Sstevel@tonic-gate * an existing connection. 5107c478bd9Sstevel@tonic-gate * 5117c478bd9Sstevel@tonic-gate * Ensure that the duplicate check and insertion is atomic. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 514f4b3ec61Sdh tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, 515*bd670b35SErik Nordmark connp->conn_ports)]; 5167c478bd9Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 517*bd670b35SErik Nordmark lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports, 5187c478bd9Sstevel@tonic-gate SCTPS_COOKIE_WAIT); 5197c478bd9Sstevel@tonic-gate if (lsctp != NULL) { 5207c478bd9Sstevel@tonic-gate /* found a duplicate connection */ 5217c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5227c478bd9Sstevel@tonic-gate SCTP_REFRELE(lsctp); 5237c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5247c478bd9Sstevel@tonic-gate return (EADDRINUSE); 5257c478bd9Sstevel@tonic-gate } 526*bd670b35SErik Nordmark 5277c478bd9Sstevel@tonic-gate /* 5287c478bd9Sstevel@tonic-gate * OK; set up the peer addr (this may grow after we get 5297c478bd9Sstevel@tonic-gate * the INIT ACK from the peer with additional addresses). 5307c478bd9Sstevel@tonic-gate */ 53177c67f2fSkcpoon if ((err = sctp_add_faddr(sctp, &dstaddr, sleep, 53277c67f2fSkcpoon B_FALSE)) != 0) { 5337c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5347c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 53545916cd2Sjpk return (err); 5367c478bd9Sstevel@tonic-gate } 537c31292eeSkcpoon cur_fp = sctp->sctp_faddrs; 538*bd670b35SErik Nordmark ASSERT(cur_fp->ixa != NULL); 539c31292eeSkcpoon 5407c478bd9Sstevel@tonic-gate /* No valid src addr, return. */ 541c31292eeSkcpoon if (cur_fp->state == SCTP_FADDRS_UNREACH) { 5427c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5437c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5447c478bd9Sstevel@tonic-gate return (EADDRNOTAVAIL); 5457c478bd9Sstevel@tonic-gate } 546c31292eeSkcpoon 547c31292eeSkcpoon sctp->sctp_primary = cur_fp; 548c31292eeSkcpoon sctp->sctp_current = cur_fp; 549c31292eeSkcpoon sctp->sctp_mss = cur_fp->sfa_pmss; 5507c478bd9Sstevel@tonic-gate sctp_conn_hash_insert(tbf, sctp, 1); 5517c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5527c478bd9Sstevel@tonic-gate 553*bd670b35SErik Nordmark ixa = cur_fp->ixa; 554*bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 555*bd670b35SErik Nordmark 556*bd670b35SErik Nordmark if (scope_id != 0) { 557*bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 558*bd670b35SErik Nordmark ixa->ixa_scopeid = scope_id; 559*bd670b35SErik Nordmark } else { 560*bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_SCOPEID_SET; 561*bd670b35SErik Nordmark } 562*bd670b35SErik Nordmark 5637c478bd9Sstevel@tonic-gate /* initialize composite headers */ 56477c67f2fSkcpoon if ((err = sctp_set_hdraddrs(sctp)) != 0) { 56545916cd2Sjpk sctp_conn_hash_remove(sctp); 56645916cd2Sjpk WAKE_SCTP(sctp); 56745916cd2Sjpk return (err); 56845916cd2Sjpk } 5697c478bd9Sstevel@tonic-gate 570*bd670b35SErik Nordmark if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) { 571*bd670b35SErik Nordmark sctp_conn_hash_remove(sctp); 572*bd670b35SErik Nordmark WAKE_SCTP(sctp); 573*bd670b35SErik Nordmark return (err); 574f4b3ec61Sdh } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Turn off the don't fragment bit on the (only) faddr, 5787c478bd9Sstevel@tonic-gate * so that if one of the messages exchanged during the 5797c478bd9Sstevel@tonic-gate * initialization sequence exceeds the path mtu, it 5807c478bd9Sstevel@tonic-gate * at least has a chance to get there. SCTP does no 5817c478bd9Sstevel@tonic-gate * fragmentation of initialization messages. The DF bit 5827c478bd9Sstevel@tonic-gate * will be turned on again in sctp_send_cookie_echo() 5837c478bd9Sstevel@tonic-gate * (but the cookie echo will still be sent with the df bit 5847c478bd9Sstevel@tonic-gate * off). 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate cur_fp->df = B_FALSE; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* Mark this address as alive */ 5897c478bd9Sstevel@tonic-gate cur_fp->state = SCTP_FADDRS_ALIVE; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* Send the INIT to the peer */ 5927c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto); 593c31292eeSkcpoon sctp->sctp_state = SCTPS_COOKIE_WAIT; 594f551bb10Svi /* 595f551bb10Svi * sctp_init_mp() could result in modifying the source 596f551bb10Svi * address list, so take the hash lock. 597f551bb10Svi */ 598f551bb10Svi mutex_enter(&tbf->tf_lock); 599*bd670b35SErik Nordmark initmp = sctp_init_mp(sctp, cur_fp); 6007c478bd9Sstevel@tonic-gate if (initmp == NULL) { 601f551bb10Svi mutex_exit(&tbf->tf_lock); 602c31292eeSkcpoon /* 603c31292eeSkcpoon * It may happen that all the source addresses 604c31292eeSkcpoon * (loopback/link local) are removed. In that case, 605c31292eeSkcpoon * faile the connect. 606c31292eeSkcpoon */ 607c31292eeSkcpoon if (sctp->sctp_nsaddrs == 0) { 608c31292eeSkcpoon sctp_conn_hash_remove(sctp); 609c31292eeSkcpoon SCTP_FADDR_TIMER_STOP(cur_fp); 610c31292eeSkcpoon WAKE_SCTP(sctp); 611c31292eeSkcpoon return (EADDRNOTAVAIL); 612c31292eeSkcpoon } 613c31292eeSkcpoon 614c31292eeSkcpoon /* Otherwise, let the retransmission timer retry */ 6157c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 616c31292eeSkcpoon goto notify_ulp; 6177c478bd9Sstevel@tonic-gate } 618f551bb10Svi mutex_exit(&tbf->tf_lock); 619c31292eeSkcpoon 6201d8c4025Svi /* 6211d8c4025Svi * On a clustered note send this notification to the clustering 6221d8c4025Svi * subsystem. 6231d8c4025Svi */ 6241d8c4025Svi if (cl_sctp_connect != NULL) { 6251d8c4025Svi uchar_t *slist; 6261d8c4025Svi uchar_t *flist; 6271d8c4025Svi size_t ssize; 6281d8c4025Svi size_t fsize; 6291d8c4025Svi 6301d8c4025Svi fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 6311d8c4025Svi ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 6321d8c4025Svi slist = kmem_alloc(ssize, KM_SLEEP); 6331d8c4025Svi flist = kmem_alloc(fsize, KM_SLEEP); 6341d8c4025Svi /* The clustering module frees the lists */ 6351d8c4025Svi sctp_get_saddr_list(sctp, slist, ssize); 6361d8c4025Svi sctp_get_faddr_list(sctp, flist, fsize); 637*bd670b35SErik Nordmark (*cl_sctp_connect)(connp->conn_family, slist, 638*bd670b35SErik Nordmark sctp->sctp_nsaddrs, connp->conn_lport, 639*bd670b35SErik Nordmark flist, sctp->sctp_nfaddrs, connp->conn_fport, 6401d8c4025Svi B_TRUE, (cl_sctp_handle_t)sctp); 6411d8c4025Svi } 642*bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 643*bd670b35SErik Nordmark ASSERT(ixa->ixa_ire != NULL); 644*bd670b35SErik Nordmark 645*bd670b35SErik Nordmark (void) conn_ip_output(initmp, ixa); 6467c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts); 647*bd670b35SErik Nordmark WAKE_SCTP(sctp); 6487c478bd9Sstevel@tonic-gate 649c31292eeSkcpoon notify_ulp: 650*bd670b35SErik Nordmark sctp_set_ulp_prop(sctp); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate return (0); 6537c478bd9Sstevel@tonic-gate default: 6547c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state)); 6557c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 6567c478bd9Sstevel@tonic-gate return (EINVAL); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate } 659