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*7480SKacheong.Poon@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/socket.h> 280Sstevel@tonic-gate #include <sys/ddi.h> 290Sstevel@tonic-gate #include <sys/sunddi.h> 301676Sjpk #include <sys/tsol/tndb.h> 311676Sjpk #include <sys/tsol/tnet.h> 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <netinet/in.h> 340Sstevel@tonic-gate #include <netinet/ip6.h> 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <inet/common.h> 370Sstevel@tonic-gate #include <inet/ip.h> 380Sstevel@tonic-gate #include <inet/ip6.h> 390Sstevel@tonic-gate #include <inet/ipclassifier.h> 400Sstevel@tonic-gate #include <inet/ipsec_impl.h> 410Sstevel@tonic-gate #include <inet/ipp_common.h> 420Sstevel@tonic-gate #include <inet/sctp_ip.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include "sctp_impl.h" 450Sstevel@tonic-gate #include "sctp_addr.h" 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* Default association hash size. The size must be a power of 2. */ 480Sstevel@tonic-gate #define SCTP_CONN_HASH_SIZE 8192 490Sstevel@tonic-gate 503448Sdh155122 uint_t sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; /* /etc/system */ 510Sstevel@tonic-gate 52852Svi117747 /* 53852Svi117747 * Cluster networking hook for traversing current assoc list. 54852Svi117747 * This routine is used to extract the current list of live associations 55852Svi117747 * which must continue to to be dispatched to this node. 56852Svi117747 */ 57852Svi117747 int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *, 58852Svi117747 boolean_t); 593448Sdh155122 static int cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, 603448Sdh155122 void *), void *arg, boolean_t cansleep, sctp_stack_t *sctps); 61852Svi117747 620Sstevel@tonic-gate void 633448Sdh155122 sctp_hash_init(sctp_stack_t *sctps) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate int i; 660Sstevel@tonic-gate 673448Sdh155122 /* Start with /etc/system value */ 683448Sdh155122 sctps->sctps_conn_hash_size = sctp_conn_hash_size; 693448Sdh155122 703448Sdh155122 if (sctps->sctps_conn_hash_size & (sctps->sctps_conn_hash_size - 1)) { 710Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */ 720Sstevel@tonic-gate for (i = 0; i < 31; i++) { 733448Sdh155122 if (sctps->sctps_conn_hash_size < (1 << i)) 740Sstevel@tonic-gate break; 750Sstevel@tonic-gate } 763448Sdh155122 sctps->sctps_conn_hash_size = 1 << i; 770Sstevel@tonic-gate } 783448Sdh155122 if (sctps->sctps_conn_hash_size < SCTP_CONN_HASH_SIZE) { 793448Sdh155122 sctps->sctps_conn_hash_size = SCTP_CONN_HASH_SIZE; 800Sstevel@tonic-gate cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n", 813448Sdh155122 sctps->sctps_conn_hash_size); 820Sstevel@tonic-gate } 833448Sdh155122 sctps->sctps_conn_fanout = 84*7480SKacheong.Poon@Sun.COM (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size * 85*7480SKacheong.Poon@Sun.COM sizeof (sctp_tf_t), KM_SLEEP); 863448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 873448Sdh155122 mutex_init(&sctps->sctps_conn_fanout[i].tf_lock, NULL, 88*7480SKacheong.Poon@Sun.COM MUTEX_DEFAULT, NULL); 890Sstevel@tonic-gate } 903448Sdh155122 sctps->sctps_listen_fanout = kmem_zalloc(SCTP_LISTEN_FANOUT_SIZE * 913448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 923448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 933448Sdh155122 mutex_init(&sctps->sctps_listen_fanout[i].tf_lock, NULL, 940Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 950Sstevel@tonic-gate } 963448Sdh155122 sctps->sctps_bind_fanout = kmem_zalloc(SCTP_BIND_FANOUT_SIZE * 973448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 983448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 993448Sdh155122 mutex_init(&sctps->sctps_bind_fanout[i].tf_lock, NULL, 1000Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate void 1053448Sdh155122 sctp_hash_destroy(sctp_stack_t *sctps) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate int i; 1080Sstevel@tonic-gate 1093448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 1103448Sdh155122 mutex_destroy(&sctps->sctps_conn_fanout[i].tf_lock); 1113448Sdh155122 } 1123448Sdh155122 kmem_free(sctps->sctps_conn_fanout, sctps->sctps_conn_hash_size * 1133448Sdh155122 sizeof (sctp_tf_t)); 1143448Sdh155122 sctps->sctps_conn_fanout = NULL; 1153448Sdh155122 1163448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 1173448Sdh155122 mutex_destroy(&sctps->sctps_listen_fanout[i].tf_lock); 1180Sstevel@tonic-gate } 1193448Sdh155122 kmem_free(sctps->sctps_listen_fanout, SCTP_LISTEN_FANOUT_SIZE * 1203448Sdh155122 sizeof (sctp_tf_t)); 1213448Sdh155122 sctps->sctps_listen_fanout = NULL; 1223448Sdh155122 1233448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 1243448Sdh155122 mutex_destroy(&sctps->sctps_bind_fanout[i].tf_lock); 1250Sstevel@tonic-gate } 1263448Sdh155122 kmem_free(sctps->sctps_bind_fanout, SCTP_BIND_FANOUT_SIZE * 1273448Sdh155122 sizeof (sctp_tf_t)); 1283448Sdh155122 sctps->sctps_bind_fanout = NULL; 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate 1311932Svi117747 /* 1321932Svi117747 * Walk the SCTP global list and refrele the ire for this ipif 1331932Svi117747 * This is called when an address goes down, so that we release any reference 1341932Svi117747 * to the ire associated with this address. Additionally, for any SCTP if 1351932Svi117747 * this was the only/last address in its source list, we don't kill the 1361932Svi117747 * assoc., if there is no address added subsequently, or if this does not 1371932Svi117747 * come up, then the assoc. will die a natural death (i.e. timeout). 1381932Svi117747 */ 1390Sstevel@tonic-gate void 1400Sstevel@tonic-gate sctp_ire_cache_flush(ipif_t *ipif) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate sctp_t *sctp; 1430Sstevel@tonic-gate sctp_t *sctp_prev = NULL; 1440Sstevel@tonic-gate sctp_faddr_t *fp; 1450Sstevel@tonic-gate conn_t *connp; 1460Sstevel@tonic-gate ire_t *ire; 1473448Sdh155122 sctp_stack_t *sctps = ipif->ipif_ill->ill_ipst-> 1483448Sdh155122 ips_netstack->netstack_sctp; 1490Sstevel@tonic-gate 1503448Sdh155122 sctp = sctps->sctps_gsctp; 1513448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 1520Sstevel@tonic-gate while (sctp != NULL) { 1530Sstevel@tonic-gate mutex_enter(&sctp->sctp_reflock); 1540Sstevel@tonic-gate if (sctp->sctp_condemned) { 1550Sstevel@tonic-gate mutex_exit(&sctp->sctp_reflock); 1563448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 1570Sstevel@tonic-gate continue; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate sctp->sctp_refcnt++; 1600Sstevel@tonic-gate mutex_exit(&sctp->sctp_reflock); 1613448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 1620Sstevel@tonic-gate if (sctp_prev != NULL) 1630Sstevel@tonic-gate SCTP_REFRELE(sctp_prev); 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate RUN_SCTP(sctp); 1660Sstevel@tonic-gate connp = sctp->sctp_connp; 1670Sstevel@tonic-gate mutex_enter(&connp->conn_lock); 1680Sstevel@tonic-gate ire = connp->conn_ire_cache; 1691932Svi117747 if (ire != NULL && ire->ire_ipif == ipif) { 1700Sstevel@tonic-gate connp->conn_ire_cache = NULL; 1710Sstevel@tonic-gate mutex_exit(&connp->conn_lock); 1720Sstevel@tonic-gate IRE_REFRELE_NOTR(ire); 1730Sstevel@tonic-gate } else { 1740Sstevel@tonic-gate mutex_exit(&connp->conn_lock); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate /* check for ires cached in faddr */ 1771932Svi117747 for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { 1781932Svi117747 /* 1791932Svi117747 * If this ipif is being used as the source address 1801932Svi117747 * we need to update it as well, else we will end 1811932Svi117747 * up using the dead source address. 1821932Svi117747 */ 1830Sstevel@tonic-gate ire = fp->ire; 1841932Svi117747 if (ire != NULL && ire->ire_ipif == ipif) { 1850Sstevel@tonic-gate fp->ire = NULL; 1860Sstevel@tonic-gate IRE_REFRELE_NOTR(ire); 1870Sstevel@tonic-gate } 1881932Svi117747 /* 1891932Svi117747 * This may result in setting the fp as unreachable, 1901932Svi117747 * i.e. if all the source addresses are down. In 1911932Svi117747 * that case the assoc. would timeout. 1921932Svi117747 */ 1931932Svi117747 if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, 1941932Svi117747 &fp->saddr)) { 1951932Svi117747 sctp_set_saddr(sctp, fp); 1961932Svi117747 if (fp == sctp->sctp_current && 1971932Svi117747 fp->state != SCTP_FADDRS_UNREACH) { 1981932Svi117747 sctp_set_faddr_current(sctp, fp); 1991932Svi117747 } 2001932Svi117747 } 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate WAKE_SCTP(sctp); 2030Sstevel@tonic-gate sctp_prev = sctp; 2043448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 2053448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 2060Sstevel@tonic-gate } 2073448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 2080Sstevel@tonic-gate if (sctp_prev != NULL) 2090Sstevel@tonic-gate SCTP_REFRELE(sctp_prev); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 212852Svi117747 /* 213852Svi117747 * Exported routine for extracting active SCTP associations. 214852Svi117747 * Like TCP, we terminate the walk if the callback returns non-zero. 2153448Sdh155122 * 2163448Sdh155122 * Need to walk all sctp_stack_t instances since this clustering 2173448Sdh155122 * interface is assumed global for all instances 218852Svi117747 */ 219852Svi117747 int 2203448Sdh155122 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), 2213448Sdh155122 void *arg, boolean_t cansleep) 2223448Sdh155122 { 2233448Sdh155122 netstack_handle_t nh; 2243448Sdh155122 netstack_t *ns; 2253448Sdh155122 int ret = 0; 2263448Sdh155122 2273448Sdh155122 netstack_next_init(&nh); 2283448Sdh155122 while ((ns = netstack_next(&nh)) != NULL) { 2293448Sdh155122 ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep, 2303448Sdh155122 ns->netstack_sctp); 2313448Sdh155122 netstack_rele(ns); 2323448Sdh155122 } 2333448Sdh155122 netstack_next_fini(&nh); 2343448Sdh155122 return (ret); 2353448Sdh155122 } 2363448Sdh155122 2373448Sdh155122 static int 2383448Sdh155122 cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *), 2393448Sdh155122 void *arg, boolean_t cansleep, sctp_stack_t *sctps) 240852Svi117747 { 241852Svi117747 sctp_t *sctp; 242852Svi117747 sctp_t *sctp_prev; 243852Svi117747 cl_sctp_info_t cl_sctpi; 244852Svi117747 uchar_t *slist; 245852Svi117747 uchar_t *flist; 246852Svi117747 2473448Sdh155122 sctp = sctps->sctps_gsctp; 248852Svi117747 sctp_prev = NULL; 2493448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 250852Svi117747 while (sctp != NULL) { 251852Svi117747 size_t ssize; 252852Svi117747 size_t fsize; 253852Svi117747 254852Svi117747 mutex_enter(&sctp->sctp_reflock); 255852Svi117747 if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) { 256852Svi117747 mutex_exit(&sctp->sctp_reflock); 2573448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 258852Svi117747 continue; 259852Svi117747 } 260852Svi117747 sctp->sctp_refcnt++; 261852Svi117747 mutex_exit(&sctp->sctp_reflock); 2623448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 263852Svi117747 if (sctp_prev != NULL) 264852Svi117747 SCTP_REFRELE(sctp_prev); 265852Svi117747 RUN_SCTP(sctp); 266852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 267852Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 268852Svi117747 269852Svi117747 slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP); 270852Svi117747 flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP); 271852Svi117747 if (slist == NULL || flist == NULL) { 272852Svi117747 WAKE_SCTP(sctp); 273852Svi117747 if (slist != NULL) 274852Svi117747 kmem_free(slist, ssize); 275852Svi117747 if (flist != NULL) 276852Svi117747 kmem_free(flist, fsize); 277852Svi117747 SCTP_REFRELE(sctp); 278852Svi117747 return (1); 279852Svi117747 } 280852Svi117747 cl_sctpi.cl_sctpi_version = CL_SCTPI_V1; 281852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 282852Svi117747 sctp_get_faddr_list(sctp, flist, fsize); 283852Svi117747 cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs; 284852Svi117747 cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs; 285852Svi117747 cl_sctpi.cl_sctpi_family = sctp->sctp_family; 286852Svi117747 cl_sctpi.cl_sctpi_ipversion = sctp->sctp_ipversion; 287852Svi117747 cl_sctpi.cl_sctpi_state = sctp->sctp_state; 288852Svi117747 cl_sctpi.cl_sctpi_lport = sctp->sctp_lport; 289852Svi117747 cl_sctpi.cl_sctpi_fport = sctp->sctp_fport; 290852Svi117747 cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp; 291852Svi117747 WAKE_SCTP(sctp); 292852Svi117747 cl_sctpi.cl_sctpi_laddrp = slist; 293852Svi117747 cl_sctpi.cl_sctpi_faddrp = flist; 294852Svi117747 if ((*cl_callback)(&cl_sctpi, arg) != 0) { 295852Svi117747 kmem_free(slist, ssize); 296852Svi117747 kmem_free(flist, fsize); 297852Svi117747 SCTP_REFRELE(sctp); 298852Svi117747 return (1); 299852Svi117747 } 300852Svi117747 /* list will be freed by cl_callback */ 301852Svi117747 sctp_prev = sctp; 3023448Sdh155122 mutex_enter(&sctps->sctps_g_lock); 3033448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 304852Svi117747 } 3053448Sdh155122 mutex_exit(&sctps->sctps_g_lock); 306852Svi117747 if (sctp_prev != NULL) 307852Svi117747 SCTP_REFRELE(sctp_prev); 308852Svi117747 return (0); 309852Svi117747 } 310852Svi117747 3110Sstevel@tonic-gate sctp_t * 3120Sstevel@tonic-gate sctp_conn_match(in6_addr_t *faddr, in6_addr_t *laddr, uint32_t ports, 3133510Svi117747 zoneid_t zoneid, sctp_stack_t *sctps) 3140Sstevel@tonic-gate { 3150Sstevel@tonic-gate sctp_tf_t *tf; 3160Sstevel@tonic-gate sctp_t *sctp; 3170Sstevel@tonic-gate sctp_faddr_t *fp; 3180Sstevel@tonic-gate 3193448Sdh155122 tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]); 3200Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) { 3232263Ssommerfe if (ports != sctp->sctp_ports || 3242263Ssommerfe !IPCL_ZONE_MATCH(sctp->sctp_connp, zoneid)) { 3250Sstevel@tonic-gate continue; 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* check for faddr match */ 3290Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp; fp = fp->next) { 3300Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) { 3310Sstevel@tonic-gate break; 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3353510Svi117747 /* no faddr match; keep looking */ 3363510Svi117747 if (fp == NULL) 3370Sstevel@tonic-gate continue; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* check for laddr match */ 3403510Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 3413510Svi117747 SCTP_REFHOLD(sctp); 3423510Svi117747 goto done; 3433510Svi117747 } 3440Sstevel@tonic-gate /* no match; continue to the next in the chain */ 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate done: 3480Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3490Sstevel@tonic-gate return (sctp); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate static sctp_t * 3533510Svi117747 listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid, 3543510Svi117747 sctp_stack_t *sctps) 3550Sstevel@tonic-gate { 3560Sstevel@tonic-gate sctp_t *sctp; 3570Sstevel@tonic-gate sctp_tf_t *tf; 3580Sstevel@tonic-gate uint16_t lport; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate lport = ((uint16_t *)&ports)[1]; 3610Sstevel@tonic-gate 3623448Sdh155122 tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]); 3630Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) { 3662263Ssommerfe if (lport != sctp->sctp_lport || 3672263Ssommerfe !IPCL_ZONE_MATCH(sctp->sctp_connp, zoneid)) { 3680Sstevel@tonic-gate continue; 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate 3713510Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 3723510Svi117747 SCTP_REFHOLD(sctp); 3733510Svi117747 goto done; 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate /* no match; continue to the next in the chain */ 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate done: 3790Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3800Sstevel@tonic-gate return (sctp); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3831676Sjpk /* called by ipsec_sctp_pol */ 3840Sstevel@tonic-gate conn_t * 3850Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 3863510Svi117747 zoneid_t zoneid, sctp_stack_t *sctps) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate sctp_t *sctp; 3890Sstevel@tonic-gate 3903510Svi117747 if ((sctp = sctp_conn_match(src, dst, ports, zoneid, sctps)) == NULL) { 3910Sstevel@tonic-gate /* Not in conn fanout; check listen fanout */ 3923510Svi117747 if ((sctp = listen_match(dst, ports, zoneid, sctps)) == NULL) 3930Sstevel@tonic-gate return (NULL); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate return (sctp->sctp_connp); 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 3981676Sjpk conn_t * 3991676Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 4003510Svi117747 zoneid_t zoneid, mblk_t *mp, sctp_stack_t *sctps) 4013448Sdh155122 4021676Sjpk { 4031676Sjpk sctp_t *sctp; 4042776Skp158701 boolean_t shared_addr; 4051676Sjpk 4063510Svi117747 if ((sctp = sctp_conn_match(src, dst, ports, zoneid, sctps)) == NULL) { 4072776Skp158701 shared_addr = (zoneid == ALL_ZONES); 4082776Skp158701 if (shared_addr) { 4093448Sdh155122 /* 4103448Sdh155122 * No need to handle exclusive-stack zones since 4113448Sdh155122 * ALL_ZONES only applies to the shared stack. 4123448Sdh155122 */ 4131676Sjpk zoneid = tsol_mlp_findzone(IPPROTO_SCTP, 4141676Sjpk htons(ntohl(ports) & 0xFFFF)); 4151676Sjpk /* 4161676Sjpk * If no shared MLP is found, tsol_mlp_findzone returns 4171676Sjpk * ALL_ZONES. In that case, we assume it's SLP, and 4181676Sjpk * search for the zone based on the packet label. 4191676Sjpk * That will also return ALL_ZONES on failure. 4201676Sjpk */ 4211676Sjpk if (zoneid == ALL_ZONES) 4221676Sjpk zoneid = tsol_packet_to_zoneid(mp); 4231676Sjpk if (zoneid == ALL_ZONES) 4241676Sjpk return (NULL); 4251676Sjpk } 4261676Sjpk /* Not in conn fanout; check listen fanout */ 4273510Svi117747 if ((sctp = listen_match(dst, ports, zoneid, sctps)) == NULL) 4281676Sjpk return (NULL); 4292776Skp158701 /* 4302776Skp158701 * On systems running trusted extensions, check if dst 4312776Skp158701 * should accept the packet. "IPV6_VERSION" indicates 4322776Skp158701 * that dst is in 16 byte AF_INET6 format. IPv4-mapped 4332776Skp158701 * IPv6 addresses are supported. 4342776Skp158701 */ 4352776Skp158701 if (is_system_labeled() && 4362776Skp158701 !tsol_receive_local(mp, dst, IPV6_VERSION, 4372776Skp158701 shared_addr, sctp->sctp_connp)) { 4382776Skp158701 DTRACE_PROBE3( 4392776Skp158701 tx__ip__log__info__classify__sctp, 4402776Skp158701 char *, 4412776Skp158701 "connp(1) could not receive mp(2)", 4422776Skp158701 conn_t *, sctp->sctp_connp, mblk_t *, mp); 4432776Skp158701 SCTP_REFRELE(sctp); 4442776Skp158701 return (NULL); 4452776Skp158701 } 4461676Sjpk } 4471676Sjpk return (sctp->sctp_connp); 4481676Sjpk } 4491676Sjpk 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Fanout for SCTP packets 4520Sstevel@tonic-gate * The caller puts <fport, lport> in the ports parameter. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate /* ARGSUSED */ 4550Sstevel@tonic-gate void 4560Sstevel@tonic-gate ip_fanout_sctp(mblk_t *mp, ill_t *recv_ill, ipha_t *ipha, 4570Sstevel@tonic-gate uint32_t ports, uint_t flags, boolean_t mctl_present, boolean_t ip_policy, 4583510Svi117747 zoneid_t zoneid) 4590Sstevel@tonic-gate { 4600Sstevel@tonic-gate sctp_t *sctp; 4610Sstevel@tonic-gate boolean_t isv4; 4620Sstevel@tonic-gate conn_t *connp; 4630Sstevel@tonic-gate mblk_t *first_mp; 4640Sstevel@tonic-gate ip6_t *ip6h; 4650Sstevel@tonic-gate in6_addr_t map_src, map_dst; 4660Sstevel@tonic-gate in6_addr_t *src, *dst; 4673448Sdh155122 ip_stack_t *ipst; 4683448Sdh155122 ipsec_stack_t *ipss; 4693448Sdh155122 sctp_stack_t *sctps; 4703448Sdh155122 4713448Sdh155122 ASSERT(recv_ill != NULL); 4723448Sdh155122 ipst = recv_ill->ill_ipst; 4733448Sdh155122 sctps = ipst->ips_netstack->netstack_sctp; 4743448Sdh155122 ipss = ipst->ips_netstack->netstack_ipsec; 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate first_mp = mp; 4770Sstevel@tonic-gate if (mctl_present) { 4780Sstevel@tonic-gate mp = first_mp->b_cont; 4790Sstevel@tonic-gate ASSERT(mp != NULL); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* Assume IP provides aligned packets - otherwise toss */ 4830Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) { 4843284Sapersson BUMP_MIB(recv_ill->ill_ip_mib, ipIfStatsInDiscards); 4850Sstevel@tonic-gate freemsg(first_mp); 4860Sstevel@tonic-gate return; 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV6_VERSION) { 4900Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 4910Sstevel@tonic-gate src = &ip6h->ip6_src; 4920Sstevel@tonic-gate dst = &ip6h->ip6_dst; 4930Sstevel@tonic-gate isv4 = B_FALSE; 4940Sstevel@tonic-gate } else { 4950Sstevel@tonic-gate ip6h = NULL; 4960Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src); 4970Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst); 4980Sstevel@tonic-gate src = &map_src; 4990Sstevel@tonic-gate dst = &map_dst; 5000Sstevel@tonic-gate isv4 = B_TRUE; 5010Sstevel@tonic-gate } 5023539Snordmark connp = sctp_fanout(src, dst, ports, zoneid, mp, sctps); 5033448Sdh155122 if (connp == NULL) { 5042429Skcpoon ip_fanout_sctp_raw(first_mp, recv_ill, ipha, isv4, 5053510Svi117747 ports, mctl_present, flags, ip_policy, zoneid); 5060Sstevel@tonic-gate return; 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate sctp = CONN2SCTP(connp); 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* Found a client; up it goes */ 5113284Sapersson BUMP_MIB(recv_ill->ill_ip_mib, ipIfStatsHCInDelivers); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 5150Sstevel@tonic-gate * This should be fine. 5160Sstevel@tonic-gate */ 5173448Sdh155122 if (CONN_INBOUND_POLICY_PRESENT(connp, ipss) || mctl_present) { 5180Sstevel@tonic-gate first_mp = ipsec_check_inbound_policy(first_mp, connp, 5190Sstevel@tonic-gate ipha, NULL, mctl_present); 5200Sstevel@tonic-gate if (first_mp == NULL) { 5210Sstevel@tonic-gate SCTP_REFRELE(sctp); 5220Sstevel@tonic-gate return; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* Initiate IPPF processing for fastpath */ 5273448Sdh155122 if (IPP_ENABLED(IPP_LOCAL_IN, ipst)) { 5280Sstevel@tonic-gate ip_process(IPP_LOCAL_IN, &mp, 5290Sstevel@tonic-gate recv_ill->ill_phyint->phyint_ifindex); 5300Sstevel@tonic-gate if (mp == NULL) { 5310Sstevel@tonic-gate SCTP_REFRELE(sctp); 5320Sstevel@tonic-gate if (mctl_present) 5330Sstevel@tonic-gate freeb(first_mp); 5340Sstevel@tonic-gate return; 5350Sstevel@tonic-gate } else if (mctl_present) { 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * ip_process might return a new mp. 5380Sstevel@tonic-gate */ 5390Sstevel@tonic-gate ASSERT(first_mp != mp); 5400Sstevel@tonic-gate first_mp->b_cont = mp; 5410Sstevel@tonic-gate } else { 5420Sstevel@tonic-gate first_mp = mp; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (connp->conn_recvif || connp->conn_recvslla || 5473318Srshoaib connp->conn_ip_recvpktinfo) { 5480Sstevel@tonic-gate int in_flags = 0; 5490Sstevel@tonic-gate 5503318Srshoaib if (connp->conn_recvif || connp->conn_ip_recvpktinfo) { 5510Sstevel@tonic-gate in_flags = IPF_RECVIF; 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate if (connp->conn_recvslla) { 5540Sstevel@tonic-gate in_flags |= IPF_RECVSLLA; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate if (isv4) { 5573318Srshoaib mp = ip_add_info(mp, recv_ill, in_flags, 5583448Sdh155122 IPCL_ZONEID(connp), ipst); 5590Sstevel@tonic-gate } else { 5600Sstevel@tonic-gate mp = ip_add_info_v6(mp, recv_ill, &ip6h->ip6_dst); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate if (mp == NULL) { 5630Sstevel@tonic-gate SCTP_REFRELE(sctp); 5640Sstevel@tonic-gate if (mctl_present) 5650Sstevel@tonic-gate freeb(first_mp); 5660Sstevel@tonic-gate return; 5670Sstevel@tonic-gate } else if (mctl_present) { 5680Sstevel@tonic-gate /* 5690Sstevel@tonic-gate * ip_add_info might return a new mp. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate ASSERT(first_mp != mp); 5720Sstevel@tonic-gate first_mp->b_cont = mp; 5730Sstevel@tonic-gate } else { 5740Sstevel@tonic-gate first_mp = mp; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 5790Sstevel@tonic-gate if (sctp->sctp_running) { 5800Sstevel@tonic-gate if (mctl_present) 5810Sstevel@tonic-gate mp->b_prev = first_mp; 5820Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_FALSE)) { 5833284Sapersson BUMP_MIB(recv_ill->ill_ip_mib, ipIfStatsInDiscards); 5840Sstevel@tonic-gate freemsg(first_mp); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5870Sstevel@tonic-gate } else { 5880Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 5890Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 5920Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 5930Sstevel@tonic-gate if (mctl_present) 5940Sstevel@tonic-gate mp->b_prev = first_mp; 5950Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_TRUE)) { 5963284Sapersson BUMP_MIB(recv_ill->ill_ip_mib, 5973284Sapersson ipIfStatsInDiscards); 5980Sstevel@tonic-gate freemsg(first_mp); 5990Sstevel@tonic-gate } 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); 6040Sstevel@tonic-gate sctp_input_data(sctp, mp, (mctl_present ? first_mp : 6050Sstevel@tonic-gate NULL)); 6060Sstevel@tonic-gate WAKE_SCTP(sctp); 6070Sstevel@tonic-gate sctp_process_sendq(sctp); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate SCTP_REFRELE(sctp); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate void 6140Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp) 6150Sstevel@tonic-gate { 6160Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_conn_tfp; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (!tf) { 6190Sstevel@tonic-gate return; 6200Sstevel@tonic-gate } 621852Svi117747 /* 622852Svi117747 * On a clustered note send this notification to the clustering 623852Svi117747 * subsystem. 624852Svi117747 */ 625852Svi117747 if (cl_sctp_disconnect != NULL) { 626852Svi117747 (*cl_sctp_disconnect)(sctp->sctp_family, 627852Svi117747 (cl_sctp_handle_t)sctp); 628852Svi117747 } 629852Svi117747 6300Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6310Sstevel@tonic-gate ASSERT(tf->tf_sctp); 6320Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 6330Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_conn_hash_next; 6340Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6350Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp); 6360Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = NULL; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate } else { 6390Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev); 6400Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp); 6410Sstevel@tonic-gate sctp->sctp_conn_hash_prev->sctp_conn_hash_next = 6420Sstevel@tonic-gate sctp->sctp_conn_hash_next; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6450Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev 6460Sstevel@tonic-gate == sctp); 6470Sstevel@tonic-gate sctp->sctp_conn_hash_next->sctp_conn_hash_prev = 6480Sstevel@tonic-gate sctp->sctp_conn_hash_prev; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate sctp->sctp_conn_hash_next = NULL; 6520Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6530Sstevel@tonic-gate sctp->sctp_conn_tfp = NULL; 6540Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate void 6580Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate if (sctp->sctp_conn_tfp) { 6610Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (!caller_holds_lock) { 6650Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6660Sstevel@tonic-gate } else { 6670Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate sctp->sctp_conn_hash_next = tf->tf_sctp; 6710Sstevel@tonic-gate if (tf->tf_sctp) { 6720Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = sctp; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6750Sstevel@tonic-gate tf->tf_sctp = sctp; 6760Sstevel@tonic-gate sctp->sctp_conn_tfp = tf; 6770Sstevel@tonic-gate if (!caller_holds_lock) { 6780Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate void 6830Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp) 6840Sstevel@tonic-gate { 6850Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_listen_tfp; 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate if (!tf) { 6880Sstevel@tonic-gate return; 6890Sstevel@tonic-gate } 690852Svi117747 /* 691852Svi117747 * On a clustered note send this notification to the clustering 692852Svi117747 * subsystem. 693852Svi117747 */ 694852Svi117747 if (cl_sctp_unlisten != NULL) { 695852Svi117747 uchar_t *slist; 696852Svi117747 ssize_t ssize; 697852Svi117747 698852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 699852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 700852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 701852Svi117747 (*cl_sctp_unlisten)(sctp->sctp_family, slist, 702852Svi117747 sctp->sctp_nsaddrs, sctp->sctp_lport); 703852Svi117747 /* list will be freed by the clustering module */ 704852Svi117747 } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7070Sstevel@tonic-gate ASSERT(tf->tf_sctp); 7080Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 7090Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_listen_hash_next; 710*7480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) { 7110Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp); 7120Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = NULL; 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate } else { 7150Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev); 7160Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next == 7170Sstevel@tonic-gate sctp); 718*7480SKacheong.Poon@Sun.COM ASSERT(sctp->sctp_listen_hash_next == NULL || 719*7480SKacheong.Poon@Sun.COM sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp); 720*7480SKacheong.Poon@Sun.COM 7210Sstevel@tonic-gate sctp->sctp_listen_hash_prev->sctp_listen_hash_next = 7220Sstevel@tonic-gate sctp->sctp_listen_hash_next; 7230Sstevel@tonic-gate 724*7480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) { 7250Sstevel@tonic-gate sctp->sctp_listen_hash_next->sctp_listen_hash_prev = 7260Sstevel@tonic-gate sctp->sctp_listen_hash_prev; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate sctp->sctp_listen_hash_next = NULL; 7300Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7310Sstevel@tonic-gate sctp->sctp_listen_tfp = NULL; 7320Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate void 7360Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp) 7370Sstevel@tonic-gate { 7380Sstevel@tonic-gate if (sctp->sctp_listen_tfp) { 7390Sstevel@tonic-gate sctp_listen_hash_remove(sctp); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7430Sstevel@tonic-gate sctp->sctp_listen_hash_next = tf->tf_sctp; 7440Sstevel@tonic-gate if (tf->tf_sctp) { 7450Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = sctp; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7480Sstevel@tonic-gate tf->tf_sctp = sctp; 7490Sstevel@tonic-gate sctp->sctp_listen_tfp = tf; 7500Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 751852Svi117747 /* 752852Svi117747 * On a clustered note send this notification to the clustering 753852Svi117747 * subsystem. 754852Svi117747 */ 755852Svi117747 if (cl_sctp_listen != NULL) { 756852Svi117747 uchar_t *slist; 757852Svi117747 ssize_t ssize; 758852Svi117747 759852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 760852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 761852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 762852Svi117747 (*cl_sctp_listen)(sctp->sctp_family, slist, 763852Svi117747 sctp->sctp_nsaddrs, sctp->sctp_lport); 764852Svi117747 /* list will be freed by the clustering module */ 765852Svi117747 } 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate /* 7690Sstevel@tonic-gate * Hash list insertion routine for sctp_t structures. 7700Sstevel@tonic-gate * Inserts entries with the ones bound to a specific IP address first 7710Sstevel@tonic-gate * followed by those bound to INADDR_ANY. 7720Sstevel@tonic-gate */ 7730Sstevel@tonic-gate void 7740Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock) 7750Sstevel@tonic-gate { 7760Sstevel@tonic-gate sctp_t **sctpp; 7770Sstevel@tonic-gate sctp_t *sctpnext; 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate if (sctp->sctp_ptpbhn != NULL) { 7800Sstevel@tonic-gate ASSERT(!caller_holds_lock); 7810Sstevel@tonic-gate sctp_bind_hash_remove(sctp); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate sctpp = &tbf->tf_sctp; 7840Sstevel@tonic-gate if (!caller_holds_lock) { 7850Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 7860Sstevel@tonic-gate } else { 7870Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tbf->tf_lock)); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate sctpnext = sctpp[0]; 7900Sstevel@tonic-gate if (sctpnext) { 7910Sstevel@tonic-gate sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash; 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate sctp->sctp_bind_hash = sctpnext; 7940Sstevel@tonic-gate sctp->sctp_ptpbhn = sctpp; 7950Sstevel@tonic-gate sctpp[0] = sctp; 7960Sstevel@tonic-gate /* For sctp_*_hash_remove */ 7970Sstevel@tonic-gate sctp->sctp_bind_lockp = &tbf->tf_lock; 7980Sstevel@tonic-gate if (!caller_holds_lock) 7990Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* 8030Sstevel@tonic-gate * Hash list removal routine for sctp_t structures. 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate void 8060Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp) 8070Sstevel@tonic-gate { 8080Sstevel@tonic-gate sctp_t *sctpnext; 8090Sstevel@tonic-gate kmutex_t *lockp; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate lockp = sctp->sctp_bind_lockp; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (sctp->sctp_ptpbhn == NULL) 8140Sstevel@tonic-gate return; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate ASSERT(lockp != NULL); 8170Sstevel@tonic-gate mutex_enter(lockp); 8180Sstevel@tonic-gate if (sctp->sctp_ptpbhn) { 8190Sstevel@tonic-gate sctpnext = sctp->sctp_bind_hash; 8200Sstevel@tonic-gate if (sctpnext) { 8210Sstevel@tonic-gate sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn; 8220Sstevel@tonic-gate sctp->sctp_bind_hash = NULL; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate *sctp->sctp_ptpbhn = sctpnext; 8250Sstevel@tonic-gate sctp->sctp_ptpbhn = NULL; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate mutex_exit(lockp); 8280Sstevel@tonic-gate sctp->sctp_bind_lockp = NULL; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 832*7480SKacheong.Poon@Sun.COM * Similar to but different from sctp_conn_match(). 8330Sstevel@tonic-gate * 8340Sstevel@tonic-gate * Matches sets of addresses as follows: if the argument addr set is 8350Sstevel@tonic-gate * a complete subset of the corresponding addr set in the sctp_t, it 8360Sstevel@tonic-gate * is a match. 8370Sstevel@tonic-gate * 8380Sstevel@tonic-gate * Caller must hold tf->tf_lock. 8390Sstevel@tonic-gate * 8400Sstevel@tonic-gate * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE. 8410Sstevel@tonic-gate */ 8420Sstevel@tonic-gate sctp_t * 8430Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports, 8440Sstevel@tonic-gate int min_state) 8450Sstevel@tonic-gate { 8460Sstevel@tonic-gate sctp_t *sctp; 8470Sstevel@tonic-gate sctp_faddr_t *fp; 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 8500Sstevel@tonic-gate 851*7480SKacheong.Poon@Sun.COM for (sctp = tf->tf_sctp; sctp != NULL; 852*7480SKacheong.Poon@Sun.COM sctp = sctp->sctp_conn_hash_next) { 8530Sstevel@tonic-gate if (*ports != sctp->sctp_ports || sctp->sctp_state < 8540Sstevel@tonic-gate min_state) { 8550Sstevel@tonic-gate continue; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate /* check for faddr match */ 859*7480SKacheong.Poon@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { 8600Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) { 8610Sstevel@tonic-gate break; 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 865*7480SKacheong.Poon@Sun.COM if (fp == NULL) { 8660Sstevel@tonic-gate /* no faddr match; keep looking */ 8670Sstevel@tonic-gate continue; 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 870*7480SKacheong.Poon@Sun.COM /* 871*7480SKacheong.Poon@Sun.COM * There is an existing association with the same peer 872*7480SKacheong.Poon@Sun.COM * address. So now we need to check if our local address 873*7480SKacheong.Poon@Sun.COM * set overlaps with the one of the existing association. 874*7480SKacheong.Poon@Sun.COM * If they overlap, we should return it. 875*7480SKacheong.Poon@Sun.COM */ 876*7480SKacheong.Poon@Sun.COM if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) { 8770Sstevel@tonic-gate goto done; 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate /* no match; continue searching */ 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate done: 884*7480SKacheong.Poon@Sun.COM if (sctp != NULL) { 8850Sstevel@tonic-gate SCTP_REFHOLD(sctp); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate return (sctp); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate boolean_t 8910Sstevel@tonic-gate ip_fanout_sctp_raw_match(conn_t *connp, uint32_t ports, ipha_t *ipha) 8920Sstevel@tonic-gate { 8930Sstevel@tonic-gate uint16_t lport; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate if (connp->conn_fully_bound) { 8960Sstevel@tonic-gate return (IPCL_CONN_MATCH(connp, IPPROTO_SCTP, ipha->ipha_src, 8970Sstevel@tonic-gate ipha->ipha_dst, ports)); 8980Sstevel@tonic-gate } else { 8990Sstevel@tonic-gate lport = htons(ntohl(ports) & 0xFFFF); 9000Sstevel@tonic-gate return (IPCL_BIND_MATCH(connp, IPPROTO_SCTP, ipha->ipha_dst, 9010Sstevel@tonic-gate lport)); 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate boolean_t 9060Sstevel@tonic-gate ip_fanout_sctp_raw_match_v6(conn_t *connp, uint32_t ports, ip6_t *ip6h, 9070Sstevel@tonic-gate boolean_t for_v4) 9080Sstevel@tonic-gate { 9090Sstevel@tonic-gate uint16_t lport; 9100Sstevel@tonic-gate in6_addr_t v6dst; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate if (!for_v4 && connp->conn_fully_bound) { 9130Sstevel@tonic-gate return (IPCL_CONN_MATCH_V6(connp, IPPROTO_SCTP, ip6h->ip6_src, 9140Sstevel@tonic-gate ip6h->ip6_dst, ports)); 9150Sstevel@tonic-gate } else { 9160Sstevel@tonic-gate lport = htons(ntohl(ports) & 0xFFFF); 9170Sstevel@tonic-gate if (for_v4) 9180Sstevel@tonic-gate v6dst = ipv6_all_zeros; 9190Sstevel@tonic-gate else 9200Sstevel@tonic-gate v6dst = ip6h->ip6_dst; 9210Sstevel@tonic-gate return (IPCL_BIND_MATCH_V6(connp, IPPROTO_SCTP, v6dst, lport)); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate } 924