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 5*1676Sjpk * Common Development and Distribution License (the "License"). 6*1676Sjpk * 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*1676Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/socket.h> 300Sstevel@tonic-gate #include <sys/ddi.h> 310Sstevel@tonic-gate #include <sys/sunddi.h> 32*1676Sjpk #include <sys/tsol/tndb.h> 33*1676Sjpk #include <sys/tsol/tnet.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <netinet/in.h> 360Sstevel@tonic-gate #include <netinet/ip6.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include <inet/common.h> 390Sstevel@tonic-gate #include <inet/ip.h> 400Sstevel@tonic-gate #include <inet/ip6.h> 410Sstevel@tonic-gate #include <inet/ipclassifier.h> 420Sstevel@tonic-gate #include <inet/ipsec_impl.h> 430Sstevel@tonic-gate #include <inet/ipp_common.h> 440Sstevel@tonic-gate #include <inet/sctp_ip.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include "sctp_impl.h" 470Sstevel@tonic-gate #include "sctp_addr.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* SCTP bind hash list - all sctp_t with state >= BOUND. */ 500Sstevel@tonic-gate sctp_tf_t sctp_bind_fanout[SCTP_BIND_FANOUT_SIZE]; 510Sstevel@tonic-gate /* SCTP listen hash list - all sctp_t with state == LISTEN. */ 520Sstevel@tonic-gate sctp_tf_t sctp_listen_fanout[SCTP_LISTEN_FANOUT_SIZE]; 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* Default association hash size. The size must be a power of 2. */ 550Sstevel@tonic-gate #define SCTP_CONN_HASH_SIZE 8192 560Sstevel@tonic-gate 570Sstevel@tonic-gate sctp_tf_t *sctp_conn_fanout; 580Sstevel@tonic-gate uint_t sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; 590Sstevel@tonic-gate 60852Svi117747 /* 61852Svi117747 * Cluster networking hook for traversing current assoc list. 62852Svi117747 * This routine is used to extract the current list of live associations 63852Svi117747 * which must continue to to be dispatched to this node. 64852Svi117747 */ 65852Svi117747 int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *, 66852Svi117747 boolean_t); 67852Svi117747 680Sstevel@tonic-gate void 690Sstevel@tonic-gate sctp_hash_init() 700Sstevel@tonic-gate { 710Sstevel@tonic-gate int i; 720Sstevel@tonic-gate 730Sstevel@tonic-gate if (sctp_conn_hash_size & (sctp_conn_hash_size - 1)) { 740Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */ 750Sstevel@tonic-gate for (i = 0; i < 31; i++) { 760Sstevel@tonic-gate if (sctp_conn_hash_size < (1 << i)) 770Sstevel@tonic-gate break; 780Sstevel@tonic-gate } 790Sstevel@tonic-gate sctp_conn_hash_size = 1 << i; 800Sstevel@tonic-gate } 810Sstevel@tonic-gate if (sctp_conn_hash_size < SCTP_CONN_HASH_SIZE) { 820Sstevel@tonic-gate sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; 830Sstevel@tonic-gate cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n", 840Sstevel@tonic-gate sctp_conn_hash_size); 850Sstevel@tonic-gate } 860Sstevel@tonic-gate sctp_conn_fanout = 870Sstevel@tonic-gate (sctp_tf_t *)kmem_zalloc(sctp_conn_hash_size * 880Sstevel@tonic-gate sizeof (sctp_tf_t), KM_SLEEP); 890Sstevel@tonic-gate for (i = 0; i < sctp_conn_hash_size; i++) { 900Sstevel@tonic-gate mutex_init(&sctp_conn_fanout[i].tf_lock, NULL, 910Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 920Sstevel@tonic-gate } 930Sstevel@tonic-gate for (i = 0; i < A_CNT(sctp_listen_fanout); i++) { 940Sstevel@tonic-gate mutex_init(&sctp_listen_fanout[i].tf_lock, NULL, 950Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 960Sstevel@tonic-gate } 970Sstevel@tonic-gate for (i = 0; i < A_CNT(sctp_bind_fanout); i++) { 980Sstevel@tonic-gate mutex_init(&sctp_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 1040Sstevel@tonic-gate sctp_hash_destroy() 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate int i; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate for (i = 0; i < sctp_conn_hash_size; i++) { 1090Sstevel@tonic-gate mutex_destroy(&sctp_conn_fanout[i].tf_lock); 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate kmem_free(sctp_conn_fanout, sctp_conn_hash_size * sizeof (sctp_tf_t)); 1120Sstevel@tonic-gate for (i = 0; i < A_CNT(sctp_listen_fanout); i++) { 1130Sstevel@tonic-gate mutex_destroy(&sctp_listen_fanout[i].tf_lock); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate for (i = 0; i < A_CNT(sctp_bind_fanout); i++) { 1160Sstevel@tonic-gate mutex_destroy(&sctp_bind_fanout[i].tf_lock); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* Walk the SCTP global list and refrele the ire for this ipif */ 1210Sstevel@tonic-gate void 1220Sstevel@tonic-gate sctp_ire_cache_flush(ipif_t *ipif) 1230Sstevel@tonic-gate { 1240Sstevel@tonic-gate sctp_t *sctp; 1250Sstevel@tonic-gate sctp_t *sctp_prev = NULL; 1260Sstevel@tonic-gate sctp_faddr_t *fp; 1270Sstevel@tonic-gate conn_t *connp; 1280Sstevel@tonic-gate ire_t *ire; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate sctp = gsctp; 1310Sstevel@tonic-gate mutex_enter(&sctp_g_lock); 1320Sstevel@tonic-gate while (sctp != NULL) { 1330Sstevel@tonic-gate mutex_enter(&sctp->sctp_reflock); 1340Sstevel@tonic-gate if (sctp->sctp_condemned) { 1350Sstevel@tonic-gate mutex_exit(&sctp->sctp_reflock); 1360Sstevel@tonic-gate sctp = list_next(&sctp_g_list, sctp); 1370Sstevel@tonic-gate continue; 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate sctp->sctp_refcnt++; 1400Sstevel@tonic-gate mutex_exit(&sctp->sctp_reflock); 1410Sstevel@tonic-gate mutex_exit(&sctp_g_lock); 1420Sstevel@tonic-gate if (sctp_prev != NULL) 1430Sstevel@tonic-gate SCTP_REFRELE(sctp_prev); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate RUN_SCTP(sctp); 1460Sstevel@tonic-gate connp = sctp->sctp_connp; 1470Sstevel@tonic-gate mutex_enter(&connp->conn_lock); 1480Sstevel@tonic-gate ire = connp->conn_ire_cache; 1490Sstevel@tonic-gate if (ire != NULL && 1500Sstevel@tonic-gate (ipif == NULL || ire->ire_ipif == ipif)) { 1510Sstevel@tonic-gate connp->conn_ire_cache = NULL; 1520Sstevel@tonic-gate mutex_exit(&connp->conn_lock); 1530Sstevel@tonic-gate IRE_REFRELE_NOTR(ire); 1540Sstevel@tonic-gate } else { 1550Sstevel@tonic-gate mutex_exit(&connp->conn_lock); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate /* check for ires cached in faddr */ 1580Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp != NULL; 1590Sstevel@tonic-gate fp = fp->next) { 1600Sstevel@tonic-gate ire = fp->ire; 1610Sstevel@tonic-gate if (ire != NULL && (ipif == NULL || 1620Sstevel@tonic-gate ire->ire_ipif == ipif)) { 1630Sstevel@tonic-gate fp->ire = NULL; 1640Sstevel@tonic-gate IRE_REFRELE_NOTR(ire); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate WAKE_SCTP(sctp); 1680Sstevel@tonic-gate sctp_prev = sctp; 1690Sstevel@tonic-gate mutex_enter(&sctp_g_lock); 1700Sstevel@tonic-gate sctp = list_next(&sctp_g_list, sctp); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate mutex_exit(&sctp_g_lock); 1730Sstevel@tonic-gate if (sctp_prev != NULL) 1740Sstevel@tonic-gate SCTP_REFRELE(sctp_prev); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 177852Svi117747 /* 178852Svi117747 * Exported routine for extracting active SCTP associations. 179852Svi117747 * Like TCP, we terminate the walk if the callback returns non-zero. 180852Svi117747 */ 181852Svi117747 int 182852Svi117747 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *arg, 183852Svi117747 boolean_t cansleep) 184852Svi117747 { 185852Svi117747 sctp_t *sctp; 186852Svi117747 sctp_t *sctp_prev; 187852Svi117747 cl_sctp_info_t cl_sctpi; 188852Svi117747 uchar_t *slist; 189852Svi117747 uchar_t *flist; 190852Svi117747 191852Svi117747 sctp = gsctp; 192852Svi117747 sctp_prev = NULL; 193852Svi117747 mutex_enter(&sctp_g_lock); 194852Svi117747 while (sctp != NULL) { 195852Svi117747 size_t ssize; 196852Svi117747 size_t fsize; 197852Svi117747 198852Svi117747 mutex_enter(&sctp->sctp_reflock); 199852Svi117747 if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) { 200852Svi117747 mutex_exit(&sctp->sctp_reflock); 201852Svi117747 sctp = list_next(&sctp_g_list, sctp); 202852Svi117747 continue; 203852Svi117747 } 204852Svi117747 sctp->sctp_refcnt++; 205852Svi117747 mutex_exit(&sctp->sctp_reflock); 206852Svi117747 mutex_exit(&sctp_g_lock); 207852Svi117747 if (sctp_prev != NULL) 208852Svi117747 SCTP_REFRELE(sctp_prev); 209852Svi117747 RUN_SCTP(sctp); 210852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 211852Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 212852Svi117747 213852Svi117747 slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP); 214852Svi117747 flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP); 215852Svi117747 if (slist == NULL || flist == NULL) { 216852Svi117747 WAKE_SCTP(sctp); 217852Svi117747 if (slist != NULL) 218852Svi117747 kmem_free(slist, ssize); 219852Svi117747 if (flist != NULL) 220852Svi117747 kmem_free(flist, fsize); 221852Svi117747 SCTP_REFRELE(sctp); 222852Svi117747 return (1); 223852Svi117747 } 224852Svi117747 cl_sctpi.cl_sctpi_version = CL_SCTPI_V1; 225852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 226852Svi117747 sctp_get_faddr_list(sctp, flist, fsize); 227852Svi117747 cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs; 228852Svi117747 cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs; 229852Svi117747 cl_sctpi.cl_sctpi_family = sctp->sctp_family; 230852Svi117747 cl_sctpi.cl_sctpi_ipversion = sctp->sctp_ipversion; 231852Svi117747 cl_sctpi.cl_sctpi_state = sctp->sctp_state; 232852Svi117747 cl_sctpi.cl_sctpi_lport = sctp->sctp_lport; 233852Svi117747 cl_sctpi.cl_sctpi_fport = sctp->sctp_fport; 234852Svi117747 cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp; 235852Svi117747 WAKE_SCTP(sctp); 236852Svi117747 cl_sctpi.cl_sctpi_laddrp = slist; 237852Svi117747 cl_sctpi.cl_sctpi_faddrp = flist; 238852Svi117747 if ((*cl_callback)(&cl_sctpi, arg) != 0) { 239852Svi117747 kmem_free(slist, ssize); 240852Svi117747 kmem_free(flist, fsize); 241852Svi117747 SCTP_REFRELE(sctp); 242852Svi117747 return (1); 243852Svi117747 } 244852Svi117747 /* list will be freed by cl_callback */ 245852Svi117747 sctp_prev = sctp; 246852Svi117747 mutex_enter(&sctp_g_lock); 247852Svi117747 sctp = list_next(&sctp_g_list, sctp); 248852Svi117747 } 249852Svi117747 mutex_exit(&sctp_g_lock); 250852Svi117747 if (sctp_prev != NULL) 251852Svi117747 SCTP_REFRELE(sctp_prev); 252852Svi117747 return (0); 253852Svi117747 } 254852Svi117747 2550Sstevel@tonic-gate sctp_t * 2560Sstevel@tonic-gate sctp_conn_match(in6_addr_t *faddr, in6_addr_t *laddr, uint32_t ports, 2570Sstevel@tonic-gate uint_t ipif_seqid, zoneid_t zoneid) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate sctp_tf_t *tf; 2600Sstevel@tonic-gate sctp_t *sctp; 2610Sstevel@tonic-gate sctp_faddr_t *fp; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate tf = &(sctp_conn_fanout[SCTP_CONN_HASH(ports)]); 2640Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) { 2670Sstevel@tonic-gate if (ports != sctp->sctp_ports || (zoneid != ALL_ZONES && 2680Sstevel@tonic-gate zoneid != sctp->sctp_zoneid)) { 2690Sstevel@tonic-gate continue; 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* check for faddr match */ 2730Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp; fp = fp->next) { 2740Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) { 2750Sstevel@tonic-gate break; 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate if (!fp) { 2800Sstevel@tonic-gate /* no faddr match; keep looking */ 2810Sstevel@tonic-gate continue; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* check for laddr match */ 2850Sstevel@tonic-gate if (ipif_seqid == 0) { 286852Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 2870Sstevel@tonic-gate SCTP_REFHOLD(sctp); 2880Sstevel@tonic-gate goto done; 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate } else { 2910Sstevel@tonic-gate if (sctp_ipif_lookup(sctp, ipif_seqid) != NULL) { 2920Sstevel@tonic-gate SCTP_REFHOLD(sctp); 2930Sstevel@tonic-gate goto done; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate /* no match; continue to the next in the chain */ 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate done: 3000Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3010Sstevel@tonic-gate return (sctp); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate static sctp_t * 3050Sstevel@tonic-gate listen_match(in6_addr_t *laddr, uint32_t ports, uint_t ipif_seqid, 3060Sstevel@tonic-gate zoneid_t zoneid) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate sctp_t *sctp; 3090Sstevel@tonic-gate sctp_tf_t *tf; 3100Sstevel@tonic-gate uint16_t lport; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate lport = ((uint16_t *)&ports)[1]; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate tf = &(sctp_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]); 3150Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) { 3180Sstevel@tonic-gate if (lport != sctp->sctp_lport || (zoneid != ALL_ZONES && 3190Sstevel@tonic-gate zoneid != sctp->sctp_zoneid)) { 3200Sstevel@tonic-gate continue; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (ipif_seqid == 0) { 324852Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 3250Sstevel@tonic-gate SCTP_REFHOLD(sctp); 3260Sstevel@tonic-gate goto done; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate } else { 3290Sstevel@tonic-gate if (sctp_ipif_lookup(sctp, ipif_seqid) != NULL) { 3300Sstevel@tonic-gate SCTP_REFHOLD(sctp); 3310Sstevel@tonic-gate goto done; 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate /* no match; continue to the next in the chain */ 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate done: 3380Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3390Sstevel@tonic-gate return (sctp); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 342*1676Sjpk /* called by ipsec_sctp_pol */ 3430Sstevel@tonic-gate conn_t * 3440Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 3450Sstevel@tonic-gate uint_t ipif_seqid, zoneid_t zoneid) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate sctp_t *sctp; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if ((sctp = sctp_conn_match(src, dst, ports, ipif_seqid, 3500Sstevel@tonic-gate zoneid)) == NULL) { 3510Sstevel@tonic-gate /* Not in conn fanout; check listen fanout */ 3520Sstevel@tonic-gate if ((sctp = listen_match(dst, ports, ipif_seqid, 3530Sstevel@tonic-gate zoneid)) == NULL) { 3540Sstevel@tonic-gate return (NULL); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate return (sctp->sctp_connp); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 360*1676Sjpk conn_t * 361*1676Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 362*1676Sjpk uint_t ipif_seqid, zoneid_t zoneid, mblk_t *mp) 363*1676Sjpk { 364*1676Sjpk sctp_t *sctp; 365*1676Sjpk 366*1676Sjpk if ((sctp = sctp_conn_match(src, dst, ports, ipif_seqid, 367*1676Sjpk zoneid)) == NULL) { 368*1676Sjpk if (zoneid == ALL_ZONES) { 369*1676Sjpk zoneid = tsol_mlp_findzone(IPPROTO_SCTP, 370*1676Sjpk htons(ntohl(ports) & 0xFFFF)); 371*1676Sjpk /* 372*1676Sjpk * If no shared MLP is found, tsol_mlp_findzone returns 373*1676Sjpk * ALL_ZONES. In that case, we assume it's SLP, and 374*1676Sjpk * search for the zone based on the packet label. 375*1676Sjpk * That will also return ALL_ZONES on failure. 376*1676Sjpk */ 377*1676Sjpk if (zoneid == ALL_ZONES) 378*1676Sjpk zoneid = tsol_packet_to_zoneid(mp); 379*1676Sjpk if (zoneid == ALL_ZONES) 380*1676Sjpk return (NULL); 381*1676Sjpk } 382*1676Sjpk /* Not in conn fanout; check listen fanout */ 383*1676Sjpk if ((sctp = listen_match(dst, ports, ipif_seqid, 384*1676Sjpk zoneid)) == NULL) { 385*1676Sjpk return (NULL); 386*1676Sjpk } 387*1676Sjpk } 388*1676Sjpk return (sctp->sctp_connp); 389*1676Sjpk } 390*1676Sjpk 3910Sstevel@tonic-gate /* 3920Sstevel@tonic-gate * Fanout for SCTP packets 3930Sstevel@tonic-gate * The caller puts <fport, lport> in the ports parameter. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate /* ARGSUSED */ 3960Sstevel@tonic-gate void 3970Sstevel@tonic-gate ip_fanout_sctp(mblk_t *mp, ill_t *recv_ill, ipha_t *ipha, 3980Sstevel@tonic-gate uint32_t ports, uint_t flags, boolean_t mctl_present, boolean_t ip_policy, 3990Sstevel@tonic-gate uint_t ipif_seqid, zoneid_t zoneid) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate sctp_t *sctp; 4020Sstevel@tonic-gate boolean_t isv4; 4030Sstevel@tonic-gate conn_t *connp; 4040Sstevel@tonic-gate mblk_t *first_mp; 4050Sstevel@tonic-gate ip6_t *ip6h; 4060Sstevel@tonic-gate in6_addr_t map_src, map_dst; 4070Sstevel@tonic-gate in6_addr_t *src, *dst; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate first_mp = mp; 4100Sstevel@tonic-gate if (mctl_present) { 4110Sstevel@tonic-gate mp = first_mp->b_cont; 4120Sstevel@tonic-gate ASSERT(mp != NULL); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* Assume IP provides aligned packets - otherwise toss */ 4160Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) { 4170Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 4180Sstevel@tonic-gate freemsg(first_mp); 4190Sstevel@tonic-gate return; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV6_VERSION) { 4230Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 4240Sstevel@tonic-gate src = &ip6h->ip6_src; 4250Sstevel@tonic-gate dst = &ip6h->ip6_dst; 4260Sstevel@tonic-gate isv4 = B_FALSE; 4270Sstevel@tonic-gate } else { 4280Sstevel@tonic-gate ip6h = NULL; 4290Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src); 4300Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst); 4310Sstevel@tonic-gate src = &map_src; 4320Sstevel@tonic-gate dst = &map_dst; 4330Sstevel@tonic-gate isv4 = B_TRUE; 4340Sstevel@tonic-gate } 435*1676Sjpk if ((connp = sctp_fanout(src, dst, ports, ipif_seqid, zoneid, mp)) == 4360Sstevel@tonic-gate NULL) { 4370Sstevel@tonic-gate ip_fanout_sctp_raw(mp, recv_ill, ipha, isv4, 4380Sstevel@tonic-gate ports, mctl_present, flags, ip_policy, 4390Sstevel@tonic-gate ipif_seqid, zoneid); 4400Sstevel@tonic-gate return; 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate sctp = CONN2SCTP(connp); 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate /* Found a client; up it goes */ 4450Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDelivers); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 4490Sstevel@tonic-gate * This should be fine. 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate if (CONN_INBOUND_POLICY_PRESENT(connp) || mctl_present) { 4520Sstevel@tonic-gate first_mp = ipsec_check_inbound_policy(first_mp, connp, 4530Sstevel@tonic-gate ipha, NULL, mctl_present); 4540Sstevel@tonic-gate if (first_mp == NULL) { 4550Sstevel@tonic-gate SCTP_REFRELE(sctp); 4560Sstevel@tonic-gate return; 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* Initiate IPPF processing for fastpath */ 4610Sstevel@tonic-gate if (IPP_ENABLED(IPP_LOCAL_IN)) { 4620Sstevel@tonic-gate ip_process(IPP_LOCAL_IN, &mp, 4630Sstevel@tonic-gate recv_ill->ill_phyint->phyint_ifindex); 4640Sstevel@tonic-gate if (mp == NULL) { 4650Sstevel@tonic-gate SCTP_REFRELE(sctp); 4660Sstevel@tonic-gate if (mctl_present) 4670Sstevel@tonic-gate freeb(first_mp); 4680Sstevel@tonic-gate return; 4690Sstevel@tonic-gate } else if (mctl_present) { 4700Sstevel@tonic-gate /* 4710Sstevel@tonic-gate * ip_process might return a new mp. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate ASSERT(first_mp != mp); 4740Sstevel@tonic-gate first_mp->b_cont = mp; 4750Sstevel@tonic-gate } else { 4760Sstevel@tonic-gate first_mp = mp; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate if (connp->conn_recvif || connp->conn_recvslla || 4810Sstevel@tonic-gate connp->conn_ipv6_recvpktinfo) { 4820Sstevel@tonic-gate int in_flags = 0; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate if (connp->conn_recvif || connp->conn_ipv6_recvpktinfo) { 4850Sstevel@tonic-gate in_flags = IPF_RECVIF; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate if (connp->conn_recvslla) { 4880Sstevel@tonic-gate in_flags |= IPF_RECVSLLA; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate if (isv4) { 4910Sstevel@tonic-gate mp = ip_add_info(mp, recv_ill, in_flags); 4920Sstevel@tonic-gate } else { 4930Sstevel@tonic-gate mp = ip_add_info_v6(mp, recv_ill, &ip6h->ip6_dst); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate if (mp == NULL) { 4960Sstevel@tonic-gate SCTP_REFRELE(sctp); 4970Sstevel@tonic-gate if (mctl_present) 4980Sstevel@tonic-gate freeb(first_mp); 4990Sstevel@tonic-gate return; 5000Sstevel@tonic-gate } else if (mctl_present) { 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * ip_add_info might return a new mp. 5030Sstevel@tonic-gate */ 5040Sstevel@tonic-gate ASSERT(first_mp != mp); 5050Sstevel@tonic-gate first_mp->b_cont = mp; 5060Sstevel@tonic-gate } else { 5070Sstevel@tonic-gate first_mp = mp; 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 5120Sstevel@tonic-gate if (sctp->sctp_running) { 5130Sstevel@tonic-gate if (mctl_present) 5140Sstevel@tonic-gate mp->b_prev = first_mp; 5150Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_FALSE)) { 5160Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 5170Sstevel@tonic-gate freemsg(first_mp); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 5220Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 5250Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 5260Sstevel@tonic-gate if (mctl_present) 5270Sstevel@tonic-gate mp->b_prev = first_mp; 5280Sstevel@tonic-gate if (!sctp_add_recvq(sctp, mp, B_TRUE)) { 5290Sstevel@tonic-gate BUMP_MIB(&ip_mib, ipInDiscards); 5300Sstevel@tonic-gate freemsg(first_mp); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 5330Sstevel@tonic-gate WAKE_SCTP(sctp); 5340Sstevel@tonic-gate } else { 5350Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 5360Sstevel@tonic-gate sctp_input_data(sctp, mp, (mctl_present ? first_mp : 5370Sstevel@tonic-gate NULL)); 5380Sstevel@tonic-gate WAKE_SCTP(sctp); 5390Sstevel@tonic-gate sctp_process_sendq(sctp); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate SCTP_REFRELE(sctp); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate void 5460Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp) 5470Sstevel@tonic-gate { 5480Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_conn_tfp; 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate if (!tf) { 5510Sstevel@tonic-gate return; 5520Sstevel@tonic-gate } 553852Svi117747 /* 554852Svi117747 * On a clustered note send this notification to the clustering 555852Svi117747 * subsystem. 556852Svi117747 */ 557852Svi117747 if (cl_sctp_disconnect != NULL) { 558852Svi117747 (*cl_sctp_disconnect)(sctp->sctp_family, 559852Svi117747 (cl_sctp_handle_t)sctp); 560852Svi117747 } 561852Svi117747 5620Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 5630Sstevel@tonic-gate ASSERT(tf->tf_sctp); 5640Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 5650Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_conn_hash_next; 5660Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 5670Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp); 5680Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = NULL; 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate } else { 5710Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev); 5720Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp); 5730Sstevel@tonic-gate sctp->sctp_conn_hash_prev->sctp_conn_hash_next = 5740Sstevel@tonic-gate sctp->sctp_conn_hash_next; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 5770Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev 5780Sstevel@tonic-gate == sctp); 5790Sstevel@tonic-gate sctp->sctp_conn_hash_next->sctp_conn_hash_prev = 5800Sstevel@tonic-gate sctp->sctp_conn_hash_prev; 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate sctp->sctp_conn_hash_next = NULL; 5840Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 5850Sstevel@tonic-gate sctp->sctp_conn_tfp = NULL; 5860Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate void 5900Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate if (sctp->sctp_conn_tfp) { 5930Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (!caller_holds_lock) { 5970Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 5980Sstevel@tonic-gate } else { 5990Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate sctp->sctp_conn_hash_next = tf->tf_sctp; 6030Sstevel@tonic-gate if (tf->tf_sctp) { 6040Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = sctp; 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6070Sstevel@tonic-gate tf->tf_sctp = sctp; 6080Sstevel@tonic-gate sctp->sctp_conn_tfp = tf; 6090Sstevel@tonic-gate if (!caller_holds_lock) { 6100Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate void 6150Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp) 6160Sstevel@tonic-gate { 6170Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_listen_tfp; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (!tf) { 6200Sstevel@tonic-gate return; 6210Sstevel@tonic-gate } 622852Svi117747 /* 623852Svi117747 * On a clustered note send this notification to the clustering 624852Svi117747 * subsystem. 625852Svi117747 */ 626852Svi117747 if (cl_sctp_unlisten != NULL) { 627852Svi117747 uchar_t *slist; 628852Svi117747 ssize_t ssize; 629852Svi117747 630852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 631852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 632852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 633852Svi117747 (*cl_sctp_unlisten)(sctp->sctp_family, slist, 634852Svi117747 sctp->sctp_nsaddrs, sctp->sctp_lport); 635852Svi117747 /* list will be freed by the clustering module */ 636852Svi117747 } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6390Sstevel@tonic-gate ASSERT(tf->tf_sctp); 6400Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 6410Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_listen_hash_next; 6420Sstevel@tonic-gate if (sctp->sctp_listen_hash_next) { 6430Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp); 6440Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = NULL; 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate } else { 6470Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev); 6480Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next == 6490Sstevel@tonic-gate sctp); 6500Sstevel@tonic-gate sctp->sctp_listen_hash_prev->sctp_listen_hash_next = 6510Sstevel@tonic-gate sctp->sctp_listen_hash_next; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate if (sctp->sctp_listen_hash_next) { 6540Sstevel@tonic-gate ASSERT( 6550Sstevel@tonic-gate sctp->sctp_listen_hash_next->sctp_listen_hash_prev == 6560Sstevel@tonic-gate sctp); 6570Sstevel@tonic-gate sctp->sctp_listen_hash_next->sctp_listen_hash_prev = 6580Sstevel@tonic-gate sctp->sctp_listen_hash_prev; 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate sctp->sctp_listen_hash_next = NULL; 6620Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 6630Sstevel@tonic-gate sctp->sctp_listen_tfp = NULL; 6640Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate void 6680Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp) 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate if (sctp->sctp_listen_tfp) { 6710Sstevel@tonic-gate sctp_listen_hash_remove(sctp); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6750Sstevel@tonic-gate sctp->sctp_listen_hash_next = tf->tf_sctp; 6760Sstevel@tonic-gate if (tf->tf_sctp) { 6770Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = sctp; 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 6800Sstevel@tonic-gate tf->tf_sctp = sctp; 6810Sstevel@tonic-gate sctp->sctp_listen_tfp = tf; 6820Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 683852Svi117747 /* 684852Svi117747 * On a clustered note send this notification to the clustering 685852Svi117747 * subsystem. 686852Svi117747 */ 687852Svi117747 if (cl_sctp_listen != NULL) { 688852Svi117747 uchar_t *slist; 689852Svi117747 ssize_t ssize; 690852Svi117747 691852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 692852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 693852Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 694852Svi117747 (*cl_sctp_listen)(sctp->sctp_family, slist, 695852Svi117747 sctp->sctp_nsaddrs, sctp->sctp_lport); 696852Svi117747 /* list will be freed by the clustering module */ 697852Svi117747 } 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Hash list insertion routine for sctp_t structures. 7020Sstevel@tonic-gate * Inserts entries with the ones bound to a specific IP address first 7030Sstevel@tonic-gate * followed by those bound to INADDR_ANY. 7040Sstevel@tonic-gate */ 7050Sstevel@tonic-gate void 7060Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock) 7070Sstevel@tonic-gate { 7080Sstevel@tonic-gate sctp_t **sctpp; 7090Sstevel@tonic-gate sctp_t *sctpnext; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (sctp->sctp_ptpbhn != NULL) { 7120Sstevel@tonic-gate ASSERT(!caller_holds_lock); 7130Sstevel@tonic-gate sctp_bind_hash_remove(sctp); 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate sctpp = &tbf->tf_sctp; 7160Sstevel@tonic-gate if (!caller_holds_lock) { 7170Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 7180Sstevel@tonic-gate } else { 7190Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tbf->tf_lock)); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate sctpnext = sctpp[0]; 7220Sstevel@tonic-gate if (sctpnext) { 7230Sstevel@tonic-gate sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash; 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate sctp->sctp_bind_hash = sctpnext; 7260Sstevel@tonic-gate sctp->sctp_ptpbhn = sctpp; 7270Sstevel@tonic-gate sctpp[0] = sctp; 7280Sstevel@tonic-gate /* For sctp_*_hash_remove */ 7290Sstevel@tonic-gate sctp->sctp_bind_lockp = &tbf->tf_lock; 7300Sstevel@tonic-gate if (!caller_holds_lock) 7310Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * Hash list removal routine for sctp_t structures. 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate void 7380Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate sctp_t *sctpnext; 7410Sstevel@tonic-gate kmutex_t *lockp; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate lockp = sctp->sctp_bind_lockp; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (sctp->sctp_ptpbhn == NULL) 7460Sstevel@tonic-gate return; 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate ASSERT(lockp != NULL); 7490Sstevel@tonic-gate mutex_enter(lockp); 7500Sstevel@tonic-gate if (sctp->sctp_ptpbhn) { 7510Sstevel@tonic-gate sctpnext = sctp->sctp_bind_hash; 7520Sstevel@tonic-gate if (sctpnext) { 7530Sstevel@tonic-gate sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn; 7540Sstevel@tonic-gate sctp->sctp_bind_hash = NULL; 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate *sctp->sctp_ptpbhn = sctpnext; 7570Sstevel@tonic-gate sctp->sctp_ptpbhn = NULL; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate mutex_exit(lockp); 7600Sstevel@tonic-gate sctp->sctp_bind_lockp = NULL; 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Similar to but more general than ip_sctp's conn_match(). 7650Sstevel@tonic-gate * 7660Sstevel@tonic-gate * Matches sets of addresses as follows: if the argument addr set is 7670Sstevel@tonic-gate * a complete subset of the corresponding addr set in the sctp_t, it 7680Sstevel@tonic-gate * is a match. 7690Sstevel@tonic-gate * 7700Sstevel@tonic-gate * Caller must hold tf->tf_lock. 7710Sstevel@tonic-gate * 7720Sstevel@tonic-gate * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate sctp_t * 7750Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports, 7760Sstevel@tonic-gate int min_state) 7770Sstevel@tonic-gate { 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate sctp_t *sctp; 7800Sstevel@tonic-gate sctp_faddr_t *fp; 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) { 7850Sstevel@tonic-gate if (*ports != sctp->sctp_ports || sctp->sctp_state < 7860Sstevel@tonic-gate min_state) { 7870Sstevel@tonic-gate continue; 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* check for faddr match */ 7910Sstevel@tonic-gate for (fp = sctp->sctp_faddrs; fp; fp = fp->next) { 7920Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) { 7930Sstevel@tonic-gate break; 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate if (!fp) { 7980Sstevel@tonic-gate /* no faddr match; keep looking */ 7990Sstevel@tonic-gate continue; 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* check for laddr subset match */ 8030Sstevel@tonic-gate if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_SUBSET) { 8040Sstevel@tonic-gate goto done; 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* no match; continue searching */ 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate done: 8110Sstevel@tonic-gate if (sctp) { 8120Sstevel@tonic-gate SCTP_REFHOLD(sctp); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate return (sctp); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate boolean_t 8180Sstevel@tonic-gate ip_fanout_sctp_raw_match(conn_t *connp, uint32_t ports, ipha_t *ipha) 8190Sstevel@tonic-gate { 8200Sstevel@tonic-gate uint16_t lport; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate if (connp->conn_fully_bound) { 8230Sstevel@tonic-gate return (IPCL_CONN_MATCH(connp, IPPROTO_SCTP, ipha->ipha_src, 8240Sstevel@tonic-gate ipha->ipha_dst, ports)); 8250Sstevel@tonic-gate } else { 8260Sstevel@tonic-gate lport = htons(ntohl(ports) & 0xFFFF); 8270Sstevel@tonic-gate return (IPCL_BIND_MATCH(connp, IPPROTO_SCTP, ipha->ipha_dst, 8280Sstevel@tonic-gate lport)); 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate boolean_t 8330Sstevel@tonic-gate ip_fanout_sctp_raw_match_v6(conn_t *connp, uint32_t ports, ip6_t *ip6h, 8340Sstevel@tonic-gate boolean_t for_v4) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate uint16_t lport; 8370Sstevel@tonic-gate in6_addr_t v6dst; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate if (!for_v4 && connp->conn_fully_bound) { 8400Sstevel@tonic-gate return (IPCL_CONN_MATCH_V6(connp, IPPROTO_SCTP, ip6h->ip6_src, 8410Sstevel@tonic-gate ip6h->ip6_dst, ports)); 8420Sstevel@tonic-gate } else { 8430Sstevel@tonic-gate lport = htons(ntohl(ports) & 0xFFFF); 8440Sstevel@tonic-gate if (for_v4) 8450Sstevel@tonic-gate v6dst = ipv6_all_zeros; 8460Sstevel@tonic-gate else 8470Sstevel@tonic-gate v6dst = ip6h->ip6_dst; 8480Sstevel@tonic-gate return (IPCL_BIND_MATCH_V6(connp, IPPROTO_SCTP, v6dst, lport)); 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate } 851