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