10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate 220Sstevel@tonic-gate /* 23*12339Sanil.udupa@sun.com * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/socket.h> 270Sstevel@tonic-gate #include <sys/ddi.h> 280Sstevel@tonic-gate #include <sys/sunddi.h> 291676Sjpk #include <sys/tsol/tndb.h> 301676Sjpk #include <sys/tsol/tnet.h> 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <netinet/in.h> 330Sstevel@tonic-gate #include <netinet/ip6.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <inet/common.h> 360Sstevel@tonic-gate #include <inet/ip.h> 370Sstevel@tonic-gate #include <inet/ip6.h> 380Sstevel@tonic-gate #include <inet/ipclassifier.h> 390Sstevel@tonic-gate #include <inet/ipsec_impl.h> 400Sstevel@tonic-gate #include <inet/ipp_common.h> 410Sstevel@tonic-gate #include <inet/sctp_ip.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include "sctp_impl.h" 440Sstevel@tonic-gate #include "sctp_addr.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* Default association hash size. The size must be a power of 2. */ 470Sstevel@tonic-gate #define SCTP_CONN_HASH_SIZE 8192 480Sstevel@tonic-gate 493448Sdh155122 uint_t sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; /* /etc/system */ 500Sstevel@tonic-gate 51852Svi117747 /* 52852Svi117747 * Cluster networking hook for traversing current assoc list. 53852Svi117747 * This routine is used to extract the current list of live associations 54852Svi117747 * which must continue to to be dispatched to this node. 55852Svi117747 */ 56852Svi117747 int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *, 57852Svi117747 boolean_t); 583448Sdh155122 static int cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, 593448Sdh155122 void *), void *arg, boolean_t cansleep, sctp_stack_t *sctps); 60852Svi117747 610Sstevel@tonic-gate void 623448Sdh155122 sctp_hash_init(sctp_stack_t *sctps) 630Sstevel@tonic-gate { 640Sstevel@tonic-gate int i; 650Sstevel@tonic-gate 663448Sdh155122 /* Start with /etc/system value */ 673448Sdh155122 sctps->sctps_conn_hash_size = sctp_conn_hash_size; 683448Sdh155122 693448Sdh155122 if (sctps->sctps_conn_hash_size & (sctps->sctps_conn_hash_size - 1)) { 700Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */ 710Sstevel@tonic-gate for (i = 0; i < 31; i++) { 723448Sdh155122 if (sctps->sctps_conn_hash_size < (1 << i)) 730Sstevel@tonic-gate break; 740Sstevel@tonic-gate } 753448Sdh155122 sctps->sctps_conn_hash_size = 1 << i; 760Sstevel@tonic-gate } 773448Sdh155122 if (sctps->sctps_conn_hash_size < SCTP_CONN_HASH_SIZE) { 783448Sdh155122 sctps->sctps_conn_hash_size = SCTP_CONN_HASH_SIZE; 790Sstevel@tonic-gate cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n", 803448Sdh155122 sctps->sctps_conn_hash_size); 810Sstevel@tonic-gate } 823448Sdh155122 sctps->sctps_conn_fanout = 837480SKacheong.Poon@Sun.COM (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size * 8411042SErik.Nordmark@Sun.COM sizeof (sctp_tf_t), KM_SLEEP); 853448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 863448Sdh155122 mutex_init(&sctps->sctps_conn_fanout[i].tf_lock, NULL, 877480SKacheong.Poon@Sun.COM MUTEX_DEFAULT, NULL); 880Sstevel@tonic-gate } 893448Sdh155122 sctps->sctps_listen_fanout = kmem_zalloc(SCTP_LISTEN_FANOUT_SIZE * 903448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 913448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 923448Sdh155122 mutex_init(&sctps->sctps_listen_fanout[i].tf_lock, NULL, 930Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 940Sstevel@tonic-gate } 953448Sdh155122 sctps->sctps_bind_fanout = kmem_zalloc(SCTP_BIND_FANOUT_SIZE * 963448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 973448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 983448Sdh155122 mutex_init(&sctps->sctps_bind_fanout[i].tf_lock, NULL, 990Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate void 1043448Sdh155122 sctp_hash_destroy(sctp_stack_t *sctps) 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate int i; 1070Sstevel@tonic-gate 1083448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 1093448Sdh155122 mutex_destroy(&sctps->sctps_conn_fanout[i].tf_lock); 1103448Sdh155122 } 1113448Sdh155122 kmem_free(sctps->sctps_conn_fanout, sctps->sctps_conn_hash_size * 1123448Sdh155122 sizeof (sctp_tf_t)); 1133448Sdh155122 sctps->sctps_conn_fanout = NULL; 1143448Sdh155122 1153448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 1163448Sdh155122 mutex_destroy(&sctps->sctps_listen_fanout[i].tf_lock); 1170Sstevel@tonic-gate } 1183448Sdh155122 kmem_free(sctps->sctps_listen_fanout, SCTP_LISTEN_FANOUT_SIZE * 1193448Sdh155122 sizeof (sctp_tf_t)); 1203448Sdh155122 sctps->sctps_listen_fanout = NULL; 1213448Sdh155122 1223448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 1233448Sdh155122 mutex_destroy(&sctps->sctps_bind_fanout[i].tf_lock); 1240Sstevel@tonic-gate } 1253448Sdh155122 kmem_free(sctps->sctps_bind_fanout, SCTP_BIND_FANOUT_SIZE * 1263448Sdh155122 sizeof (sctp_tf_t)); 1273448Sdh155122 sctps->sctps_bind_fanout = NULL; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1301932Svi117747 /* 131852Svi117747 * Exported routine for extracting active SCTP associations. 132852Svi117747 * Like TCP, we terminate the walk if the callback returns non-zero. 1333448Sdh155122 * 1343448Sdh155122 * Need to walk all sctp_stack_t instances since this clustering 1353448Sdh155122 * interface is assumed global for all instances 136852Svi117747 */ 137852Svi117747 int 1383448Sdh155122 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), 1393448Sdh155122 void *arg, boolean_t cansleep) 1403448Sdh155122 { 1413448Sdh155122 netstack_handle_t nh; 1423448Sdh155122 netstack_t *ns; 1433448Sdh155122 int ret = 0; 1443448Sdh155122 1453448Sdh155122 netstack_next_init(&nh); 1463448Sdh155122 while ((ns = netstack_next(&nh)) != NULL) { 1473448Sdh155122 ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep, 1483448Sdh155122 ns->netstack_sctp); 1493448Sdh155122 netstack_rele(ns); 1503448Sdh155122 } 1513448Sdh155122 netstack_next_fini(&nh); 1523448Sdh155122 return (ret); 1533448Sdh155122 } 1543448Sdh155122 1553448Sdh155122 static int 1563448Sdh155122 cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *), 1573448Sdh155122 void *arg, boolean_t cansleep, sctp_stack_t *sctps) 158852Svi117747 { 159852Svi117747 sctp_t *sctp; 160852Svi117747 sctp_t *sctp_prev; 161852Svi117747 cl_sctp_info_t cl_sctpi; 162852Svi117747 uchar_t *slist; 163852Svi117747 uchar_t *flist; 164852Svi117747 165852Svi117747 sctp_prev = NULL; 1663448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 16711042SErik.Nordmark@Sun.COM sctp = list_head(&sctps->sctps_g_list); 168852Svi117747 while (sctp != NULL) { 169852Svi117747 size_t ssize; 170852Svi117747 size_t fsize; 171852Svi117747 172852Svi117747 mutex_enter(&sctp->sctp_reflock); 173852Svi117747 if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) { 174852Svi117747 mutex_exit(&sctp->sctp_reflock); 1753448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 176852Svi117747 continue; 177852Svi117747 } 178852Svi117747 sctp->sctp_refcnt++; 179852Svi117747 mutex_exit(&sctp->sctp_reflock); 1803448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 181852Svi117747 if (sctp_prev != NULL) 182852Svi117747 SCTP_REFRELE(sctp_prev); 183852Svi117747 RUN_SCTP(sctp); 184852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 185852Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 186852Svi117747 187852Svi117747 slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP); 188852Svi117747 flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP); 189852Svi117747 if (slist == NULL || flist == NULL) { 190852Svi117747 WAKE_SCTP(sctp); 191852Svi117747 if (slist != NULL) 192852Svi117747 kmem_free(slist, ssize); 193852Svi117747 if (flist != NULL) 194852Svi117747 kmem_free(flist, fsize); 195852Svi117747 SCTP_REFRELE(sctp); 196852Svi117747 return (1); 197852Svi117747 } 198852Svi117747 cl_sctpi.cl_sctpi_version = CL_SCTPI_V1; 199852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 200852Svi117747 sctp_get_faddr_list(sctp, flist, fsize); 201852Svi117747 cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs; 202852Svi117747 cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs; 20311042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_family = sctp->sctp_connp->conn_family; 20411042SErik.Nordmark@Sun.COM if (cl_sctpi.cl_sctpi_family == AF_INET) 20511042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_ipversion = IPV4_VERSION; 20611042SErik.Nordmark@Sun.COM else 20711042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_ipversion = IPV6_VERSION; 208852Svi117747 cl_sctpi.cl_sctpi_state = sctp->sctp_state; 20911042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_lport = sctp->sctp_connp->conn_lport; 21011042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_fport = sctp->sctp_connp->conn_fport; 211852Svi117747 cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp; 212852Svi117747 WAKE_SCTP(sctp); 213852Svi117747 cl_sctpi.cl_sctpi_laddrp = slist; 214852Svi117747 cl_sctpi.cl_sctpi_faddrp = flist; 215852Svi117747 if ((*cl_callback)(&cl_sctpi, arg) != 0) { 216852Svi117747 kmem_free(slist, ssize); 217852Svi117747 kmem_free(flist, fsize); 218852Svi117747 SCTP_REFRELE(sctp); 219852Svi117747 return (1); 220852Svi117747 } 221852Svi117747 /* list will be freed by cl_callback */ 222852Svi117747 sctp_prev = sctp; 2233448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 2243448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 225852Svi117747 } 2263448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 227852Svi117747 if (sctp_prev != NULL) 228852Svi117747 SCTP_REFRELE(sctp_prev); 229852Svi117747 return (0); 230852Svi117747 } 231852Svi117747 2320Sstevel@tonic-gate sctp_t * 233*12339Sanil.udupa@sun.com sctp_conn_match(in6_addr_t **faddrpp, uint32_t nfaddr, in6_addr_t *laddr, 234*12339Sanil.udupa@sun.com uint32_t ports, zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps) 2350Sstevel@tonic-gate { 2360Sstevel@tonic-gate sctp_tf_t *tf; 2370Sstevel@tonic-gate sctp_t *sctp; 2380Sstevel@tonic-gate sctp_faddr_t *fp; 23911042SErik.Nordmark@Sun.COM conn_t *connp; 240*12339Sanil.udupa@sun.com in6_addr_t **faddrs, **endaddrs = &faddrpp[nfaddr]; 2410Sstevel@tonic-gate 2423448Sdh155122 tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]); 2430Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 2440Sstevel@tonic-gate 245*12339Sanil.udupa@sun.com for (sctp = tf->tf_sctp; sctp != NULL; sctp = 246*12339Sanil.udupa@sun.com sctp->sctp_conn_hash_next) { 24711042SErik.Nordmark@Sun.COM connp = sctp->sctp_connp; 24811042SErik.Nordmark@Sun.COM if (ports != connp->conn_ports) 2490Sstevel@tonic-gate continue; 25011042SErik.Nordmark@Sun.COM if (!(connp->conn_zoneid == zoneid || 25111042SErik.Nordmark@Sun.COM connp->conn_allzones || 25211042SErik.Nordmark@Sun.COM ((connp->conn_mac_mode != CONN_MAC_DEFAULT) && 25311042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_MAC_EXEMPTABLE) && 25411042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_SHARED_ADDR)))) 25511042SErik.Nordmark@Sun.COM continue; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* check for faddr match */ 258*12339Sanil.udupa@sun.com for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { 259*12339Sanil.udupa@sun.com for (faddrs = faddrpp; faddrs < endaddrs; faddrs++) { 260*12339Sanil.udupa@sun.com if (IN6_ARE_ADDR_EQUAL(*faddrs, &fp->faddr)) { 261*12339Sanil.udupa@sun.com /* check for laddr match */ 262*12339Sanil.udupa@sun.com if (sctp_saddr_lookup(sctp, laddr, 0) 263*12339Sanil.udupa@sun.com != NULL) { 264*12339Sanil.udupa@sun.com SCTP_REFHOLD(sctp); 265*12339Sanil.udupa@sun.com mutex_exit(&tf->tf_lock); 266*12339Sanil.udupa@sun.com return (sctp); 267*12339Sanil.udupa@sun.com } 268*12339Sanil.udupa@sun.com } 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* no match; continue to the next in the chain */ 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 2760Sstevel@tonic-gate return (sctp); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate static sctp_t * 2803510Svi117747 listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid, 28111042SErik.Nordmark@Sun.COM iaflags_t iraflags, sctp_stack_t *sctps) 2820Sstevel@tonic-gate { 2830Sstevel@tonic-gate sctp_t *sctp; 2840Sstevel@tonic-gate sctp_tf_t *tf; 2850Sstevel@tonic-gate uint16_t lport; 28611042SErik.Nordmark@Sun.COM conn_t *connp; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate lport = ((uint16_t *)&ports)[1]; 2890Sstevel@tonic-gate 2903448Sdh155122 tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]); 2910Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) { 29411042SErik.Nordmark@Sun.COM connp = sctp->sctp_connp; 29511042SErik.Nordmark@Sun.COM if (lport != connp->conn_lport) 2960Sstevel@tonic-gate continue; 29711042SErik.Nordmark@Sun.COM 29811042SErik.Nordmark@Sun.COM if (!(connp->conn_zoneid == zoneid || 29911042SErik.Nordmark@Sun.COM connp->conn_allzones || 30011042SErik.Nordmark@Sun.COM ((connp->conn_mac_mode != CONN_MAC_DEFAULT) && 30111042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_MAC_EXEMPTABLE) && 30211042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_SHARED_ADDR)))) 30311042SErik.Nordmark@Sun.COM continue; 3040Sstevel@tonic-gate 3053510Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 3063510Svi117747 SCTP_REFHOLD(sctp); 3073510Svi117747 goto done; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate /* no match; continue to the next in the chain */ 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate done: 3130Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3140Sstevel@tonic-gate return (sctp); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3171676Sjpk /* called by ipsec_sctp_pol */ 3180Sstevel@tonic-gate conn_t * 3190Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 32011042SErik.Nordmark@Sun.COM zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps) 3210Sstevel@tonic-gate { 3220Sstevel@tonic-gate sctp_t *sctp; 3230Sstevel@tonic-gate 324*12339Sanil.udupa@sun.com sctp = sctp_conn_match(&src, 1, dst, ports, zoneid, iraflags, sctps); 32511042SErik.Nordmark@Sun.COM if (sctp == NULL) { 3260Sstevel@tonic-gate /* Not in conn fanout; check listen fanout */ 32711042SErik.Nordmark@Sun.COM sctp = listen_match(dst, ports, zoneid, iraflags, sctps); 32811042SErik.Nordmark@Sun.COM if (sctp == NULL) 3290Sstevel@tonic-gate return (NULL); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate return (sctp->sctp_connp); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 33411042SErik.Nordmark@Sun.COM /* 335*12339Sanil.udupa@sun.com * This is called from sctp_fanout() with IP header src & dst addresses. 336*12339Sanil.udupa@sun.com * First call sctp_conn_match() to get a match by passing in src & dst 337*12339Sanil.udupa@sun.com * addresses from IP header. 338*12339Sanil.udupa@sun.com * However sctp_conn_match() can return no match under condition such as : 339*12339Sanil.udupa@sun.com * A host can send an INIT ACK from a different address than the INIT was sent 340*12339Sanil.udupa@sun.com * to (in a multi-homed env). 341*12339Sanil.udupa@sun.com * According to RFC4960, a host can send additional addresses in an INIT 342*12339Sanil.udupa@sun.com * ACK chunk. 343*12339Sanil.udupa@sun.com * Therefore extract all addresses from the INIT ACK chunk, pass to 344*12339Sanil.udupa@sun.com * sctp_conn_match() to get a match. 345*12339Sanil.udupa@sun.com */ 346*12339Sanil.udupa@sun.com static sctp_t * 347*12339Sanil.udupa@sun.com sctp_lookup_by_faddrs(mblk_t *mp, sctp_hdr_t *sctph, in6_addr_t *srcp, 348*12339Sanil.udupa@sun.com in6_addr_t *dstp, uint32_t ports, zoneid_t zoneid, sctp_stack_t *sctps, 349*12339Sanil.udupa@sun.com iaflags_t iraflags) 350*12339Sanil.udupa@sun.com { 351*12339Sanil.udupa@sun.com sctp_t *sctp; 352*12339Sanil.udupa@sun.com sctp_chunk_hdr_t *ich; 353*12339Sanil.udupa@sun.com sctp_init_chunk_t *iack; 354*12339Sanil.udupa@sun.com sctp_parm_hdr_t *ph; 355*12339Sanil.udupa@sun.com ssize_t mlen, remaining; 356*12339Sanil.udupa@sun.com uint16_t param_type, addr_len = PARM_ADDR4_LEN; 357*12339Sanil.udupa@sun.com in6_addr_t src; 358*12339Sanil.udupa@sun.com in6_addr_t **addrbuf = NULL, **faddrpp = NULL; 359*12339Sanil.udupa@sun.com boolean_t isv4; 360*12339Sanil.udupa@sun.com uint32_t totaddr, nfaddr = 0; 361*12339Sanil.udupa@sun.com 362*12339Sanil.udupa@sun.com /* 363*12339Sanil.udupa@sun.com * If we get a match with the passed-in IP header src & dst addresses, 364*12339Sanil.udupa@sun.com * quickly return the matched sctp. 365*12339Sanil.udupa@sun.com */ 366*12339Sanil.udupa@sun.com if ((sctp = sctp_conn_match(&srcp, 1, dstp, ports, zoneid, iraflags, 367*12339Sanil.udupa@sun.com sctps)) != NULL) { 368*12339Sanil.udupa@sun.com return (sctp); 369*12339Sanil.udupa@sun.com } 370*12339Sanil.udupa@sun.com 371*12339Sanil.udupa@sun.com /* 372*12339Sanil.udupa@sun.com * Currently sctph is set to NULL in icmp error fanout case 373*12339Sanil.udupa@sun.com * (ip_fanout_sctp()). 374*12339Sanil.udupa@sun.com * The above sctp_conn_match() should handle that, otherwise 375*12339Sanil.udupa@sun.com * return no match found. 376*12339Sanil.udupa@sun.com */ 377*12339Sanil.udupa@sun.com if (sctph == NULL) 378*12339Sanil.udupa@sun.com return (NULL); 379*12339Sanil.udupa@sun.com 380*12339Sanil.udupa@sun.com /* 381*12339Sanil.udupa@sun.com * Do a pullup again in case the previous one was partially successful, 382*12339Sanil.udupa@sun.com * so try to complete the pullup here and have a single contiguous 383*12339Sanil.udupa@sun.com * chunk for processing of entire INIT ACK chunk below. 384*12339Sanil.udupa@sun.com */ 385*12339Sanil.udupa@sun.com if (mp->b_cont != NULL) { 386*12339Sanil.udupa@sun.com if (pullupmsg(mp, -1) == 0) { 387*12339Sanil.udupa@sun.com return (NULL); 388*12339Sanil.udupa@sun.com } 389*12339Sanil.udupa@sun.com } 390*12339Sanil.udupa@sun.com 391*12339Sanil.udupa@sun.com mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 392*12339Sanil.udupa@sun.com if ((ich = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) { 393*12339Sanil.udupa@sun.com return (NULL); 394*12339Sanil.udupa@sun.com } 395*12339Sanil.udupa@sun.com 396*12339Sanil.udupa@sun.com if (ich->sch_id == CHUNK_INIT_ACK) { 397*12339Sanil.udupa@sun.com remaining = ntohs(ich->sch_len) - sizeof (*ich) - 398*12339Sanil.udupa@sun.com sizeof (*iack); 399*12339Sanil.udupa@sun.com if (remaining < sizeof (*ph)) { 400*12339Sanil.udupa@sun.com return (NULL); 401*12339Sanil.udupa@sun.com } 402*12339Sanil.udupa@sun.com 403*12339Sanil.udupa@sun.com isv4 = (iraflags & IRAF_IS_IPV4) ? B_TRUE : B_FALSE; 404*12339Sanil.udupa@sun.com if (!isv4) 405*12339Sanil.udupa@sun.com addr_len = PARM_ADDR6_LEN; 406*12339Sanil.udupa@sun.com totaddr = remaining/addr_len; 407*12339Sanil.udupa@sun.com 408*12339Sanil.udupa@sun.com iack = (sctp_init_chunk_t *)(ich + 1); 409*12339Sanil.udupa@sun.com ph = (sctp_parm_hdr_t *)(iack + 1); 410*12339Sanil.udupa@sun.com 411*12339Sanil.udupa@sun.com addrbuf = (in6_addr_t **) 412*12339Sanil.udupa@sun.com kmem_zalloc(totaddr * sizeof (in6_addr_t *), KM_NOSLEEP); 413*12339Sanil.udupa@sun.com if (addrbuf == NULL) 414*12339Sanil.udupa@sun.com return (NULL); 415*12339Sanil.udupa@sun.com faddrpp = addrbuf; 416*12339Sanil.udupa@sun.com 417*12339Sanil.udupa@sun.com while (ph != NULL) { 418*12339Sanil.udupa@sun.com /* 419*12339Sanil.udupa@sun.com * According to RFC4960 : 420*12339Sanil.udupa@sun.com * All integer fields in an SCTP packet MUST be 421*12339Sanil.udupa@sun.com * transmitted in network byte order, 422*12339Sanil.udupa@sun.com * unless otherwise stated. 423*12339Sanil.udupa@sun.com * Therefore convert the param type to host byte order. 424*12339Sanil.udupa@sun.com * Also do not add src address present in IP header 425*12339Sanil.udupa@sun.com * as it has already been thru sctp_conn_match() above. 426*12339Sanil.udupa@sun.com */ 427*12339Sanil.udupa@sun.com param_type = ntohs(ph->sph_type); 428*12339Sanil.udupa@sun.com switch (param_type) { 429*12339Sanil.udupa@sun.com case PARM_ADDR4: 430*12339Sanil.udupa@sun.com IN6_INADDR_TO_V4MAPPED((struct in_addr *) 431*12339Sanil.udupa@sun.com (ph + 1), &src); 432*12339Sanil.udupa@sun.com if (IN6_ARE_ADDR_EQUAL(&src, srcp)) 433*12339Sanil.udupa@sun.com break; 434*12339Sanil.udupa@sun.com *faddrpp = (in6_addr_t *) 435*12339Sanil.udupa@sun.com kmem_zalloc(sizeof (in6_addr_t), 436*12339Sanil.udupa@sun.com KM_NOSLEEP); 437*12339Sanil.udupa@sun.com if (*faddrpp == NULL) 438*12339Sanil.udupa@sun.com break; 439*12339Sanil.udupa@sun.com IN6_INADDR_TO_V4MAPPED((struct in_addr *) 440*12339Sanil.udupa@sun.com (ph + 1), *faddrpp); 441*12339Sanil.udupa@sun.com nfaddr++; 442*12339Sanil.udupa@sun.com faddrpp++; 443*12339Sanil.udupa@sun.com break; 444*12339Sanil.udupa@sun.com case PARM_ADDR6: 445*12339Sanil.udupa@sun.com *faddrpp = (in6_addr_t *)(ph + 1); 446*12339Sanil.udupa@sun.com if (IN6_ARE_ADDR_EQUAL(*faddrpp, srcp)) 447*12339Sanil.udupa@sun.com break; 448*12339Sanil.udupa@sun.com nfaddr++; 449*12339Sanil.udupa@sun.com faddrpp++; 450*12339Sanil.udupa@sun.com break; 451*12339Sanil.udupa@sun.com default: 452*12339Sanil.udupa@sun.com break; 453*12339Sanil.udupa@sun.com } 454*12339Sanil.udupa@sun.com ph = sctp_next_parm(ph, &remaining); 455*12339Sanil.udupa@sun.com } 456*12339Sanil.udupa@sun.com 457*12339Sanil.udupa@sun.com ASSERT(nfaddr < totaddr); 458*12339Sanil.udupa@sun.com 459*12339Sanil.udupa@sun.com if (nfaddr > 0) { 460*12339Sanil.udupa@sun.com sctp = sctp_conn_match(addrbuf, nfaddr, dstp, ports, 461*12339Sanil.udupa@sun.com zoneid, iraflags, sctps); 462*12339Sanil.udupa@sun.com 463*12339Sanil.udupa@sun.com if (isv4) { 464*12339Sanil.udupa@sun.com for (faddrpp = addrbuf; nfaddr > 0; 465*12339Sanil.udupa@sun.com faddrpp++, nfaddr--) { 466*12339Sanil.udupa@sun.com if (IN6_IS_ADDR_V4MAPPED(*faddrpp)) { 467*12339Sanil.udupa@sun.com kmem_free(*faddrpp, 468*12339Sanil.udupa@sun.com sizeof (in6_addr_t)); 469*12339Sanil.udupa@sun.com } 470*12339Sanil.udupa@sun.com } 471*12339Sanil.udupa@sun.com } 472*12339Sanil.udupa@sun.com } 473*12339Sanil.udupa@sun.com kmem_free(addrbuf, totaddr * sizeof (in6_addr_t *)); 474*12339Sanil.udupa@sun.com } 475*12339Sanil.udupa@sun.com return (sctp); 476*12339Sanil.udupa@sun.com } 477*12339Sanil.udupa@sun.com 478*12339Sanil.udupa@sun.com /* 47911042SErik.Nordmark@Sun.COM * Fanout to a sctp instance. 48011042SErik.Nordmark@Sun.COM */ 4811676Sjpk conn_t * 4821676Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 483*12339Sanil.udupa@sun.com ip_recv_attr_t *ira, mblk_t *mp, sctp_stack_t *sctps, sctp_hdr_t *sctph) 4841676Sjpk { 48511042SErik.Nordmark@Sun.COM zoneid_t zoneid = ira->ira_zoneid; 48611042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 4871676Sjpk sctp_t *sctp; 4881676Sjpk 489*12339Sanil.udupa@sun.com sctp = sctp_lookup_by_faddrs(mp, sctph, src, dst, ports, zoneid, 490*12339Sanil.udupa@sun.com sctps, iraflags); 49111042SErik.Nordmark@Sun.COM if (sctp == NULL) { 4921676Sjpk /* Not in conn fanout; check listen fanout */ 49311042SErik.Nordmark@Sun.COM sctp = listen_match(dst, ports, zoneid, iraflags, sctps); 49411042SErik.Nordmark@Sun.COM if (sctp == NULL) 4951676Sjpk return (NULL); 4962776Skp158701 /* 4972776Skp158701 * On systems running trusted extensions, check if dst 4982776Skp158701 * should accept the packet. "IPV6_VERSION" indicates 4992776Skp158701 * that dst is in 16 byte AF_INET6 format. IPv4-mapped 5002776Skp158701 * IPv6 addresses are supported. 5012776Skp158701 */ 50211042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_SYSTEM_LABELED) && 50311042SErik.Nordmark@Sun.COM !tsol_receive_local(mp, dst, IPV6_VERSION, ira, 50411042SErik.Nordmark@Sun.COM sctp->sctp_connp)) { 5052776Skp158701 DTRACE_PROBE3( 5062776Skp158701 tx__ip__log__info__classify__sctp, 5072776Skp158701 char *, 5082776Skp158701 "connp(1) could not receive mp(2)", 5092776Skp158701 conn_t *, sctp->sctp_connp, mblk_t *, mp); 5102776Skp158701 SCTP_REFRELE(sctp); 5112776Skp158701 return (NULL); 5122776Skp158701 } 5131676Sjpk } 51411042SErik.Nordmark@Sun.COM /* 51511042SErik.Nordmark@Sun.COM * For labeled systems, there's no need to check the 51611042SErik.Nordmark@Sun.COM * label here. It's known to be good as we checked 51711042SErik.Nordmark@Sun.COM * before allowing the connection to become bound. 51811042SErik.Nordmark@Sun.COM */ 5191676Sjpk return (sctp->sctp_connp); 5201676Sjpk } 5211676Sjpk 5220Sstevel@tonic-gate /* 52311042SErik.Nordmark@Sun.COM * Fanout for ICMP errors for SCTP 5240Sstevel@tonic-gate * The caller puts <fport, lport> in the ports parameter. 5250Sstevel@tonic-gate */ 5260Sstevel@tonic-gate void 52711042SErik.Nordmark@Sun.COM ip_fanout_sctp(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, uint32_t ports, 52811042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira) 5290Sstevel@tonic-gate { 53011042SErik.Nordmark@Sun.COM sctp_t *sctp; 53111042SErik.Nordmark@Sun.COM conn_t *connp; 53211042SErik.Nordmark@Sun.COM in6_addr_t map_src, map_dst; 53311042SErik.Nordmark@Sun.COM in6_addr_t *src, *dst; 53411042SErik.Nordmark@Sun.COM boolean_t secure; 53511042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 53611042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 53711042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack; 53811042SErik.Nordmark@Sun.COM ipsec_stack_t *ipss = ns->netstack_ipsec; 53911042SErik.Nordmark@Sun.COM sctp_stack_t *sctps = ns->netstack_sctp; 54011042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 54111042SErik.Nordmark@Sun.COM ill_t *rill = ira->ira_rill; 5423448Sdh155122 54311042SErik.Nordmark@Sun.COM ASSERT(iraflags & IRAF_ICMP_ERROR); 5440Sstevel@tonic-gate 54511042SErik.Nordmark@Sun.COM secure = iraflags & IRAF_IPSEC_SECURE; 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* Assume IP provides aligned packets - otherwise toss */ 5480Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) { 54911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 55011042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 55111042SErik.Nordmark@Sun.COM freemsg(mp); 5520Sstevel@tonic-gate return; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 55511042SErik.Nordmark@Sun.COM if (!(iraflags & IRAF_IS_IPV4)) { 5560Sstevel@tonic-gate src = &ip6h->ip6_src; 5570Sstevel@tonic-gate dst = &ip6h->ip6_dst; 5580Sstevel@tonic-gate } else { 5590Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src); 5600Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst); 5610Sstevel@tonic-gate src = &map_src; 5620Sstevel@tonic-gate dst = &map_dst; 5630Sstevel@tonic-gate } 564*12339Sanil.udupa@sun.com connp = sctp_fanout(src, dst, ports, ira, mp, sctps, NULL); 5653448Sdh155122 if (connp == NULL) { 56611042SErik.Nordmark@Sun.COM ip_fanout_sctp_raw(mp, ipha, ip6h, ports, ira); 5670Sstevel@tonic-gate return; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate sctp = CONN2SCTP(connp); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 5730Sstevel@tonic-gate * This should be fine. 5740Sstevel@tonic-gate */ 57511042SErik.Nordmark@Sun.COM if (((iraflags & IRAF_IS_IPV4) ? 57611042SErik.Nordmark@Sun.COM CONN_INBOUND_POLICY_PRESENT(connp, ipss) : 57711042SErik.Nordmark@Sun.COM CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) || 57811042SErik.Nordmark@Sun.COM secure) { 57911042SErik.Nordmark@Sun.COM mp = ipsec_check_inbound_policy(mp, connp, ipha, 58011042SErik.Nordmark@Sun.COM ip6h, ira); 58111042SErik.Nordmark@Sun.COM if (mp == NULL) { 5820Sstevel@tonic-gate SCTP_REFRELE(sctp); 5830Sstevel@tonic-gate return; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 58711042SErik.Nordmark@Sun.COM ira->ira_ill = ira->ira_rill = NULL; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 5900Sstevel@tonic-gate if (sctp->sctp_running) { 59111042SErik.Nordmark@Sun.COM sctp_add_recvq(sctp, mp, B_FALSE, ira); 5920Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5930Sstevel@tonic-gate } else { 5940Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 5950Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 5980Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 59911042SErik.Nordmark@Sun.COM sctp_add_recvq(sctp, mp, B_TRUE, ira); 6000Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 6010Sstevel@tonic-gate WAKE_SCTP(sctp); 6020Sstevel@tonic-gate } else { 6030Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 60411042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_ICMP_ERROR) { 60511042SErik.Nordmark@Sun.COM sctp_icmp_error(sctp, mp); 60611042SErik.Nordmark@Sun.COM } else { 60711042SErik.Nordmark@Sun.COM sctp_input_data(sctp, mp, ira); 60811042SErik.Nordmark@Sun.COM } 6090Sstevel@tonic-gate WAKE_SCTP(sctp); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate SCTP_REFRELE(sctp); 61311042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 61411042SErik.Nordmark@Sun.COM ira->ira_rill = rill; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate void 6180Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp) 6190Sstevel@tonic-gate { 6200Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_conn_tfp; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate if (!tf) { 6230Sstevel@tonic-gate return; 6240Sstevel@tonic-gate } 625852Svi117747 /* 626852Svi117747 * On a clustered note send this notification to the clustering 627852Svi117747 * subsystem. 628852Svi117747 */ 629852Svi117747 if (cl_sctp_disconnect != NULL) { 63011042SErik.Nordmark@Sun.COM (*cl_sctp_disconnect)(sctp->sctp_connp->conn_family, 631852Svi117747 (cl_sctp_handle_t)sctp); 632852Svi117747 } 633852Svi117747 6340Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6350Sstevel@tonic-gate ASSERT(tf->tf_sctp); 6360Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 6370Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_conn_hash_next; 6380Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6390Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp); 6400Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = NULL; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate } else { 6430Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev); 6440Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp); 6450Sstevel@tonic-gate sctp->sctp_conn_hash_prev->sctp_conn_hash_next = 6460Sstevel@tonic-gate sctp->sctp_conn_hash_next; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6490Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev 6500Sstevel@tonic-gate == sctp); 6510Sstevel@tonic-gate sctp->sctp_conn_hash_next->sctp_conn_hash_prev = 6520Sstevel@tonic-gate sctp->sctp_conn_hash_prev; 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate sctp->sctp_conn_hash_next = NULL; 6560Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6570Sstevel@tonic-gate sctp->sctp_conn_tfp = NULL; 6580Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate void 6620Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock) 6630Sstevel@tonic-gate { 6640Sstevel@tonic-gate if (sctp->sctp_conn_tfp) { 6650Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate if (!caller_holds_lock) { 6690Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6700Sstevel@tonic-gate } else { 6710Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate sctp->sctp_conn_hash_next = tf->tf_sctp; 6750Sstevel@tonic-gate if (tf->tf_sctp) { 6760Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = sctp; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6790Sstevel@tonic-gate tf->tf_sctp = sctp; 6800Sstevel@tonic-gate sctp->sctp_conn_tfp = tf; 6810Sstevel@tonic-gate if (!caller_holds_lock) { 6820Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate void 6870Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp) 6880Sstevel@tonic-gate { 6890Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_listen_tfp; 69011042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp; 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (!tf) { 6930Sstevel@tonic-gate return; 6940Sstevel@tonic-gate } 695852Svi117747 /* 696852Svi117747 * On a clustered note send this notification to the clustering 697852Svi117747 * subsystem. 698852Svi117747 */ 699852Svi117747 if (cl_sctp_unlisten != NULL) { 700852Svi117747 uchar_t *slist; 701852Svi117747 ssize_t ssize; 702852Svi117747 703852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 704852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 705852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 70611042SErik.Nordmark@Sun.COM (*cl_sctp_unlisten)(connp->conn_family, slist, 70711042SErik.Nordmark@Sun.COM sctp->sctp_nsaddrs, connp->conn_lport); 708852Svi117747 /* list will be freed by the clustering module */ 709852Svi117747 } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7120Sstevel@tonic-gate ASSERT(tf->tf_sctp); 7130Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 7140Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_listen_hash_next; 7157480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) { 7160Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp); 7170Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = NULL; 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate } else { 7200Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev); 7210Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next == 7220Sstevel@tonic-gate sctp); 7237480SKacheong.Poon@Sun.COM ASSERT(sctp->sctp_listen_hash_next == NULL || 7247480SKacheong.Poon@Sun.COM sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp); 7257480SKacheong.Poon@Sun.COM 7260Sstevel@tonic-gate sctp->sctp_listen_hash_prev->sctp_listen_hash_next = 7270Sstevel@tonic-gate sctp->sctp_listen_hash_next; 7280Sstevel@tonic-gate 7297480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) { 73011042SErik.Nordmark@Sun.COM sctp_t *next = sctp->sctp_listen_hash_next; 73111042SErik.Nordmark@Sun.COM 73211042SErik.Nordmark@Sun.COM ASSERT(next->sctp_listen_hash_prev == sctp); 73311042SErik.Nordmark@Sun.COM next->sctp_listen_hash_prev = 7340Sstevel@tonic-gate sctp->sctp_listen_hash_prev; 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate sctp->sctp_listen_hash_next = NULL; 7380Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7390Sstevel@tonic-gate sctp->sctp_listen_tfp = NULL; 7400Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate void 7440Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp) 7450Sstevel@tonic-gate { 74611042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp; 74711042SErik.Nordmark@Sun.COM 7480Sstevel@tonic-gate if (sctp->sctp_listen_tfp) { 7490Sstevel@tonic-gate sctp_listen_hash_remove(sctp); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7530Sstevel@tonic-gate sctp->sctp_listen_hash_next = tf->tf_sctp; 7540Sstevel@tonic-gate if (tf->tf_sctp) { 7550Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = sctp; 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7580Sstevel@tonic-gate tf->tf_sctp = sctp; 7590Sstevel@tonic-gate sctp->sctp_listen_tfp = tf; 7600Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 761852Svi117747 /* 762852Svi117747 * On a clustered note send this notification to the clustering 763852Svi117747 * subsystem. 764852Svi117747 */ 765852Svi117747 if (cl_sctp_listen != NULL) { 766852Svi117747 uchar_t *slist; 767852Svi117747 ssize_t ssize; 768852Svi117747 769852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 770852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 771852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 77211042SErik.Nordmark@Sun.COM (*cl_sctp_listen)(connp->conn_family, slist, 77311042SErik.Nordmark@Sun.COM sctp->sctp_nsaddrs, connp->conn_lport); 774852Svi117747 /* list will be freed by the clustering module */ 775852Svi117747 } 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * Hash list insertion routine for sctp_t structures. 7800Sstevel@tonic-gate * Inserts entries with the ones bound to a specific IP address first 7810Sstevel@tonic-gate * followed by those bound to INADDR_ANY. 7820Sstevel@tonic-gate */ 7830Sstevel@tonic-gate void 7840Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock) 7850Sstevel@tonic-gate { 7860Sstevel@tonic-gate sctp_t **sctpp; 7870Sstevel@tonic-gate sctp_t *sctpnext; 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate if (sctp->sctp_ptpbhn != NULL) { 7900Sstevel@tonic-gate ASSERT(!caller_holds_lock); 7910Sstevel@tonic-gate sctp_bind_hash_remove(sctp); 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate sctpp = &tbf->tf_sctp; 7940Sstevel@tonic-gate if (!caller_holds_lock) { 7950Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 7960Sstevel@tonic-gate } else { 7970Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tbf->tf_lock)); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate sctpnext = sctpp[0]; 8000Sstevel@tonic-gate if (sctpnext) { 8010Sstevel@tonic-gate sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash; 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate sctp->sctp_bind_hash = sctpnext; 8040Sstevel@tonic-gate sctp->sctp_ptpbhn = sctpp; 8050Sstevel@tonic-gate sctpp[0] = sctp; 8060Sstevel@tonic-gate /* For sctp_*_hash_remove */ 8070Sstevel@tonic-gate sctp->sctp_bind_lockp = &tbf->tf_lock; 8080Sstevel@tonic-gate if (!caller_holds_lock) 8090Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * Hash list removal routine for sctp_t structures. 8140Sstevel@tonic-gate */ 8150Sstevel@tonic-gate void 8160Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp) 8170Sstevel@tonic-gate { 8180Sstevel@tonic-gate sctp_t *sctpnext; 8190Sstevel@tonic-gate kmutex_t *lockp; 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate lockp = sctp->sctp_bind_lockp; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate if (sctp->sctp_ptpbhn == NULL) 8240Sstevel@tonic-gate return; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate ASSERT(lockp != NULL); 8270Sstevel@tonic-gate mutex_enter(lockp); 8280Sstevel@tonic-gate if (sctp->sctp_ptpbhn) { 8290Sstevel@tonic-gate sctpnext = sctp->sctp_bind_hash; 8300Sstevel@tonic-gate if (sctpnext) { 8310Sstevel@tonic-gate sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn; 8320Sstevel@tonic-gate sctp->sctp_bind_hash = NULL; 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate *sctp->sctp_ptpbhn = sctpnext; 8350Sstevel@tonic-gate sctp->sctp_ptpbhn = NULL; 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate mutex_exit(lockp); 8380Sstevel@tonic-gate sctp->sctp_bind_lockp = NULL; 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate /* 8427480SKacheong.Poon@Sun.COM * Similar to but different from sctp_conn_match(). 8430Sstevel@tonic-gate * 8440Sstevel@tonic-gate * Matches sets of addresses as follows: if the argument addr set is 8450Sstevel@tonic-gate * a complete subset of the corresponding addr set in the sctp_t, it 8460Sstevel@tonic-gate * is a match. 8470Sstevel@tonic-gate * 8480Sstevel@tonic-gate * Caller must hold tf->tf_lock. 8490Sstevel@tonic-gate * 8500Sstevel@tonic-gate * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE. 8510Sstevel@tonic-gate */ 8520Sstevel@tonic-gate sctp_t * 8530Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports, 8540Sstevel@tonic-gate int min_state) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate sctp_t *sctp; 8570Sstevel@tonic-gate sctp_faddr_t *fp; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 8600Sstevel@tonic-gate 8617480SKacheong.Poon@Sun.COM for (sctp = tf->tf_sctp; sctp != NULL; 8627480SKacheong.Poon@Sun.COM sctp = sctp->sctp_conn_hash_next) { 86311042SErik.Nordmark@Sun.COM if (*ports != sctp->sctp_connp->conn_ports || 86411042SErik.Nordmark@Sun.COM sctp->sctp_state < min_state) { 8650Sstevel@tonic-gate continue; 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* check for faddr match */ 8697480SKacheong.Poon@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { 8700Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) { 8710Sstevel@tonic-gate break; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8757480SKacheong.Poon@Sun.COM if (fp == NULL) { 8760Sstevel@tonic-gate /* no faddr match; keep looking */ 8770Sstevel@tonic-gate continue; 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8807480SKacheong.Poon@Sun.COM /* 8817480SKacheong.Poon@Sun.COM * There is an existing association with the same peer 8827480SKacheong.Poon@Sun.COM * address. So now we need to check if our local address 8837480SKacheong.Poon@Sun.COM * set overlaps with the one of the existing association. 8847480SKacheong.Poon@Sun.COM * If they overlap, we should return it. 8857480SKacheong.Poon@Sun.COM */ 8867480SKacheong.Poon@Sun.COM if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) { 8870Sstevel@tonic-gate goto done; 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* no match; continue searching */ 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate done: 8947480SKacheong.Poon@Sun.COM if (sctp != NULL) { 8950Sstevel@tonic-gate SCTP_REFHOLD(sctp); 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate return (sctp); 8980Sstevel@tonic-gate } 899