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 /* 23481845d8SGeorge 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; 66*5dd46ab5SKacheong Poon 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 130*5dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, acceptor); 131*5dd46ab5SKacheong Poon 1327c478bd9Sstevel@tonic-gate /* 1337c478bd9Sstevel@tonic-gate * listener->sctp_rwnd should be the default window size or a 1347c478bd9Sstevel@tonic-gate * window size changed via SO_RCVBUF option. 1357c478bd9Sstevel@tonic-gate */ 1361d8c4025Svi acceptor->sctp_rwnd = listener->sctp_rwnd; 1371d8c4025Svi acceptor->sctp_irwnd = acceptor->sctp_rwnd; 1387d546a59Svi acceptor->sctp_pd_point = acceptor->sctp_rwnd; 1390f1702c5SYu Xiangning acceptor->sctp_upcalls = listener->sctp_upcalls; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate return (0); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* Process the COOKIE packet, mp, directed at the listener 'sctp' */ 1457c478bd9Sstevel@tonic-gate sctp_t * 1467c478bd9Sstevel@tonic-gate sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len, 147bd670b35SErik Nordmark sctp_init_chunk_t *iack, ip_recv_attr_t *ira) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate sctp_t *eager; 1507c478bd9Sstevel@tonic-gate ip6_t *ip6h; 1517c478bd9Sstevel@tonic-gate int err; 1527c478bd9Sstevel@tonic-gate conn_t *connp, *econnp; 153f4b3ec61Sdh sctp_stack_t *sctps; 1540f1702c5SYu Xiangning struct sock_proto_props sopp; 155de8c4a14SErik Nordmark cred_t *cr; 156de8c4a14SErik Nordmark pid_t cpid; 157bd670b35SErik Nordmark in6_addr_t faddr, laddr; 158bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 159*5dd46ab5SKacheong Poon sctp_listen_cnt_t *slc = sctp->sctp_listen_cnt; 160*5dd46ab5SKacheong Poon boolean_t slc_set = B_FALSE; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * No need to check for duplicate as this is the listener 1647c478bd9Sstevel@tonic-gate * and we are holding the lock. This means that no new 1657c478bd9Sstevel@tonic-gate * connection can be created out of it. And since the 1667c478bd9Sstevel@tonic-gate * fanout already done cannot find a match, it means that 1677c478bd9Sstevel@tonic-gate * there is no duplicate. 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 1707c478bd9Sstevel@tonic-gate 171*5dd46ab5SKacheong Poon connp = sctp->sctp_connp; 172*5dd46ab5SKacheong Poon sctps = sctp->sctp_sctps; 173*5dd46ab5SKacheong Poon 174*5dd46ab5SKacheong Poon /* 175*5dd46ab5SKacheong Poon * Enforce the limit set on the number of connections per listener. 176*5dd46ab5SKacheong Poon * Note that tlc_cnt starts with 1. So need to add 1 to tlc_max 177*5dd46ab5SKacheong Poon * for comparison. 178*5dd46ab5SKacheong Poon */ 179*5dd46ab5SKacheong Poon if (slc != NULL) { 180*5dd46ab5SKacheong Poon int64_t now; 181*5dd46ab5SKacheong Poon 182*5dd46ab5SKacheong Poon if (atomic_add_32_nv(&slc->slc_cnt, 1) > slc->slc_max + 1) { 183*5dd46ab5SKacheong Poon now = ddi_get_lbolt64(); 184*5dd46ab5SKacheong Poon atomic_add_32(&slc->slc_cnt, -1); 185*5dd46ab5SKacheong Poon SCTP_KSTAT(sctps, sctp_listen_cnt_drop); 186*5dd46ab5SKacheong Poon slc->slc_drop++; 187*5dd46ab5SKacheong Poon if (now - slc->slc_report_time > 188*5dd46ab5SKacheong Poon MSEC_TO_TICK(SCTP_SLC_REPORT_INTERVAL)) { 189*5dd46ab5SKacheong Poon zcmn_err(connp->conn_zoneid, CE_WARN, 190*5dd46ab5SKacheong Poon "SCTP listener (port %d) association max " 191*5dd46ab5SKacheong Poon "(%u) reached: %u attempts dropped total\n", 192*5dd46ab5SKacheong Poon ntohs(connp->conn_lport), 193*5dd46ab5SKacheong Poon slc->slc_max, slc->slc_drop); 194*5dd46ab5SKacheong Poon slc->slc_report_time = now; 195*5dd46ab5SKacheong Poon } 196*5dd46ab5SKacheong Poon return (NULL); 197*5dd46ab5SKacheong Poon } 198*5dd46ab5SKacheong Poon slc_set = B_TRUE; 199*5dd46ab5SKacheong Poon } 200*5dd46ab5SKacheong Poon 2017c478bd9Sstevel@tonic-gate if ((eager = sctp_create_eager(sctp)) == NULL) { 202*5dd46ab5SKacheong Poon if (slc_set) 203*5dd46ab5SKacheong Poon atomic_add_32(&slc->slc_cnt, -1); 2047c478bd9Sstevel@tonic-gate return (NULL); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate econnp = eager->sctp_connp; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (connp->conn_policy != NULL) { 209bd670b35SErik Nordmark /* Inherit the policy from the listener; use actions from ira */ 210bd670b35SErik Nordmark if (!ip_ipsec_policy_inherit(econnp, connp, ira)) { 2117c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 212*5dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpListenDrop); 2137c478bd9Sstevel@tonic-gate return (NULL); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 217bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 218bd670b35SErik Nordmark if (ira->ira_flags & IXAF_IS_IPV4) { 219bd670b35SErik Nordmark ipha_t *ipha; 220bd670b35SErik Nordmark 221bd670b35SErik Nordmark ipha = (ipha_t *)ip6h; 222bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr); 223bd670b35SErik Nordmark IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr); 224bd670b35SErik Nordmark } else { 225bd670b35SErik Nordmark laddr = ip6h->ip6_dst; 226bd670b35SErik Nordmark faddr = ip6h->ip6_src; 227bd670b35SErik Nordmark } 228bd670b35SErik Nordmark 229bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) { 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * XXX need to fix the cached policy issue here. 232bd670b35SErik Nordmark * We temporarily set the conn_laddr/conn_faddr here so 2337c478bd9Sstevel@tonic-gate * that IPsec can use it for the latched policy 2347c478bd9Sstevel@tonic-gate * selector. This is obvioursly wrong as SCTP can 2357c478bd9Sstevel@tonic-gate * use different addresses... 2367c478bd9Sstevel@tonic-gate */ 237bd670b35SErik Nordmark econnp->conn_laddr_v6 = laddr; 238bd670b35SErik Nordmark econnp->conn_faddr_v6 = faddr; 239bd670b35SErik Nordmark econnp->conn_saddr_v6 = laddr; 2407c478bd9Sstevel@tonic-gate } 241bd670b35SErik Nordmark if (ipsec_conn_cache_policy(econnp, 242bd670b35SErik Nordmark (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) { 2437c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 244*5dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpListenDrop); 2457c478bd9Sstevel@tonic-gate return (NULL); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 248de8c4a14SErik Nordmark /* Save for getpeerucred */ 249bd670b35SErik Nordmark cr = ira->ira_cred; 250bd670b35SErik Nordmark cpid = ira->ira_cpid; 251bd670b35SErik Nordmark 252bd670b35SErik Nordmark if (is_system_labeled()) { 253bd670b35SErik Nordmark ip_xmit_attr_t *ixa = econnp->conn_ixa; 254bd670b35SErik Nordmark 255bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 256bd670b35SErik Nordmark 257bd670b35SErik Nordmark /* Discard any old label */ 258bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 259bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 260bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 261bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 262bd670b35SErik Nordmark ixa->ixa_tsl = NULL; 263bd670b35SErik Nordmark } 264bd670b35SErik Nordmark 265bd670b35SErik Nordmark if ((connp->conn_mlp_type != mlptSingle || 266bd670b35SErik Nordmark connp->conn_mac_mode != CONN_MAC_DEFAULT) && 267bd670b35SErik Nordmark ira->ira_tsl != NULL) { 268bd670b35SErik Nordmark /* 269bd670b35SErik Nordmark * If this is an MLP connection or a MAC-Exempt 270bd670b35SErik Nordmark * connection with an unlabeled node, packets are to be 271bd670b35SErik Nordmark * exchanged using the security label of the received 272bd670b35SErik Nordmark * Cookie packet instead of the server application's 273bd670b35SErik Nordmark * label. 274bd670b35SErik Nordmark * tsol_check_dest called from ip_set_destination 275bd670b35SErik Nordmark * might later update TSF_UNLABELED by replacing 276bd670b35SErik Nordmark * ixa_tsl with a new label. 277bd670b35SErik Nordmark */ 278bd670b35SErik Nordmark label_hold(ira->ira_tsl); 279bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl); 280bd670b35SErik Nordmark } else { 281bd670b35SErik Nordmark ixa->ixa_tsl = crgetlabel(econnp->conn_cred); 282bd670b35SErik Nordmark } 283bd670b35SErik Nordmark } 284de8c4a14SErik Nordmark 2857c478bd9Sstevel@tonic-gate err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack); 286bd670b35SErik Nordmark if (err != 0) { 2877c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 288*5dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpListenDrop); 2897c478bd9Sstevel@tonic-gate return (NULL); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 292bd670b35SErik Nordmark ASSERT(eager->sctp_current->ixa != NULL); 293bd670b35SErik Nordmark 294bd670b35SErik Nordmark ixa = eager->sctp_current->ixa; 295bd670b35SErik Nordmark if (!(ira->ira_flags & IXAF_IS_IPV4)) { 296bd670b35SErik Nordmark ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4)); 297bd670b35SErik Nordmark 298bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) || 299bd670b35SErik Nordmark IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) { 300bd670b35SErik Nordmark eager->sctp_linklocal = 1; 301bd670b35SErik Nordmark 302bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 303bd670b35SErik Nordmark ixa->ixa_scopeid = ifindex; 304bd670b35SErik Nordmark econnp->conn_incoming_ifindex = ifindex; 305bd670b35SErik Nordmark } 306bd670b35SErik Nordmark } 307bd670b35SErik Nordmark 3081d8c4025Svi /* 3091d8c4025Svi * On a clustered note send this notification to the clustering 3101d8c4025Svi * subsystem. 3111d8c4025Svi */ 3121d8c4025Svi if (cl_sctp_connect != NULL) { 3131d8c4025Svi uchar_t *slist; 3141d8c4025Svi uchar_t *flist; 3151d8c4025Svi size_t fsize; 3161d8c4025Svi size_t ssize; 3171d8c4025Svi 3181d8c4025Svi fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs; 3191d8c4025Svi ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs; 3201d8c4025Svi slist = kmem_alloc(ssize, KM_NOSLEEP); 3211d8c4025Svi flist = kmem_alloc(fsize, KM_NOSLEEP); 3221d8c4025Svi if (slist == NULL || flist == NULL) { 3231d8c4025Svi if (slist != NULL) 3241d8c4025Svi kmem_free(slist, ssize); 3251d8c4025Svi if (flist != NULL) 3261d8c4025Svi kmem_free(flist, fsize); 3271d8c4025Svi sctp_close_eager(eager); 328*5dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpListenDrop); 329f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_cl_connect); 3301d8c4025Svi return (NULL); 3311d8c4025Svi } 3321d8c4025Svi /* The clustering module frees these list */ 3331d8c4025Svi sctp_get_saddr_list(eager, slist, ssize); 3341d8c4025Svi sctp_get_faddr_list(eager, flist, fsize); 335bd670b35SErik Nordmark (*cl_sctp_connect)(econnp->conn_family, slist, 336bd670b35SErik Nordmark eager->sctp_nsaddrs, econnp->conn_lport, flist, 337bd670b35SErik Nordmark eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE, 3381d8c4025Svi (cl_sctp_handle_t)eager); 3391d8c4025Svi } 3401d8c4025Svi 3417c478bd9Sstevel@tonic-gate /* Connection established, so send up the conn_ind */ 3427c478bd9Sstevel@tonic-gate if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd, 343de8c4a14SErik Nordmark (sock_lower_handle_t)eager, NULL, cr, cpid, 3440f1702c5SYu Xiangning &eager->sctp_upcalls)) == NULL) { 3457c478bd9Sstevel@tonic-gate sctp_close_eager(eager); 346*5dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpListenDrop); 3477c478bd9Sstevel@tonic-gate return (NULL); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate ASSERT(SCTP_IS_DETACHED(eager)); 3507c478bd9Sstevel@tonic-gate eager->sctp_detached = B_FALSE; 3510f1702c5SYu Xiangning bzero(&sopp, sizeof (sopp)); 3520f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF; 3530f1702c5SYu Xiangning sopp.sopp_maxblk = strmsgsz; 354bd670b35SErik Nordmark if (econnp->conn_family == AF_INET) { 3550f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3560f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len; 3577c478bd9Sstevel@tonic-gate } else { 3580f1702c5SYu Xiangning sopp.sopp_wroff = sctps->sctps_wroff_xtra + 3590f1702c5SYu Xiangning sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len; 3607c478bd9Sstevel@tonic-gate } 3610f1702c5SYu Xiangning eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp); 3627c478bd9Sstevel@tonic-gate return (eager); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Connect to a peer - this function inserts the sctp in the 3677c478bd9Sstevel@tonic-gate * bind and conn fanouts, sends the INIT, and replies to the client 3687c478bd9Sstevel@tonic-gate * with an OK ack. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate int 371bd670b35SErik Nordmark sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen, 372bd670b35SErik Nordmark cred_t *cr, pid_t pid) 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate sin_t *sin; 3757c478bd9Sstevel@tonic-gate sin6_t *sin6; 3767c478bd9Sstevel@tonic-gate in6_addr_t dstaddr; 3777c478bd9Sstevel@tonic-gate in_port_t dstport; 3787c478bd9Sstevel@tonic-gate mblk_t *initmp; 3797c478bd9Sstevel@tonic-gate sctp_tf_t *tbf; 3807c478bd9Sstevel@tonic-gate sctp_t *lsctp; 3817c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 3827c478bd9Sstevel@tonic-gate int sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP; 38345916cd2Sjpk int err; 3847c478bd9Sstevel@tonic-gate sctp_faddr_t *cur_fp; 385f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 386bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 387bd670b35SErik Nordmark uint_t scope_id = 0; 388bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * Determine packet type based on type of address passed in 3927c478bd9Sstevel@tonic-gate * the request should contain an IPv4 or IPv6 address. 3937c478bd9Sstevel@tonic-gate * Make sure that address family matches the type of 394bd670b35SErik Nordmark * family of the address passed down. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate if (addrlen < sizeof (sin_t)) { 3977c478bd9Sstevel@tonic-gate return (EINVAL); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate switch (dst->sa_family) { 4007c478bd9Sstevel@tonic-gate case AF_INET: 4017c478bd9Sstevel@tonic-gate sin = (sin_t *)dst; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast */ 404c4f4b3c8Skcpoon if (CLASSD(sin->sin_addr.s_addr) || 4057c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr == INADDR_BROADCAST)) { 4067c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 4077c478bd9Sstevel@tonic-gate return (EINVAL); 4087c478bd9Sstevel@tonic-gate } 409bd670b35SErik Nordmark if (connp->conn_ipv6_v6only) 4107c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* convert to v6 mapped */ 4137c478bd9Sstevel@tonic-gate /* Check for attempt to connect to INADDR_ANY */ 4147c478bd9Sstevel@tonic-gate if (sin->sin_addr.s_addr == INADDR_ANY) { 4157c478bd9Sstevel@tonic-gate struct in_addr v4_addr; 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * SunOS 4.x and 4.3 BSD allow an application 4187c478bd9Sstevel@tonic-gate * to connect a TCP socket to INADDR_ANY. 4197c478bd9Sstevel@tonic-gate * When they do this, the kernel picks the 4207c478bd9Sstevel@tonic-gate * address of one interface and uses it 4217c478bd9Sstevel@tonic-gate * instead. The kernel usually ends up 4227c478bd9Sstevel@tonic-gate * picking the address of the loopback 4237c478bd9Sstevel@tonic-gate * interface. This is an undocumented feature. 4247c478bd9Sstevel@tonic-gate * However, we provide the same thing here 4257c478bd9Sstevel@tonic-gate * in case any TCP apps that use this feature 4267c478bd9Sstevel@tonic-gate * are being ported to SCTP... 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate v4_addr.s_addr = htonl(INADDR_LOOPBACK); 4297c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr); 4307c478bd9Sstevel@tonic-gate } else { 4317c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate dstport = sin->sin_port; 4347c478bd9Sstevel@tonic-gate break; 4357c478bd9Sstevel@tonic-gate case AF_INET6: 4367c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)dst; 4377c478bd9Sstevel@tonic-gate /* Check for attempt to connect to non-unicast. */ 4387c478bd9Sstevel@tonic-gate if ((addrlen < sizeof (sin6_t)) || 4397c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 4407c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: non-unicast\n")); 4417c478bd9Sstevel@tonic-gate return (EINVAL); 4427c478bd9Sstevel@tonic-gate } 443bd670b35SErik Nordmark if (connp->conn_ipv6_v6only && 4447c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 4457c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate /* check for attempt to connect to unspec */ 4487c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4497c478bd9Sstevel@tonic-gate dstaddr = ipv6_loopback; 4507c478bd9Sstevel@tonic-gate } else { 4517c478bd9Sstevel@tonic-gate dstaddr = sin6->sin6_addr; 452bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) { 453f551bb10Svi sctp->sctp_linklocal = 1; 454bd670b35SErik Nordmark scope_id = sin6->sin6_scope_id; 455bd670b35SErik Nordmark } 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate dstport = sin6->sin6_port; 458bd670b35SErik Nordmark connp->conn_flowinfo = sin6->sin6_flowinfo; 4597c478bd9Sstevel@tonic-gate break; 4607c478bd9Sstevel@tonic-gate default: 4617c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: unknown family %d\n", 462b34b8d1aSkcpoon dst->sa_family)); 4637c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf)); 4677c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: attempting connect to %s...\n", buf)); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate RUN_SCTP(sctp); 4707c478bd9Sstevel@tonic-gate 471bd670b35SErik Nordmark if (connp->conn_family != dst->sa_family || 472bd670b35SErik Nordmark (connp->conn_state_flags & CONN_CLOSING)) { 4737c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 4747c478bd9Sstevel@tonic-gate return (EINVAL); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 477bd670b35SErik Nordmark /* We update our cred/cpid based on the caller of connect */ 478bd670b35SErik Nordmark if (connp->conn_cred != cr) { 479bd670b35SErik Nordmark crhold(cr); 480bd670b35SErik Nordmark crfree(connp->conn_cred); 481bd670b35SErik Nordmark connp->conn_cred = cr; 482bd670b35SErik Nordmark } 483bd670b35SErik Nordmark connp->conn_cpid = pid; 484bd670b35SErik Nordmark 485bd670b35SErik Nordmark /* Cache things in conn_ixa without any refhold */ 486bd670b35SErik Nordmark ixa = connp->conn_ixa; 487be4c8f74SErik Nordmark ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED)); 488bd670b35SErik Nordmark ixa->ixa_cred = cr; 489bd670b35SErik Nordmark ixa->ixa_cpid = pid; 490bd670b35SErik Nordmark if (is_system_labeled()) { 491bd670b35SErik Nordmark /* We need to restart with a label based on the cred */ 492bd670b35SErik Nordmark ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred); 493bd670b35SErik Nordmark } 494bd670b35SErik Nordmark 4957c478bd9Sstevel@tonic-gate switch (sctp->sctp_state) { 4967c478bd9Sstevel@tonic-gate case SCTPS_IDLE: { 4971d8c4025Svi struct sockaddr_storage ss; 4981d8c4025Svi 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * We support a quick connect capability here, allowing 5017c478bd9Sstevel@tonic-gate * clients to transition directly from IDLE to COOKIE_WAIT. 5027c478bd9Sstevel@tonic-gate * sctp_bindi will pick an unused port, insert the connection 5037c478bd9Sstevel@tonic-gate * in the bind hash and transition to BOUND state. SCTP 5047c478bd9Sstevel@tonic-gate * picks and uses what it considers the optimal local address 5057c478bd9Sstevel@tonic-gate * set (just like specifiying INADDR_ANY to bind()). 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate dprint(1, ("sctp_connect: idle, attempting bind...\n")); 5087c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs == 0); 5097c478bd9Sstevel@tonic-gate 5101d8c4025Svi bzero(&ss, sizeof (ss)); 511bd670b35SErik Nordmark ss.ss_family = connp->conn_family; 5121d8c4025Svi WAKE_SCTP(sctp); 5131d8c4025Svi if ((err = sctp_bind(sctp, (struct sockaddr *)&ss, 5141d8c4025Svi sizeof (ss))) != 0) { 5157c478bd9Sstevel@tonic-gate return (err); 5167c478bd9Sstevel@tonic-gate } 5171d8c4025Svi RUN_SCTP(sctp); 5187c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate case SCTPS_BOUND: 5227c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs > 0); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* do the connect */ 5257c478bd9Sstevel@tonic-gate /* XXX check for attempt to connect to self */ 526bd670b35SErik Nordmark connp->conn_fport = dstport; 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * Don't allow this connection to completely duplicate 5307c478bd9Sstevel@tonic-gate * an existing connection. 5317c478bd9Sstevel@tonic-gate * 5327c478bd9Sstevel@tonic-gate * Ensure that the duplicate check and insertion is atomic. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 535f4b3ec61Sdh tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, 536bd670b35SErik Nordmark connp->conn_ports)]; 5377c478bd9Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 538bd670b35SErik Nordmark lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports, 5397c478bd9Sstevel@tonic-gate SCTPS_COOKIE_WAIT); 5407c478bd9Sstevel@tonic-gate if (lsctp != NULL) { 5417c478bd9Sstevel@tonic-gate /* found a duplicate connection */ 5427c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5437c478bd9Sstevel@tonic-gate SCTP_REFRELE(lsctp); 5447c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5457c478bd9Sstevel@tonic-gate return (EADDRINUSE); 5467c478bd9Sstevel@tonic-gate } 547bd670b35SErik Nordmark 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * OK; set up the peer addr (this may grow after we get 5507c478bd9Sstevel@tonic-gate * the INIT ACK from the peer with additional addresses). 5517c478bd9Sstevel@tonic-gate */ 55277c67f2fSkcpoon if ((err = sctp_add_faddr(sctp, &dstaddr, sleep, 55377c67f2fSkcpoon B_FALSE)) != 0) { 5547c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5557c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 55645916cd2Sjpk return (err); 5577c478bd9Sstevel@tonic-gate } 558c31292eeSkcpoon cur_fp = sctp->sctp_faddrs; 559bd670b35SErik Nordmark ASSERT(cur_fp->ixa != NULL); 560c31292eeSkcpoon 5617c478bd9Sstevel@tonic-gate /* No valid src addr, return. */ 562c31292eeSkcpoon if (cur_fp->state == SCTP_FADDRS_UNREACH) { 5637c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5647c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 5657c478bd9Sstevel@tonic-gate return (EADDRNOTAVAIL); 5667c478bd9Sstevel@tonic-gate } 567c31292eeSkcpoon 568c31292eeSkcpoon sctp->sctp_primary = cur_fp; 569c31292eeSkcpoon sctp->sctp_current = cur_fp; 570c31292eeSkcpoon sctp->sctp_mss = cur_fp->sfa_pmss; 5717c478bd9Sstevel@tonic-gate sctp_conn_hash_insert(tbf, sctp, 1); 5727c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 5737c478bd9Sstevel@tonic-gate 574bd670b35SErik Nordmark ixa = cur_fp->ixa; 575bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 576bd670b35SErik Nordmark 577bd670b35SErik Nordmark if (scope_id != 0) { 578bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_SCOPEID_SET; 579bd670b35SErik Nordmark ixa->ixa_scopeid = scope_id; 580bd670b35SErik Nordmark } else { 581bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_SCOPEID_SET; 582bd670b35SErik Nordmark } 583bd670b35SErik Nordmark 5847c478bd9Sstevel@tonic-gate /* initialize composite headers */ 58577c67f2fSkcpoon if ((err = sctp_set_hdraddrs(sctp)) != 0) { 58645916cd2Sjpk sctp_conn_hash_remove(sctp); 58745916cd2Sjpk WAKE_SCTP(sctp); 58845916cd2Sjpk return (err); 58945916cd2Sjpk } 5907c478bd9Sstevel@tonic-gate 591bd670b35SErik Nordmark if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) { 592bd670b35SErik Nordmark sctp_conn_hash_remove(sctp); 593bd670b35SErik Nordmark WAKE_SCTP(sctp); 594bd670b35SErik Nordmark return (err); 595f4b3ec61Sdh } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Turn off the don't fragment bit on the (only) faddr, 5997c478bd9Sstevel@tonic-gate * so that if one of the messages exchanged during the 6007c478bd9Sstevel@tonic-gate * initialization sequence exceeds the path mtu, it 6017c478bd9Sstevel@tonic-gate * at least has a chance to get there. SCTP does no 6027c478bd9Sstevel@tonic-gate * fragmentation of initialization messages. The DF bit 6037c478bd9Sstevel@tonic-gate * will be turned on again in sctp_send_cookie_echo() 6047c478bd9Sstevel@tonic-gate * (but the cookie echo will still be sent with the df bit 6057c478bd9Sstevel@tonic-gate * off). 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate cur_fp->df = B_FALSE; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* Mark this address as alive */ 6107c478bd9Sstevel@tonic-gate cur_fp->state = SCTP_FADDRS_ALIVE; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* Send the INIT to the peer */ 6137c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto); 614c31292eeSkcpoon sctp->sctp_state = SCTPS_COOKIE_WAIT; 615f551bb10Svi /* 616f551bb10Svi * sctp_init_mp() could result in modifying the source 617f551bb10Svi * address list, so take the hash lock. 618f551bb10Svi */ 619f551bb10Svi mutex_enter(&tbf->tf_lock); 620bd670b35SErik Nordmark initmp = sctp_init_mp(sctp, cur_fp); 6217c478bd9Sstevel@tonic-gate if (initmp == NULL) { 622f551bb10Svi mutex_exit(&tbf->tf_lock); 623c31292eeSkcpoon /* 624c31292eeSkcpoon * It may happen that all the source addresses 625c31292eeSkcpoon * (loopback/link local) are removed. In that case, 626c31292eeSkcpoon * faile the connect. 627c31292eeSkcpoon */ 628c31292eeSkcpoon if (sctp->sctp_nsaddrs == 0) { 629c31292eeSkcpoon sctp_conn_hash_remove(sctp); 630c31292eeSkcpoon SCTP_FADDR_TIMER_STOP(cur_fp); 631c31292eeSkcpoon WAKE_SCTP(sctp); 632c31292eeSkcpoon return (EADDRNOTAVAIL); 633c31292eeSkcpoon } 634c31292eeSkcpoon 635c31292eeSkcpoon /* Otherwise, let the retransmission timer retry */ 6367c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 637c31292eeSkcpoon goto notify_ulp; 6387c478bd9Sstevel@tonic-gate } 639f551bb10Svi mutex_exit(&tbf->tf_lock); 640c31292eeSkcpoon 6411d8c4025Svi /* 6421d8c4025Svi * On a clustered note send this notification to the clustering 6431d8c4025Svi * subsystem. 6441d8c4025Svi */ 6451d8c4025Svi if (cl_sctp_connect != NULL) { 6461d8c4025Svi uchar_t *slist; 6471d8c4025Svi uchar_t *flist; 6481d8c4025Svi size_t ssize; 6491d8c4025Svi size_t fsize; 6501d8c4025Svi 6511d8c4025Svi fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 6521d8c4025Svi ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 6531d8c4025Svi slist = kmem_alloc(ssize, KM_SLEEP); 6541d8c4025Svi flist = kmem_alloc(fsize, KM_SLEEP); 6551d8c4025Svi /* The clustering module frees the lists */ 6561d8c4025Svi sctp_get_saddr_list(sctp, slist, ssize); 6571d8c4025Svi sctp_get_faddr_list(sctp, flist, fsize); 658bd670b35SErik Nordmark (*cl_sctp_connect)(connp->conn_family, slist, 659bd670b35SErik Nordmark sctp->sctp_nsaddrs, connp->conn_lport, 660bd670b35SErik Nordmark flist, sctp->sctp_nfaddrs, connp->conn_fport, 6611d8c4025Svi B_TRUE, (cl_sctp_handle_t)sctp); 6621d8c4025Svi } 663bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 664bd670b35SErik Nordmark ASSERT(ixa->ixa_ire != NULL); 665bd670b35SErik Nordmark 666bd670b35SErik Nordmark (void) conn_ip_output(initmp, ixa); 6677c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts); 668bd670b35SErik Nordmark WAKE_SCTP(sctp); 6697c478bd9Sstevel@tonic-gate 670c31292eeSkcpoon notify_ulp: 671bd670b35SErik Nordmark sctp_set_ulp_prop(sctp); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate return (0); 6747c478bd9Sstevel@tonic-gate default: 6757c478bd9Sstevel@tonic-gate ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state)); 6767c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 6777c478bd9Sstevel@tonic-gate return (EINVAL); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate } 680