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*481845d8SGeorge Shepherd * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 307c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 317c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 327c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 337c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 347c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 357c478bd9Sstevel@tonic-gate #include <sys/socket.h> 3645916cd2Sjpk #include <sys/tsol/tndb.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <netinet/in.h> 397c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <inet/common.h> 427c478bd9Sstevel@tonic-gate #include <inet/ip.h> 437c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 447c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 457c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 487c478bd9Sstevel@tonic-gate #include "sctp_addr.h" 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * Common accept code. Called by sctp_conn_request. 527c478bd9Sstevel@tonic-gate * cr_pkt is the INIT / INIT ACK packet. 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate static int 557c478bd9Sstevel@tonic-gate sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, 567c478bd9Sstevel@tonic-gate uint_t ip_hdr_len, sctp_init_chunk_t *iack) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate sctp_hdr_t *sctph; 607c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ich; 617c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 627c478bd9Sstevel@tonic-gate int err; 637c478bd9Sstevel@tonic-gate uint_t sctp_options; 64d7ab25acSkp conn_t *aconnp; 6545916cd2Sjpk conn_t *lconnp; 66f4b3ec61Sdh sctp_stack_t *sctps = listener->sctp_sctps; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len); 697c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(sctph)); 707c478bd9Sstevel@tonic-gate 71bd670b35SErik Nordmark aconnp = acceptor->sctp_connp; 72bd670b35SErik Nordmark lconnp = listener->sctp_connp; 73bd670b35SErik Nordmark aconnp->conn_lport = lconnp->conn_lport; 74bd670b35SErik Nordmark aconnp->conn_fport = sctph->sh_sport; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate ich = (sctp_chunk_hdr_t *)(iack + 1); 777c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)(ich + 1); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* acceptor isn't in any fanouts yet, so don't need to hold locks */ 807c478bd9Sstevel@tonic-gate ASSERT(acceptor->sctp_faddrs == NULL); 817c478bd9Sstevel@tonic-gate err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich, 827c478bd9Sstevel@tonic-gate &sctp_options); 837c478bd9Sstevel@tonic-gate if (err != 0) 847c478bd9Sstevel@tonic-gate return (err); 857c478bd9Sstevel@tonic-gate 8677c67f2fSkcpoon if ((err = sctp_set_hdraddrs(acceptor)) != 0) 8745916cd2Sjpk return (err); 8845916cd2Sjpk 89bd670b35SErik Nordmark if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0) 90bd670b35SErik Nordmark return (err); 91bd670b35SErik Nordmark 927c478bd9Sstevel@tonic-gate if ((sctp_options & SCTP_PRSCTP_OPTION) && 93f4b3ec61Sdh listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 947c478bd9Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_TRUE; 957c478bd9Sstevel@tonic-gate } else { 967c478bd9Sstevel@tonic-gate acceptor->sctp_prsctp_aware = B_FALSE; 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* Get initial TSNs */ 1007c478bd9Sstevel@tonic-gate acceptor->sctp_ltsn = ntohl(iack->sic_inittsn); 1017c478bd9Sstevel@tonic-gate acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd = 1027c478bd9Sstevel@tonic-gate acceptor->sctp_ltsn - 1; 1037c478bd9Sstevel@tonic-gate acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd; 1047c478bd9Sstevel@tonic-gate /* Serial numbers are initialized to the same value as the TSNs */ 1057c478bd9Sstevel@tonic-gate acceptor->sctp_lcsn = acceptor->sctp_ltsn; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(acceptor, init, iack)) 1087c478bd9Sstevel@tonic-gate return (ENOMEM); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * Copy sctp_secret from the listener in case we need to validate 1127c478bd9Sstevel@tonic-gate * a possibly delayed cookie. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN); 1157c478bd9Sstevel@tonic-gate bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret, 1167c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 117d3d50737SRafael Vanoni acceptor->sctp_last_secret_update = ddi_get_lbolt64(); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * After acceptor is inserted in the hash list, it can be found. 1217c478bd9Sstevel@tonic-gate * So we need to lock it here. 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate RUN_SCTP(acceptor); 1247c478bd9Sstevel@tonic-gate 125f4b3ec61Sdh sctp_conn_hash_insert(&sctps->sctps_conn_fanout[ 126bd670b35SErik Nordmark SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0); 127f4b3ec61Sdh sctp_bind_hash_insert(&sctps->sctps_bind_fanout[ 128bd670b35SErik Nordmark SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * No need to check for multicast destination since ip will only pass 1327c478bd9Sstevel@tonic-gate * up multicasts to those that have expressed interest 1337c478bd9Sstevel@tonic-gate * TODO: what about rejecting broadcasts? 1347c478bd9Sstevel@tonic-gate * Also check that source is not a multicast or broadcast address. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate /* XXXSCTP */ 1377c478bd9Sstevel@tonic-gate acceptor->sctp_state = SCTPS_ESTABLISHED; 138d3d50737SRafael Vanoni acceptor->sctp_assoc_start_time = (uint32_t)ddi_get_lbolt(); 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * listener->sctp_rwnd should be the default window size or a 1417c478bd9Sstevel@tonic-gate * window size changed via SO_RCVBUF option. 1427c478bd9Sstevel@tonic-gate */ 1431d8c4025Svi acceptor->sctp_rwnd = listener->sctp_rwnd; 1441d8c4025Svi acceptor->sctp_irwnd = acceptor->sctp_rwnd; 1457d546a59Svi acceptor->sctp_pd_point = acceptor->sctp_rwnd; 1460f1702c5SYu Xiangning acceptor->sctp_upcalls = listener->sctp_upcalls; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate return (0); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */ 1527c478bd9Sstevel@tonic-gate sctp_t * 1537c478bd9Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len, 154bd670b35SErik Nordmark sctp_init_chunk_t *iack, ip_recv_attr_t *ira) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate sctp_t *eager; 1577c478bd9Sstevel@tonic-gate ip6_t *ip6h; 1587c478bd9Sstevel@tonic-gate int err; 1597c478bd9Sstevel@tonic-gate conn_t *connp, *econnp; 160f4b3ec61Sdh sctp_stack_t *sctps; 1610f1702c5SYu Xiangning struct sock_proto_props sopp; 162de8c4a14SErik Nordmark cred_t *cr; 163de8c4a14SErik Nordmark pid_t cpid; 164bd670b35SErik Nordmark in6_addr_t faddr, laddr; 165bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * No need to check for duplicate as this is the listener 1697c478bd9Sstevel@tonic-gate * and we are holding the lock. This means that no new 1707c478bd9Sstevel@tonic-gate * connection can be created out of it. And since the 1717c478bd9Sstevel@tonic-gate * fanout already done cannot find a match, it means that 1727c478bd9Sstevel@tonic-gate * there is no duplicate. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if ((eager = sctp_create_eager(sctp)) == NULL) { 1777c478bd9Sstevel@tonic-gate return (NULL); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate connp = sctp->sctp_connp; 181f4b3ec61Sdh sctps = sctp->sctp_sctps; 1827c478bd9Sstevel@tonic-gate econnp = eager->sctp_connp; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if (connp->conn_policy != NULL) { 185bd670b35SErik Nordmark /* Inherit the policy from the listener; use actions from ira */ 186bd670b35SErik Nordmark if (!ip_ipsec_policy_inherit(econnp, connp, ira)) { 1877c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 188f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 1897c478bd9Sstevel@tonic-gate return (NULL); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 193bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 194bd670b35SErik Nordmark if (ira->ira_flags & IXAF_IS_IPV4) { 195bd670b35SErik Nordmark ipha_t *ipha; 196bd670b35SErik Nordmark 197bd670b35SErik Nordmark ipha = (ipha_t *)ip6h; 198bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr); 199bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr); 200bd670b35SErik Nordmark } else { 201bd670b35SErik Nordmark laddr = ip6h->ip6_dst; 202bd670b35SErik Nordmark faddr = ip6h->ip6_src; 203bd670b35SErik Nordmark } 204bd670b35SErik Nordmark 205bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) { 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * XXX need to fix the cached policy issue here. 208bd670b35SErik Nordmark * We temporarily set the conn_laddr/conn_faddr here so 2097c478bd9Sstevel@tonic-gate * that IPsec can use it for the latched policy 2107c478bd9Sstevel@tonic-gate * selector. This is obvioursly wrong as SCTP can 2117c478bd9Sstevel@tonic-gate * use different addresses... 2127c478bd9Sstevel@tonic-gate */ 213bd670b35SErik Nordmark econnp->conn_laddr_v6 = laddr; 214bd670b35SErik Nordmark econnp->conn_faddr_v6 = faddr; 215bd670b35SErik Nordmark econnp->conn_saddr_v6 = laddr; 2167c478bd9Sstevel@tonic-gate } 217bd670b35SErik Nordmark if (ipsec_conn_cache_policy(econnp, 218bd670b35SErik Nordmark (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) { 2197c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 220f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2217c478bd9Sstevel@tonic-gate return (NULL); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 224de8c4a14SErik Nordmark /* Save for getpeerucred */ 225bd670b35SErik Nordmark cr = ira->ira_cred; 226bd670b35SErik Nordmark cpid = ira->ira_cpid; 227bd670b35SErik Nordmark 228bd670b35SErik Nordmark if (is_system_labeled()) { 229bd670b35SErik Nordmark ip_xmit_attr_t *ixa = econnp->conn_ixa; 230bd670b35SErik Nordmark 231bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 232bd670b35SErik Nordmark 233bd670b35SErik Nordmark /* Discard any old label */ 234bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 235bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 236bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 237bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 238bd670b35SErik Nordmark ixa->ixa_tsl = NULL; 239bd670b35SErik Nordmark } 240bd670b35SErik Nordmark 241bd670b35SErik Nordmark if ((connp->conn_mlp_type != mlptSingle || 242bd670b35SErik Nordmark connp->conn_mac_mode != CONN_MAC_DEFAULT) && 243bd670b35SErik Nordmark ira->ira_tsl != NULL) { 244bd670b35SErik Nordmark /* 245bd670b35SErik Nordmark * If this is an MLP connection or a MAC-Exempt 246bd670b35SErik Nordmark * connection with an unlabeled node, packets are to be 247bd670b35SErik Nordmark * exchanged using the security label of the received 248bd670b35SErik Nordmark * Cookie packet instead of the server application's 249bd670b35SErik Nordmark * label. 250bd670b35SErik Nordmark * tsol_check_dest called from ip_set_destination 251bd670b35SErik Nordmark * might later update TSF_UNLABELED by replacing 252bd670b35SErik Nordmark * ixa_tsl with a new label. 253bd670b35SErik Nordmark */ 254bd670b35SErik Nordmark label_hold(ira->ira_tsl); 255bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl); 256bd670b35SErik Nordmark } else { 257bd670b35SErik Nordmark ixa->ixa_tsl = crgetlabel(econnp->conn_cred); 258bd670b35SErik Nordmark } 259bd670b35SErik Nordmark } 260de8c4a14SErik Nordmark 2617c478bd9Sstevel@tonic-gate err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack); 262bd670b35SErik Nordmark if (err != 0) { 2637c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 264f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 2657c478bd9Sstevel@tonic-gate return (NULL); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 268bd670b35SErik Nordmark ASSERT(eager->sctp_current->ixa != NULL); 269bd670b35SErik Nordmark 270bd670b35SErik Nordmark ixa = eager->sctp_current->ixa; 271bd670b35SErik Nordmark if (!(ira->ira_flags & IXAF_IS_IPV4)) { 272bd670b35SErik Nordmark ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4)); 273bd670b35SErik Nordmark 274bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) || 275bd670b35SErik Nordmark IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) { 276bd670b35SErik Nordmark eager->sctp_linklocal = 1; 277bd670b35SErik Nordmark 278bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 279bd670b35SErik Nordmark ixa->ixa_scopeid = ifindex; 280bd670b35SErik Nordmark econnp->conn_incoming_ifindex = ifindex; 281bd670b35SErik Nordmark } 282bd670b35SErik Nordmark } 283bd670b35SErik Nordmark 2841d8c4025Svi /* 2851d8c4025Svi * On a clustered note send this notification to the clustering 2861d8c4025Svi * subsystem. 2871d8c4025Svi */ 2881d8c4025Svi if (cl_sctp_connect != NULL) { 2891d8c4025Svi uchar_t *slist; 2901d8c4025Svi uchar_t *flist; 2911d8c4025Svi size_t fsize; 2921d8c4025Svi size_t ssize; 2931d8c4025Svi 2941d8c4025Svi fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs; 2951d8c4025Svi ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs; 2961d8c4025Svi slist = kmem_alloc(ssize, KM_NOSLEEP); 2971d8c4025Svi flist = kmem_alloc(fsize, KM_NOSLEEP); 2981d8c4025Svi if (slist == NULL || flist == NULL) { 2991d8c4025Svi if (slist != NULL) 3001d8c4025Svi kmem_free(slist, ssize); 3011d8c4025Svi if (flist != NULL) 3021d8c4025Svi kmem_free(flist, fsize); 3031d8c4025Svi sctp_close_eager(eager); 304f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 305f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_cl_connect); 3061d8c4025Svi return (NULL); 3071d8c4025Svi } 3081d8c4025Svi /* The clustering module frees these list */ 3091d8c4025Svi sctp_get_saddr_list(eager, slist, ssize); 3101d8c4025Svi sctp_get_faddr_list(eager, flist, fsize); 311bd670b35SErik Nordmark (*cl_sctp_connect)(econnp->conn_family, slist, 312bd670b35SErik Nordmark eager->sctp_nsaddrs, econnp->conn_lport, flist, 313bd670b35SErik Nordmark eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE, 3141d8c4025Svi (cl_sctp_handle_t)eager); 3151d8c4025Svi } 3161d8c4025Svi 3177c478bd9Sstevel@tonic-gate /* Connection established, so send up the conn_ind */ 3187c478bd9Sstevel@tonic-gate if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd, 319de8c4a14SErik Nordmark (sock_lower_handle_t)eager, NULL, cr, cpid, 3200f1702c5SYu Xiangning &eager->sctp_upcalls)) == NULL) { 3217c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 322f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpListenDrop); 3237c478bd9Sstevel@tonic-gate return (NULL); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate ASSERT(SCTP_IS_DETACHED(eager)); 3267c478bd9Sstevel@tonic-gate eager->sctp_detached = B_FALSE; 3270f1702c5SYu Xiangning bzero(&sopp, sizeof (sopp)); 3280f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF; 3290f1702c5SYu Xiangning sopp.sopp_maxblk = strmsgsz; 330bd670b35SErik Nordmark if (econnp->conn_family == AF_INET) { 3310f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3320f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len; 3337c478bd9Sstevel@tonic-gate } else { 3340f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3350f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len; 3367c478bd9Sstevel@tonic-gate } 3370f1702c5SYu Xiangning eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp); 3387c478bd9Sstevel@tonic-gate return (eager); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Connect to a peer - this function inserts the sctp in the 3437c478bd9Sstevel@tonic-gate * bind and conn fanouts, sends the INIT, and replies to the client 3447c478bd9Sstevel@tonic-gate * with an OK ack. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate int 347bd670b35SErik Nordmark sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen, 348bd670b35SErik Nordmark cred_t *cr, pid_t pid) 3497c478bd9Sstevel@tonic-gate { 3507c478bd9Sstevel@tonic-gate sin_t *sin; 3517c478bd9Sstevel@tonic-gate sin6_t *sin6; 3527c478bd9Sstevel@tonic-gate in6_addr_t dstaddr; 3537c478bd9Sstevel@tonic-gate in_port_t dstport; 3547c478bd9Sstevel@tonic-gate mblk_t *initmp; 3557c478bd9Sstevel@tonic-gate sctp_tf_t *tbf; 3567c478bd9Sstevel@tonic-gate sctp_t *lsctp; 3577c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 3587c478bd9Sstevel@tonic-gate int sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP; 35945916cd2Sjpk int err; 3607c478bd9Sstevel@tonic-gate sctp_faddr_t *cur_fp; 361f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 362bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 363bd670b35SErik Nordmark uint_t scope_id = 0; 364bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Determine packet type based on type of address passed in 3687c478bd9Sstevel@tonic-gate * the request should contain an IPv4 or IPv6 address. 3697c478bd9Sstevel@tonic-gate * Make sure that address family matches the type of 370bd670b35SErik Nordmark * family of the address passed down. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate if (addrlen < sizeof (sin_t)) { 3737c478bd9Sstevel@tonic-gate return (EINVAL); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate switch (dst->sa_family) { 3767c478bd9Sstevel@tonic-gate case AF_INET: 3777c478bd9Sstevel@tonic-gate sin = (sin_t *)dst; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast */ 380c4f4b3c8Skcpoon if (CLASSD(sin->sin_addr.s_addr) || 3817c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr == INADDR_BROADCAST)) { 3827c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 3837c478bd9Sstevel@tonic-gate return (EINVAL); 3847c478bd9Sstevel@tonic-gate } 385bd670b35SErik Nordmark if (connp->conn_ipv6_v6only) 3867c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* convert to v6 mapped */ 3897c478bd9Sstevel@tonic-gate /* Check for attempt to connect to INADDR_ANY */ 3907c478bd9Sstevel@tonic-gate if (sin->sin_addr.s_addr == INADDR_ANY) { 3917c478bd9Sstevel@tonic-gate struct in_addr v4_addr; 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * SunOS 4.x and 4.3 BSD allow an application 3947c478bd9Sstevel@tonic-gate * to connect a TCP socket to INADDR_ANY. 3957c478bd9Sstevel@tonic-gate * When they do this, the kernel picks the 3967c478bd9Sstevel@tonic-gate * address of one interface and uses it 3977c478bd9Sstevel@tonic-gate * instead. The kernel usually ends up 3987c478bd9Sstevel@tonic-gate * picking the address of the loopback 3997c478bd9Sstevel@tonic-gate * interface. This is an undocumented feature. 4007c478bd9Sstevel@tonic-gate * However, we provide the same thing here 4017c478bd9Sstevel@tonic-gate * in case any TCP apps that use this feature 4027c478bd9Sstevel@tonic-gate * are being ported to SCTP... 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate v4_addr.s_addr = htonl(INADDR_LOOPBACK); 4057c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr); 4067c478bd9Sstevel@tonic-gate } else { 4077c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate dstport = sin->sin_port; 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate case AF_INET6: 4127c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)dst; 4137c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast. */ 4147c478bd9Sstevel@tonic-gate if ((addrlen < sizeof (sin6_t)) || 4157c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 4167c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 4177c478bd9Sstevel@tonic-gate return (EINVAL); 4187c478bd9Sstevel@tonic-gate } 419bd670b35SErik Nordmark if (connp->conn_ipv6_v6only && 4207c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 4217c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate /* check for attempt to connect to unspec */ 4247c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4257c478bd9Sstevel@tonic-gate dstaddr = ipv6_loopback; 4267c478bd9Sstevel@tonic-gate } else { 4277c478bd9Sstevel@tonic-gate dstaddr = sin6->sin6_addr; 428bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) { 429f551bb10Svi sctp->sctp_linklocal = 1; 430bd670b35SErik Nordmark scope_id = sin6->sin6_scope_id; 431bd670b35SErik Nordmark } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate dstport = sin6->sin6_port; 434bd670b35SErik Nordmark connp->conn_flowinfo = sin6->sin6_flowinfo; 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate default: 4377c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: unknown family %d\n", 438b34b8d1aSkcpoon dst->sa_family)); 4397c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf)); 4437c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: attempting connect to %s...\n", buf)); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 4467c478bd9Sstevel@tonic-gate 447bd670b35SErik Nordmark if (connp->conn_family != dst->sa_family || 448bd670b35SErik Nordmark (connp->conn_state_flags & CONN_CLOSING)) { 4497c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 4507c478bd9Sstevel@tonic-gate return (EINVAL); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 453bd670b35SErik Nordmark /* We update our cred/cpid based on the caller of connect */ 454bd670b35SErik Nordmark if (connp->conn_cred != cr) { 455bd670b35SErik Nordmark crhold(cr); 456bd670b35SErik Nordmark crfree(connp->conn_cred); 457bd670b35SErik Nordmark connp->conn_cred = cr; 458bd670b35SErik Nordmark } 459bd670b35SErik Nordmark connp->conn_cpid = pid; 460bd670b35SErik Nordmark 461bd670b35SErik Nordmark /* Cache things in conn_ixa without any refhold */ 462bd670b35SErik Nordmark ixa = connp->conn_ixa; 463be4c8f74SErik Nordmark ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED)); 464bd670b35SErik Nordmark ixa->ixa_cred = cr; 465bd670b35SErik Nordmark ixa->ixa_cpid = pid; 466bd670b35SErik Nordmark if (is_system_labeled()) { 467bd670b35SErik Nordmark /* We need to restart with a label based on the cred */ 468bd670b35SErik Nordmark ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred); 469bd670b35SErik Nordmark } 470bd670b35SErik 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)); 487bd670b35SErik 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 */ 502bd670b35SErik Nordmark connp->conn_fport = dstport; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * Don't allow this connection to completely duplicate 5067c478bd9Sstevel@tonic-gate * an existing connection. 5077c478bd9Sstevel@tonic-gate * 5087c478bd9Sstevel@tonic-gate * Ensure that the duplicate check and insertion is atomic. 5097c478bd9Sstevel@tonic-gate */ 5107c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 511f4b3ec61Sdh tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, 512bd670b35SErik Nordmark connp->conn_ports)]; 5137c478bd9Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 514bd670b35SErik Nordmark lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports, 5157c478bd9Sstevel@tonic-gate SCTPS_COOKIE_WAIT); 5167c478bd9Sstevel@tonic-gate if (lsctp != NULL) { 5177c478bd9Sstevel@tonic-gate /* found a duplicate connection */ 5187c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5197c478bd9Sstevel@tonic-gate SCTP_REFRELE(lsctp); 5207c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5217c478bd9Sstevel@tonic-gate return (EADDRINUSE); 5227c478bd9Sstevel@tonic-gate } 523bd670b35SErik Nordmark 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * OK; set up the peer addr (this may grow after we get 5267c478bd9Sstevel@tonic-gate * the INIT ACK from the peer with additional addresses). 5277c478bd9Sstevel@tonic-gate */ 52877c67f2fSkcpoon if ((err = sctp_add_faddr(sctp, &dstaddr, sleep, 52977c67f2fSkcpoon B_FALSE)) != 0) { 5307c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5317c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 53245916cd2Sjpk return (err); 5337c478bd9Sstevel@tonic-gate } 534c31292eeSkcpoon cur_fp = sctp->sctp_faddrs; 535bd670b35SErik Nordmark ASSERT(cur_fp->ixa != NULL); 536c31292eeSkcpoon 5377c478bd9Sstevel@tonic-gate /* No valid src addr, return. */ 538c31292eeSkcpoon if (cur_fp->state == SCTP_FADDRS_UNREACH) { 5397c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5407c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5417c478bd9Sstevel@tonic-gate return (EADDRNOTAVAIL); 5427c478bd9Sstevel@tonic-gate } 543c31292eeSkcpoon 544c31292eeSkcpoon sctp->sctp_primary = cur_fp; 545c31292eeSkcpoon sctp->sctp_current = cur_fp; 546c31292eeSkcpoon sctp->sctp_mss = cur_fp->sfa_pmss; 5477c478bd9Sstevel@tonic-gate sctp_conn_hash_insert(tbf, sctp, 1); 5487c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5497c478bd9Sstevel@tonic-gate 550bd670b35SErik Nordmark ixa = cur_fp->ixa; 551bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 552bd670b35SErik Nordmark 553bd670b35SErik Nordmark if (scope_id != 0) { 554bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 555bd670b35SErik Nordmark ixa->ixa_scopeid = scope_id; 556bd670b35SErik Nordmark } else { 557bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_SCOPEID_SET; 558bd670b35SErik Nordmark } 559bd670b35SErik Nordmark 5607c478bd9Sstevel@tonic-gate /* initialize composite headers */ 56177c67f2fSkcpoon if ((err = sctp_set_hdraddrs(sctp)) != 0) { 56245916cd2Sjpk sctp_conn_hash_remove(sctp); 56345916cd2Sjpk WAKE_SCTP(sctp); 56445916cd2Sjpk return (err); 56545916cd2Sjpk } 5667c478bd9Sstevel@tonic-gate 567bd670b35SErik Nordmark if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) { 568bd670b35SErik Nordmark sctp_conn_hash_remove(sctp); 569bd670b35SErik Nordmark WAKE_SCTP(sctp); 570bd670b35SErik Nordmark return (err); 571f4b3ec61Sdh } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * Turn off the don't fragment bit on the (only) faddr, 5757c478bd9Sstevel@tonic-gate * so that if one of the messages exchanged during the 5767c478bd9Sstevel@tonic-gate * initialization sequence exceeds the path mtu, it 5777c478bd9Sstevel@tonic-gate * at least has a chance to get there. SCTP does no 5787c478bd9Sstevel@tonic-gate * fragmentation of initialization messages. The DF bit 5797c478bd9Sstevel@tonic-gate * will be turned on again in sctp_send_cookie_echo() 5807c478bd9Sstevel@tonic-gate * (but the cookie echo will still be sent with the df bit 5817c478bd9Sstevel@tonic-gate * off). 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate cur_fp->df = B_FALSE; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* Mark this address as alive */ 5867c478bd9Sstevel@tonic-gate cur_fp->state = SCTP_FADDRS_ALIVE; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* Send the INIT to the peer */ 5897c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto); 590c31292eeSkcpoon sctp->sctp_state = SCTPS_COOKIE_WAIT; 591f551bb10Svi /* 592f551bb10Svi * sctp_init_mp() could result in modifying the source 593f551bb10Svi * address list, so take the hash lock. 594f551bb10Svi */ 595f551bb10Svi mutex_enter(&tbf->tf_lock); 596bd670b35SErik Nordmark initmp = sctp_init_mp(sctp, cur_fp); 5977c478bd9Sstevel@tonic-gate if (initmp == NULL) { 598f551bb10Svi mutex_exit(&tbf->tf_lock); 599c31292eeSkcpoon /* 600c31292eeSkcpoon * It may happen that all the source addresses 601c31292eeSkcpoon * (loopback/link local) are removed. In that case, 602c31292eeSkcpoon * faile the connect. 603c31292eeSkcpoon */ 604c31292eeSkcpoon if (sctp->sctp_nsaddrs == 0) { 605c31292eeSkcpoon sctp_conn_hash_remove(sctp); 606c31292eeSkcpoon SCTP_FADDR_TIMER_STOP(cur_fp); 607c31292eeSkcpoon WAKE_SCTP(sctp); 608c31292eeSkcpoon return (EADDRNOTAVAIL); 609c31292eeSkcpoon } 610c31292eeSkcpoon 611c31292eeSkcpoon /* Otherwise, let the retransmission timer retry */ 6127c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 613c31292eeSkcpoon goto notify_ulp; 6147c478bd9Sstevel@tonic-gate } 615f551bb10Svi mutex_exit(&tbf->tf_lock); 616c31292eeSkcpoon 6171d8c4025Svi /* 6181d8c4025Svi * On a clustered note send this notification to the clustering 6191d8c4025Svi * subsystem. 6201d8c4025Svi */ 6211d8c4025Svi if (cl_sctp_connect != NULL) { 6221d8c4025Svi uchar_t *slist; 6231d8c4025Svi uchar_t *flist; 6241d8c4025Svi size_t ssize; 6251d8c4025Svi size_t fsize; 6261d8c4025Svi 6271d8c4025Svi fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 6281d8c4025Svi ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 6291d8c4025Svi slist = kmem_alloc(ssize, KM_SLEEP); 6301d8c4025Svi flist = kmem_alloc(fsize, KM_SLEEP); 6311d8c4025Svi /* The clustering module frees the lists */ 6321d8c4025Svi sctp_get_saddr_list(sctp, slist, ssize); 6331d8c4025Svi sctp_get_faddr_list(sctp, flist, fsize); 634bd670b35SErik Nordmark (*cl_sctp_connect)(connp->conn_family, slist, 635bd670b35SErik Nordmark sctp->sctp_nsaddrs, connp->conn_lport, 636bd670b35SErik Nordmark flist, sctp->sctp_nfaddrs, connp->conn_fport, 6371d8c4025Svi B_TRUE, (cl_sctp_handle_t)sctp); 6381d8c4025Svi } 639bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 640bd670b35SErik Nordmark ASSERT(ixa->ixa_ire != NULL); 641bd670b35SErik Nordmark 642bd670b35SErik Nordmark (void) conn_ip_output(initmp, ixa); 6437c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts); 644bd670b35SErik Nordmark WAKE_SCTP(sctp); 6457c478bd9Sstevel@tonic-gate 646c31292eeSkcpoon notify_ulp: 647bd670b35SErik Nordmark sctp_set_ulp_prop(sctp); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate return (0); 6507c478bd9Sstevel@tonic-gate default: 6517c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state)); 6527c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 6537c478bd9Sstevel@tonic-gate return (EINVAL); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate } 656