xref: /onnv-gate/usr/src/uts/common/inet/sctp/sctp_hash.c (revision 11042:2d6e217af1b4)
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*11042SErik.Nordmark@Sun.COM  * Copyright 2009 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 =
847480SKacheong.Poon@Sun.COM 	    (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size *
85*11042SErik.Nordmark@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,
887480SKacheong.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 /*
132852Svi117747  * Exported routine for extracting active SCTP associations.
133852Svi117747  * Like TCP, we terminate the walk if the callback returns non-zero.
1343448Sdh155122  *
1353448Sdh155122  * Need to walk all sctp_stack_t instances since this clustering
1363448Sdh155122  * interface is assumed global for all instances
137852Svi117747  */
138852Svi117747 int
1393448Sdh155122 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *),
1403448Sdh155122     void *arg, boolean_t cansleep)
1413448Sdh155122 {
1423448Sdh155122 	netstack_handle_t nh;
1433448Sdh155122 	netstack_t *ns;
1443448Sdh155122 	int ret = 0;
1453448Sdh155122 
1463448Sdh155122 	netstack_next_init(&nh);
1473448Sdh155122 	while ((ns = netstack_next(&nh)) != NULL) {
1483448Sdh155122 		ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep,
1493448Sdh155122 		    ns->netstack_sctp);
1503448Sdh155122 		netstack_rele(ns);
1513448Sdh155122 	}
1523448Sdh155122 	netstack_next_fini(&nh);
1533448Sdh155122 	return (ret);
1543448Sdh155122 }
1553448Sdh155122 
1563448Sdh155122 static int
1573448Sdh155122 cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *),
1583448Sdh155122     void *arg, boolean_t cansleep, sctp_stack_t *sctps)
159852Svi117747 {
160852Svi117747 	sctp_t		*sctp;
161852Svi117747 	sctp_t		*sctp_prev;
162852Svi117747 	cl_sctp_info_t	cl_sctpi;
163852Svi117747 	uchar_t		*slist;
164852Svi117747 	uchar_t		*flist;
165852Svi117747 
166852Svi117747 	sctp_prev = NULL;
1673448Sdh155122 	mutex_enter(&sctps->sctps_g_lock);
168*11042SErik.Nordmark@Sun.COM 	sctp = list_head(&sctps->sctps_g_list);
169852Svi117747 	while (sctp != NULL) {
170852Svi117747 		size_t	ssize;
171852Svi117747 		size_t	fsize;
172852Svi117747 
173852Svi117747 		mutex_enter(&sctp->sctp_reflock);
174852Svi117747 		if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) {
175852Svi117747 			mutex_exit(&sctp->sctp_reflock);
1763448Sdh155122 			sctp = list_next(&sctps->sctps_g_list, sctp);
177852Svi117747 			continue;
178852Svi117747 		}
179852Svi117747 		sctp->sctp_refcnt++;
180852Svi117747 		mutex_exit(&sctp->sctp_reflock);
1813448Sdh155122 		mutex_exit(&sctps->sctps_g_lock);
182852Svi117747 		if (sctp_prev != NULL)
183852Svi117747 			SCTP_REFRELE(sctp_prev);
184852Svi117747 		RUN_SCTP(sctp);
185852Svi117747 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
186852Svi117747 		fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
187852Svi117747 
188852Svi117747 		slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP);
189852Svi117747 		flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP);
190852Svi117747 		if (slist == NULL || flist == NULL) {
191852Svi117747 			WAKE_SCTP(sctp);
192852Svi117747 			if (slist != NULL)
193852Svi117747 				kmem_free(slist, ssize);
194852Svi117747 			if (flist != NULL)
195852Svi117747 				kmem_free(flist, fsize);
196852Svi117747 			SCTP_REFRELE(sctp);
197852Svi117747 			return (1);
198852Svi117747 		}
199852Svi117747 		cl_sctpi.cl_sctpi_version = CL_SCTPI_V1;
200852Svi117747 		sctp_get_saddr_list(sctp, slist, ssize);
201852Svi117747 		sctp_get_faddr_list(sctp, flist, fsize);
202852Svi117747 		cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs;
203852Svi117747 		cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs;
204*11042SErik.Nordmark@Sun.COM 		cl_sctpi.cl_sctpi_family = sctp->sctp_connp->conn_family;
205*11042SErik.Nordmark@Sun.COM 		if (cl_sctpi.cl_sctpi_family == AF_INET)
206*11042SErik.Nordmark@Sun.COM 			cl_sctpi.cl_sctpi_ipversion = IPV4_VERSION;
207*11042SErik.Nordmark@Sun.COM 		else
208*11042SErik.Nordmark@Sun.COM 			cl_sctpi.cl_sctpi_ipversion = IPV6_VERSION;
209852Svi117747 		cl_sctpi.cl_sctpi_state = sctp->sctp_state;
210*11042SErik.Nordmark@Sun.COM 		cl_sctpi.cl_sctpi_lport = sctp->sctp_connp->conn_lport;
211*11042SErik.Nordmark@Sun.COM 		cl_sctpi.cl_sctpi_fport = sctp->sctp_connp->conn_fport;
212852Svi117747 		cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp;
213852Svi117747 		WAKE_SCTP(sctp);
214852Svi117747 		cl_sctpi.cl_sctpi_laddrp = slist;
215852Svi117747 		cl_sctpi.cl_sctpi_faddrp = flist;
216852Svi117747 		if ((*cl_callback)(&cl_sctpi, arg) != 0) {
217852Svi117747 			kmem_free(slist, ssize);
218852Svi117747 			kmem_free(flist, fsize);
219852Svi117747 			SCTP_REFRELE(sctp);
220852Svi117747 			return (1);
221852Svi117747 		}
222852Svi117747 		/* list will be freed by cl_callback */
223852Svi117747 		sctp_prev = sctp;
2243448Sdh155122 		mutex_enter(&sctps->sctps_g_lock);
2253448Sdh155122 		sctp = list_next(&sctps->sctps_g_list, sctp);
226852Svi117747 	}
2273448Sdh155122 	mutex_exit(&sctps->sctps_g_lock);
228852Svi117747 	if (sctp_prev != NULL)
229852Svi117747 		SCTP_REFRELE(sctp_prev);
230852Svi117747 	return (0);
231852Svi117747 }
232852Svi117747 
2330Sstevel@tonic-gate sctp_t *
2340Sstevel@tonic-gate sctp_conn_match(in6_addr_t *faddr, in6_addr_t *laddr, uint32_t ports,
235*11042SErik.Nordmark@Sun.COM     zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	sctp_tf_t		*tf;
2380Sstevel@tonic-gate 	sctp_t			*sctp;
2390Sstevel@tonic-gate 	sctp_faddr_t		*fp;
240*11042SErik.Nordmark@Sun.COM 	conn_t			*connp;
2410Sstevel@tonic-gate 
2423448Sdh155122 	tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]);
2430Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) {
246*11042SErik.Nordmark@Sun.COM 		connp = sctp->sctp_connp;
247*11042SErik.Nordmark@Sun.COM 		if (ports != connp->conn_ports)
2480Sstevel@tonic-gate 			continue;
249*11042SErik.Nordmark@Sun.COM 		if (!(connp->conn_zoneid == zoneid ||
250*11042SErik.Nordmark@Sun.COM 		    connp->conn_allzones ||
251*11042SErik.Nordmark@Sun.COM 		    ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
252*11042SErik.Nordmark@Sun.COM 		    (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
253*11042SErik.Nordmark@Sun.COM 		    (iraflags & IRAF_TX_SHARED_ADDR))))
254*11042SErik.Nordmark@Sun.COM 			continue;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		/* check for faddr match */
2570Sstevel@tonic-gate 		for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
2580Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) {
2590Sstevel@tonic-gate 				break;
2600Sstevel@tonic-gate 			}
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 
2633510Svi117747 		/* no faddr match; keep looking */
2643510Svi117747 		if (fp == NULL)
2650Sstevel@tonic-gate 			continue;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		/* check for laddr match */
2683510Svi117747 		if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) {
2693510Svi117747 			SCTP_REFHOLD(sctp);
2703510Svi117747 			goto done;
2713510Svi117747 		}
2720Sstevel@tonic-gate 		/* no match; continue to the next in the chain */
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate done:
2760Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
2770Sstevel@tonic-gate 	return (sctp);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate static sctp_t *
2813510Svi117747 listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid,
282*11042SErik.Nordmark@Sun.COM     iaflags_t iraflags, sctp_stack_t *sctps)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	sctp_t			*sctp;
2850Sstevel@tonic-gate 	sctp_tf_t		*tf;
2860Sstevel@tonic-gate 	uint16_t		lport;
287*11042SErik.Nordmark@Sun.COM 	conn_t			*connp;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	lport = ((uint16_t *)&ports)[1];
2900Sstevel@tonic-gate 
2913448Sdh155122 	tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]);
2920Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) {
295*11042SErik.Nordmark@Sun.COM 		connp = sctp->sctp_connp;
296*11042SErik.Nordmark@Sun.COM 		if (lport != connp->conn_lport)
2970Sstevel@tonic-gate 			continue;
298*11042SErik.Nordmark@Sun.COM 
299*11042SErik.Nordmark@Sun.COM 		if (!(connp->conn_zoneid == zoneid ||
300*11042SErik.Nordmark@Sun.COM 		    connp->conn_allzones ||
301*11042SErik.Nordmark@Sun.COM 		    ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
302*11042SErik.Nordmark@Sun.COM 		    (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
303*11042SErik.Nordmark@Sun.COM 		    (iraflags & IRAF_TX_SHARED_ADDR))))
304*11042SErik.Nordmark@Sun.COM 			continue;
3050Sstevel@tonic-gate 
3063510Svi117747 		if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) {
3073510Svi117747 			SCTP_REFHOLD(sctp);
3083510Svi117747 			goto done;
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 		/* no match; continue to the next in the chain */
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate done:
3140Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
3150Sstevel@tonic-gate 	return (sctp);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3181676Sjpk /* called by ipsec_sctp_pol */
3190Sstevel@tonic-gate conn_t *
3200Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
321*11042SErik.Nordmark@Sun.COM     zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	sctp_t *sctp;
3240Sstevel@tonic-gate 
325*11042SErik.Nordmark@Sun.COM 	sctp = sctp_conn_match(src, dst, ports, zoneid, iraflags, sctps);
326*11042SErik.Nordmark@Sun.COM 	if (sctp == NULL) {
3270Sstevel@tonic-gate 		/* Not in conn fanout; check listen fanout */
328*11042SErik.Nordmark@Sun.COM 		sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
329*11042SErik.Nordmark@Sun.COM 		if (sctp == NULL)
3300Sstevel@tonic-gate 			return (NULL);
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 	return (sctp->sctp_connp);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate 
335*11042SErik.Nordmark@Sun.COM /*
336*11042SErik.Nordmark@Sun.COM  * Fanout to a sctp instance.
337*11042SErik.Nordmark@Sun.COM  */
3381676Sjpk conn_t *
3391676Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
340*11042SErik.Nordmark@Sun.COM     ip_recv_attr_t *ira, mblk_t *mp, sctp_stack_t *sctps)
3411676Sjpk {
342*11042SErik.Nordmark@Sun.COM 	zoneid_t zoneid = ira->ira_zoneid;
343*11042SErik.Nordmark@Sun.COM 	iaflags_t iraflags = ira->ira_flags;
3441676Sjpk 	sctp_t *sctp;
3451676Sjpk 
346*11042SErik.Nordmark@Sun.COM 	sctp = sctp_conn_match(src, dst, ports, zoneid, iraflags, sctps);
347*11042SErik.Nordmark@Sun.COM 	if (sctp == NULL) {
3481676Sjpk 		/* Not in conn fanout; check listen fanout */
349*11042SErik.Nordmark@Sun.COM 		sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
350*11042SErik.Nordmark@Sun.COM 		if (sctp == NULL)
3511676Sjpk 			return (NULL);
3522776Skp158701 		/*
3532776Skp158701 		 * On systems running trusted extensions, check if dst
3542776Skp158701 		 * should accept the packet. "IPV6_VERSION" indicates
3552776Skp158701 		 * that dst is in 16 byte AF_INET6 format. IPv4-mapped
3562776Skp158701 		 * IPv6 addresses are supported.
3572776Skp158701 		 */
358*11042SErik.Nordmark@Sun.COM 		if ((iraflags & IRAF_SYSTEM_LABELED) &&
359*11042SErik.Nordmark@Sun.COM 		    !tsol_receive_local(mp, dst, IPV6_VERSION, ira,
360*11042SErik.Nordmark@Sun.COM 		    sctp->sctp_connp)) {
3612776Skp158701 			DTRACE_PROBE3(
3622776Skp158701 			    tx__ip__log__info__classify__sctp,
3632776Skp158701 			    char *,
3642776Skp158701 			    "connp(1) could not receive mp(2)",
3652776Skp158701 			    conn_t *, sctp->sctp_connp, mblk_t *, mp);
3662776Skp158701 			SCTP_REFRELE(sctp);
3672776Skp158701 			return (NULL);
3682776Skp158701 		}
3691676Sjpk 	}
370*11042SErik.Nordmark@Sun.COM 	/*
371*11042SErik.Nordmark@Sun.COM 	 * For labeled systems, there's no need to check the
372*11042SErik.Nordmark@Sun.COM 	 * label here.  It's known to be good as we checked
373*11042SErik.Nordmark@Sun.COM 	 * before allowing the connection to become bound.
374*11042SErik.Nordmark@Sun.COM 	 */
3751676Sjpk 	return (sctp->sctp_connp);
3761676Sjpk }
3771676Sjpk 
3780Sstevel@tonic-gate /*
379*11042SErik.Nordmark@Sun.COM  * Fanout for ICMP errors for SCTP
3800Sstevel@tonic-gate  * The caller puts <fport, lport> in the ports parameter.
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate void
383*11042SErik.Nordmark@Sun.COM ip_fanout_sctp(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, uint32_t ports,
384*11042SErik.Nordmark@Sun.COM     ip_recv_attr_t *ira)
3850Sstevel@tonic-gate {
386*11042SErik.Nordmark@Sun.COM 	sctp_t		*sctp;
387*11042SErik.Nordmark@Sun.COM 	conn_t		*connp;
388*11042SErik.Nordmark@Sun.COM 	in6_addr_t	map_src, map_dst;
389*11042SErik.Nordmark@Sun.COM 	in6_addr_t	*src, *dst;
390*11042SErik.Nordmark@Sun.COM 	boolean_t	secure;
391*11042SErik.Nordmark@Sun.COM 	ill_t		*ill = ira->ira_ill;
392*11042SErik.Nordmark@Sun.COM 	ip_stack_t	*ipst = ill->ill_ipst;
393*11042SErik.Nordmark@Sun.COM 	netstack_t	*ns = ipst->ips_netstack;
394*11042SErik.Nordmark@Sun.COM 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
395*11042SErik.Nordmark@Sun.COM 	sctp_stack_t	*sctps = ns->netstack_sctp;
396*11042SErik.Nordmark@Sun.COM 	iaflags_t	iraflags = ira->ira_flags;
397*11042SErik.Nordmark@Sun.COM 	ill_t		*rill = ira->ira_rill;
3983448Sdh155122 
399*11042SErik.Nordmark@Sun.COM 	ASSERT(iraflags & IRAF_ICMP_ERROR);
4000Sstevel@tonic-gate 
401*11042SErik.Nordmark@Sun.COM 	secure = iraflags & IRAF_IPSEC_SECURE;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	/* Assume IP provides aligned packets - otherwise toss */
4040Sstevel@tonic-gate 	if (!OK_32PTR(mp->b_rptr)) {
405*11042SErik.Nordmark@Sun.COM 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
406*11042SErik.Nordmark@Sun.COM 		ip_drop_input("ipIfStatsInDiscards", mp, ill);
407*11042SErik.Nordmark@Sun.COM 		freemsg(mp);
4080Sstevel@tonic-gate 		return;
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
411*11042SErik.Nordmark@Sun.COM 	if (!(iraflags & IRAF_IS_IPV4)) {
4120Sstevel@tonic-gate 		src = &ip6h->ip6_src;
4130Sstevel@tonic-gate 		dst = &ip6h->ip6_dst;
4140Sstevel@tonic-gate 	} else {
4150Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src);
4160Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst);
4170Sstevel@tonic-gate 		src = &map_src;
4180Sstevel@tonic-gate 		dst = &map_dst;
4190Sstevel@tonic-gate 	}
420*11042SErik.Nordmark@Sun.COM 	connp = sctp_fanout(src, dst, ports, ira, mp, sctps);
4213448Sdh155122 	if (connp == NULL) {
422*11042SErik.Nordmark@Sun.COM 		ip_fanout_sctp_raw(mp, ipha, ip6h, ports, ira);
4230Sstevel@tonic-gate 		return;
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	sctp = CONN2SCTP(connp);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/*
4280Sstevel@tonic-gate 	 * We check some fields in conn_t without holding a lock.
4290Sstevel@tonic-gate 	 * This should be fine.
4300Sstevel@tonic-gate 	 */
431*11042SErik.Nordmark@Sun.COM 	if (((iraflags & IRAF_IS_IPV4) ?
432*11042SErik.Nordmark@Sun.COM 	    CONN_INBOUND_POLICY_PRESENT(connp, ipss) :
433*11042SErik.Nordmark@Sun.COM 	    CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) ||
434*11042SErik.Nordmark@Sun.COM 	    secure) {
435*11042SErik.Nordmark@Sun.COM 		mp = ipsec_check_inbound_policy(mp, connp, ipha,
436*11042SErik.Nordmark@Sun.COM 		    ip6h, ira);
437*11042SErik.Nordmark@Sun.COM 		if (mp == NULL) {
4380Sstevel@tonic-gate 			SCTP_REFRELE(sctp);
4390Sstevel@tonic-gate 			return;
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
443*11042SErik.Nordmark@Sun.COM 	ira->ira_ill = ira->ira_rill = NULL;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	mutex_enter(&sctp->sctp_lock);
4460Sstevel@tonic-gate 	if (sctp->sctp_running) {
447*11042SErik.Nordmark@Sun.COM 		sctp_add_recvq(sctp, mp, B_FALSE, ira);
4480Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
4490Sstevel@tonic-gate 	} else {
4500Sstevel@tonic-gate 		sctp->sctp_running = B_TRUE;
4510Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_recvq_lock);
4540Sstevel@tonic-gate 		if (sctp->sctp_recvq != NULL) {
455*11042SErik.Nordmark@Sun.COM 			sctp_add_recvq(sctp, mp, B_TRUE, ira);
4560Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_recvq_lock);
4570Sstevel@tonic-gate 			WAKE_SCTP(sctp);
4580Sstevel@tonic-gate 		} else {
4590Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_recvq_lock);
460*11042SErik.Nordmark@Sun.COM 			if (ira->ira_flags & IRAF_ICMP_ERROR) {
461*11042SErik.Nordmark@Sun.COM 				sctp_icmp_error(sctp, mp);
462*11042SErik.Nordmark@Sun.COM 			} else {
463*11042SErik.Nordmark@Sun.COM 				sctp_input_data(sctp, mp, ira);
464*11042SErik.Nordmark@Sun.COM 			}
4650Sstevel@tonic-gate 			WAKE_SCTP(sctp);
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	SCTP_REFRELE(sctp);
469*11042SErik.Nordmark@Sun.COM 	ira->ira_ill = ill;
470*11042SErik.Nordmark@Sun.COM 	ira->ira_rill = rill;
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate void
4740Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate 	sctp_tf_t *tf = sctp->sctp_conn_tfp;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (!tf) {
4790Sstevel@tonic-gate 		return;
4800Sstevel@tonic-gate 	}
481852Svi117747 	/*
482852Svi117747 	 * On a clustered note send this notification to the clustering
483852Svi117747 	 * subsystem.
484852Svi117747 	 */
485852Svi117747 	if (cl_sctp_disconnect != NULL) {
486*11042SErik.Nordmark@Sun.COM 		(*cl_sctp_disconnect)(sctp->sctp_connp->conn_family,
487852Svi117747 		    (cl_sctp_handle_t)sctp);
488852Svi117747 	}
489852Svi117747 
4900Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
4910Sstevel@tonic-gate 	ASSERT(tf->tf_sctp);
4920Sstevel@tonic-gate 	if (tf->tf_sctp == sctp) {
4930Sstevel@tonic-gate 		tf->tf_sctp = sctp->sctp_conn_hash_next;
4940Sstevel@tonic-gate 		if (sctp->sctp_conn_hash_next) {
4950Sstevel@tonic-gate 			ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp);
4960Sstevel@tonic-gate 			tf->tf_sctp->sctp_conn_hash_prev = NULL;
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 	} else {
4990Sstevel@tonic-gate 		ASSERT(sctp->sctp_conn_hash_prev);
5000Sstevel@tonic-gate 		ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp);
5010Sstevel@tonic-gate 		sctp->sctp_conn_hash_prev->sctp_conn_hash_next =
5020Sstevel@tonic-gate 		    sctp->sctp_conn_hash_next;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		if (sctp->sctp_conn_hash_next) {
5050Sstevel@tonic-gate 			ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev
5060Sstevel@tonic-gate 			    == sctp);
5070Sstevel@tonic-gate 			sctp->sctp_conn_hash_next->sctp_conn_hash_prev =
5080Sstevel@tonic-gate 			    sctp->sctp_conn_hash_prev;
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 	sctp->sctp_conn_hash_next = NULL;
5120Sstevel@tonic-gate 	sctp->sctp_conn_hash_prev = NULL;
5130Sstevel@tonic-gate 	sctp->sctp_conn_tfp = NULL;
5140Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate void
5180Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock)
5190Sstevel@tonic-gate {
5200Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp) {
5210Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if (!caller_holds_lock) {
5250Sstevel@tonic-gate 		mutex_enter(&tf->tf_lock);
5260Sstevel@tonic-gate 	} else {
5270Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&tf->tf_lock));
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	sctp->sctp_conn_hash_next = tf->tf_sctp;
5310Sstevel@tonic-gate 	if (tf->tf_sctp) {
5320Sstevel@tonic-gate 		tf->tf_sctp->sctp_conn_hash_prev = sctp;
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 	sctp->sctp_conn_hash_prev = NULL;
5350Sstevel@tonic-gate 	tf->tf_sctp = sctp;
5360Sstevel@tonic-gate 	sctp->sctp_conn_tfp = tf;
5370Sstevel@tonic-gate 	if (!caller_holds_lock) {
5380Sstevel@tonic-gate 		mutex_exit(&tf->tf_lock);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate void
5430Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	sctp_tf_t *tf = sctp->sctp_listen_tfp;
546*11042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (!tf) {
5490Sstevel@tonic-gate 		return;
5500Sstevel@tonic-gate 	}
551852Svi117747 	/*
552852Svi117747 	 * On a clustered note send this notification to the clustering
553852Svi117747 	 * subsystem.
554852Svi117747 	 */
555852Svi117747 	if (cl_sctp_unlisten != NULL) {
556852Svi117747 		uchar_t	*slist;
557852Svi117747 		ssize_t	ssize;
558852Svi117747 
559852Svi117747 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
560852Svi117747 		slist = kmem_alloc(ssize, KM_SLEEP);
561852Svi117747 		sctp_get_saddr_list(sctp, slist, ssize);
562*11042SErik.Nordmark@Sun.COM 		(*cl_sctp_unlisten)(connp->conn_family, slist,
563*11042SErik.Nordmark@Sun.COM 		    sctp->sctp_nsaddrs, connp->conn_lport);
564852Svi117747 		/* list will be freed by the clustering module */
565852Svi117747 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
5680Sstevel@tonic-gate 	ASSERT(tf->tf_sctp);
5690Sstevel@tonic-gate 	if (tf->tf_sctp == sctp) {
5700Sstevel@tonic-gate 		tf->tf_sctp = sctp->sctp_listen_hash_next;
5717480SKacheong.Poon@Sun.COM 		if (sctp->sctp_listen_hash_next != NULL) {
5720Sstevel@tonic-gate 			ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp);
5730Sstevel@tonic-gate 			tf->tf_sctp->sctp_listen_hash_prev = NULL;
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 	} else {
5760Sstevel@tonic-gate 		ASSERT(sctp->sctp_listen_hash_prev);
5770Sstevel@tonic-gate 		ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next ==
5780Sstevel@tonic-gate 		    sctp);
5797480SKacheong.Poon@Sun.COM 		ASSERT(sctp->sctp_listen_hash_next == NULL ||
5807480SKacheong.Poon@Sun.COM 		    sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp);
5817480SKacheong.Poon@Sun.COM 
5820Sstevel@tonic-gate 		sctp->sctp_listen_hash_prev->sctp_listen_hash_next =
5830Sstevel@tonic-gate 		    sctp->sctp_listen_hash_next;
5840Sstevel@tonic-gate 
5857480SKacheong.Poon@Sun.COM 		if (sctp->sctp_listen_hash_next != NULL) {
586*11042SErik.Nordmark@Sun.COM 			sctp_t *next = sctp->sctp_listen_hash_next;
587*11042SErik.Nordmark@Sun.COM 
588*11042SErik.Nordmark@Sun.COM 			ASSERT(next->sctp_listen_hash_prev == sctp);
589*11042SErik.Nordmark@Sun.COM 			next->sctp_listen_hash_prev =
5900Sstevel@tonic-gate 			    sctp->sctp_listen_hash_prev;
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 	sctp->sctp_listen_hash_next = NULL;
5940Sstevel@tonic-gate 	sctp->sctp_listen_hash_prev = NULL;
5950Sstevel@tonic-gate 	sctp->sctp_listen_tfp = NULL;
5960Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate void
6000Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp)
6010Sstevel@tonic-gate {
602*11042SErik.Nordmark@Sun.COM 	conn_t	*connp = sctp->sctp_connp;
603*11042SErik.Nordmark@Sun.COM 
6040Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp) {
6050Sstevel@tonic-gate 		sctp_listen_hash_remove(sctp);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
6090Sstevel@tonic-gate 	sctp->sctp_listen_hash_next = tf->tf_sctp;
6100Sstevel@tonic-gate 	if (tf->tf_sctp) {
6110Sstevel@tonic-gate 		tf->tf_sctp->sctp_listen_hash_prev = sctp;
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 	sctp->sctp_listen_hash_prev = NULL;
6140Sstevel@tonic-gate 	tf->tf_sctp = sctp;
6150Sstevel@tonic-gate 	sctp->sctp_listen_tfp = tf;
6160Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
617852Svi117747 	/*
618852Svi117747 	 * On a clustered note send this notification to the clustering
619852Svi117747 	 * subsystem.
620852Svi117747 	 */
621852Svi117747 	if (cl_sctp_listen != NULL) {
622852Svi117747 		uchar_t	*slist;
623852Svi117747 		ssize_t	ssize;
624852Svi117747 
625852Svi117747 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
626852Svi117747 		slist = kmem_alloc(ssize, KM_SLEEP);
627852Svi117747 		sctp_get_saddr_list(sctp, slist, ssize);
628*11042SErik.Nordmark@Sun.COM 		(*cl_sctp_listen)(connp->conn_family, slist,
629*11042SErik.Nordmark@Sun.COM 		    sctp->sctp_nsaddrs, connp->conn_lport);
630852Svi117747 		/* list will be freed by the clustering module */
631852Svi117747 	}
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate /*
6350Sstevel@tonic-gate  * Hash list insertion routine for sctp_t structures.
6360Sstevel@tonic-gate  * Inserts entries with the ones bound to a specific IP address first
6370Sstevel@tonic-gate  * followed by those bound to INADDR_ANY.
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate void
6400Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	sctp_t	**sctpp;
6430Sstevel@tonic-gate 	sctp_t	*sctpnext;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn != NULL) {
6460Sstevel@tonic-gate 		ASSERT(!caller_holds_lock);
6470Sstevel@tonic-gate 		sctp_bind_hash_remove(sctp);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 	sctpp = &tbf->tf_sctp;
6500Sstevel@tonic-gate 	if (!caller_holds_lock) {
6510Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
6520Sstevel@tonic-gate 	} else {
6530Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&tbf->tf_lock));
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 	sctpnext = sctpp[0];
6560Sstevel@tonic-gate 	if (sctpnext) {
6570Sstevel@tonic-gate 		sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash;
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate 	sctp->sctp_bind_hash = sctpnext;
6600Sstevel@tonic-gate 	sctp->sctp_ptpbhn = sctpp;
6610Sstevel@tonic-gate 	sctpp[0] = sctp;
6620Sstevel@tonic-gate 	/* For sctp_*_hash_remove */
6630Sstevel@tonic-gate 	sctp->sctp_bind_lockp = &tbf->tf_lock;
6640Sstevel@tonic-gate 	if (!caller_holds_lock)
6650Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate  * Hash list removal routine for sctp_t structures.
6700Sstevel@tonic-gate  */
6710Sstevel@tonic-gate void
6720Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp)
6730Sstevel@tonic-gate {
6740Sstevel@tonic-gate 	sctp_t	*sctpnext;
6750Sstevel@tonic-gate 	kmutex_t *lockp;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	lockp = sctp->sctp_bind_lockp;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn == NULL)
6800Sstevel@tonic-gate 		return;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	ASSERT(lockp != NULL);
6830Sstevel@tonic-gate 	mutex_enter(lockp);
6840Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn) {
6850Sstevel@tonic-gate 		sctpnext = sctp->sctp_bind_hash;
6860Sstevel@tonic-gate 		if (sctpnext) {
6870Sstevel@tonic-gate 			sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn;
6880Sstevel@tonic-gate 			sctp->sctp_bind_hash = NULL;
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 		*sctp->sctp_ptpbhn = sctpnext;
6910Sstevel@tonic-gate 		sctp->sctp_ptpbhn = NULL;
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 	mutex_exit(lockp);
6940Sstevel@tonic-gate 	sctp->sctp_bind_lockp = NULL;
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate /*
6987480SKacheong.Poon@Sun.COM  * Similar to but different from sctp_conn_match().
6990Sstevel@tonic-gate  *
7000Sstevel@tonic-gate  * Matches sets of addresses as follows: if the argument addr set is
7010Sstevel@tonic-gate  * a complete subset of the corresponding addr set in the sctp_t, it
7020Sstevel@tonic-gate  * is a match.
7030Sstevel@tonic-gate  *
7040Sstevel@tonic-gate  * Caller must hold tf->tf_lock.
7050Sstevel@tonic-gate  *
7060Sstevel@tonic-gate  * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE.
7070Sstevel@tonic-gate  */
7080Sstevel@tonic-gate sctp_t *
7090Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports,
7100Sstevel@tonic-gate     int min_state)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 	sctp_t *sctp;
7130Sstevel@tonic-gate 	sctp_faddr_t *fp;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&tf->tf_lock));
7160Sstevel@tonic-gate 
7177480SKacheong.Poon@Sun.COM 	for (sctp = tf->tf_sctp; sctp != NULL;
7187480SKacheong.Poon@Sun.COM 	    sctp = sctp->sctp_conn_hash_next) {
719*11042SErik.Nordmark@Sun.COM 		if (*ports != sctp->sctp_connp->conn_ports ||
720*11042SErik.Nordmark@Sun.COM 		    sctp->sctp_state < min_state) {
7210Sstevel@tonic-gate 			continue;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		/* check for faddr match */
7257480SKacheong.Poon@Sun.COM 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
7260Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(faddr, &fp->faddr)) {
7270Sstevel@tonic-gate 				break;
7280Sstevel@tonic-gate 			}
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 
7317480SKacheong.Poon@Sun.COM 		if (fp == NULL) {
7320Sstevel@tonic-gate 			/* no faddr match; keep looking */
7330Sstevel@tonic-gate 			continue;
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 
7367480SKacheong.Poon@Sun.COM 		/*
7377480SKacheong.Poon@Sun.COM 		 * There is an existing association with the same peer
7387480SKacheong.Poon@Sun.COM 		 * address.  So now we need to check if our local address
7397480SKacheong.Poon@Sun.COM 		 * set overlaps with the one of the existing association.
7407480SKacheong.Poon@Sun.COM 		 * If they overlap, we should return it.
7417480SKacheong.Poon@Sun.COM 		 */
7427480SKacheong.Poon@Sun.COM 		if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) {
7430Sstevel@tonic-gate 			goto done;
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		/* no match; continue searching */
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate done:
7507480SKacheong.Poon@Sun.COM 	if (sctp != NULL) {
7510Sstevel@tonic-gate 		SCTP_REFHOLD(sctp);
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 	return (sctp);
7540Sstevel@tonic-gate }
755