xref: /onnv-gate/usr/src/uts/common/inet/sctp/sctp_hash.c (revision 7480:2bcd910ba7ea)
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