17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
236be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
277c478bd9Sstevel@tonic-gate #include <sys/socket.h>
287c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
3045916cd2Sjpk #include <sys/tsol/tndb.h>
3145916cd2Sjpk #include <sys/tsol/tnet.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <netinet/in.h>
347c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <inet/common.h>
377c478bd9Sstevel@tonic-gate #include <inet/ip.h>
387c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
397c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
407c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
417c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h>
427c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
457c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* Default association hash size.  The size must be a power of 2. */
487c478bd9Sstevel@tonic-gate #define	SCTP_CONN_HASH_SIZE	8192
497c478bd9Sstevel@tonic-gate 
50f4b3ec61Sdh uint_t		sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; /* /etc/system */
517c478bd9Sstevel@tonic-gate 
521d8c4025Svi /*
531d8c4025Svi  * Cluster networking hook for traversing current assoc list.
541d8c4025Svi  * This routine is used to extract the current list of live associations
551d8c4025Svi  * which must continue to to be dispatched to this node.
561d8c4025Svi  */
571d8c4025Svi int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *,
581d8c4025Svi     boolean_t);
59f4b3ec61Sdh static int cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *,
60f4b3ec61Sdh     void *), void *arg, boolean_t cansleep, sctp_stack_t *sctps);
611d8c4025Svi 
627c478bd9Sstevel@tonic-gate void
sctp_hash_init(sctp_stack_t * sctps)63f4b3ec61Sdh sctp_hash_init(sctp_stack_t *sctps)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	int i;
667c478bd9Sstevel@tonic-gate 
67f4b3ec61Sdh 	/* Start with /etc/system value */
68f4b3ec61Sdh 	sctps->sctps_conn_hash_size = sctp_conn_hash_size;
69f4b3ec61Sdh 
70*de710d24SJosef 'Jeff' Sipek 	if (!ISP2(sctps->sctps_conn_hash_size)) {
717c478bd9Sstevel@tonic-gate 		/* Not a power of two. Round up to nearest power of two */
727c478bd9Sstevel@tonic-gate 		for (i = 0; i < 31; i++) {
73f4b3ec61Sdh 			if (sctps->sctps_conn_hash_size < (1 << i))
747c478bd9Sstevel@tonic-gate 				break;
757c478bd9Sstevel@tonic-gate 		}
76f4b3ec61Sdh 		sctps->sctps_conn_hash_size = 1 << i;
777c478bd9Sstevel@tonic-gate 	}
78f4b3ec61Sdh 	if (sctps->sctps_conn_hash_size < SCTP_CONN_HASH_SIZE) {
79f4b3ec61Sdh 		sctps->sctps_conn_hash_size = SCTP_CONN_HASH_SIZE;
807c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n",
81f4b3ec61Sdh 		    sctps->sctps_conn_hash_size);
827c478bd9Sstevel@tonic-gate 	}
83f4b3ec61Sdh 	sctps->sctps_conn_fanout =
84e6f13f86SKacheong Poon 	    (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size *
85bd670b35SErik Nordmark 	    sizeof (sctp_tf_t), KM_SLEEP);
86f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_conn_hash_size; i++) {
87f4b3ec61Sdh 		mutex_init(&sctps->sctps_conn_fanout[i].tf_lock, NULL,
88e6f13f86SKacheong Poon 		    MUTEX_DEFAULT, NULL);
897c478bd9Sstevel@tonic-gate 	}
90f4b3ec61Sdh 	sctps->sctps_listen_fanout = kmem_zalloc(SCTP_LISTEN_FANOUT_SIZE *
91f4b3ec61Sdh 	    sizeof (sctp_tf_t),	KM_SLEEP);
92f4b3ec61Sdh 	for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) {
93f4b3ec61Sdh 		mutex_init(&sctps->sctps_listen_fanout[i].tf_lock, NULL,
947c478bd9Sstevel@tonic-gate 		    MUTEX_DEFAULT, NULL);
957c478bd9Sstevel@tonic-gate 	}
96f4b3ec61Sdh 	sctps->sctps_bind_fanout = kmem_zalloc(SCTP_BIND_FANOUT_SIZE *
97f4b3ec61Sdh 	    sizeof (sctp_tf_t),	KM_SLEEP);
98f4b3ec61Sdh 	for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) {
99f4b3ec61Sdh 		mutex_init(&sctps->sctps_bind_fanout[i].tf_lock, NULL,
1007c478bd9Sstevel@tonic-gate 		    MUTEX_DEFAULT, NULL);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate void
sctp_hash_destroy(sctp_stack_t * sctps)105f4b3ec61Sdh sctp_hash_destroy(sctp_stack_t *sctps)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	int i;
1087c478bd9Sstevel@tonic-gate 
109f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_conn_hash_size; i++) {
110f4b3ec61Sdh 		mutex_destroy(&sctps->sctps_conn_fanout[i].tf_lock);
1117c478bd9Sstevel@tonic-gate 	}
112f4b3ec61Sdh 	kmem_free(sctps->sctps_conn_fanout, sctps->sctps_conn_hash_size *
113f4b3ec61Sdh 	    sizeof (sctp_tf_t));
114f4b3ec61Sdh 	sctps->sctps_conn_fanout = NULL;
115f4b3ec61Sdh 
116f4b3ec61Sdh 	for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) {
117f4b3ec61Sdh 		mutex_destroy(&sctps->sctps_listen_fanout[i].tf_lock);
1187c478bd9Sstevel@tonic-gate 	}
119f4b3ec61Sdh 	kmem_free(sctps->sctps_listen_fanout, SCTP_LISTEN_FANOUT_SIZE *
120f4b3ec61Sdh 	    sizeof (sctp_tf_t));
121f4b3ec61Sdh 	sctps->sctps_listen_fanout = NULL;
122f4b3ec61Sdh 
123f4b3ec61Sdh 	for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) {
124f4b3ec61Sdh 		mutex_destroy(&sctps->sctps_bind_fanout[i].tf_lock);
1257c478bd9Sstevel@tonic-gate 	}
126f4b3ec61Sdh 	kmem_free(sctps->sctps_bind_fanout, SCTP_BIND_FANOUT_SIZE *
127f4b3ec61Sdh 	    sizeof (sctp_tf_t));
128f4b3ec61Sdh 	sctps->sctps_bind_fanout = NULL;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1311d8c4025Svi /*
1321d8c4025Svi  * Exported routine for extracting active SCTP associations.
1331d8c4025Svi  * Like TCP, we terminate the walk if the callback returns non-zero.
134f4b3ec61Sdh  *
135f4b3ec61Sdh  * Need to walk all sctp_stack_t instances since this clustering
136f4b3ec61Sdh  * interface is assumed global for all instances
1371d8c4025Svi  */
1381d8c4025Svi int
cl_sctp_walk_list(int (* cl_callback)(cl_sctp_info_t *,void *),void * arg,boolean_t cansleep)139f4b3ec61Sdh cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *),
140f4b3ec61Sdh     void *arg, boolean_t cansleep)
141f4b3ec61Sdh {
142f4b3ec61Sdh 	netstack_handle_t nh;
143f4b3ec61Sdh 	netstack_t *ns;
144f4b3ec61Sdh 	int ret = 0;
145f4b3ec61Sdh 
146f4b3ec61Sdh 	netstack_next_init(&nh);
147f4b3ec61Sdh 	while ((ns = netstack_next(&nh)) != NULL) {
148f4b3ec61Sdh 		ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep,
149f4b3ec61Sdh 		    ns->netstack_sctp);
150f4b3ec61Sdh 		netstack_rele(ns);
151f4b3ec61Sdh 	}
152f4b3ec61Sdh 	netstack_next_fini(&nh);
153f4b3ec61Sdh 	return (ret);
154f4b3ec61Sdh }
155f4b3ec61Sdh 
156f4b3ec61Sdh static int
cl_sctp_walk_list_stack(int (* cl_callback)(cl_sctp_info_t *,void *),void * arg,boolean_t cansleep,sctp_stack_t * sctps)157f4b3ec61Sdh cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *),
158f4b3ec61Sdh     void *arg, boolean_t cansleep, sctp_stack_t *sctps)
1591d8c4025Svi {
1601d8c4025Svi 	sctp_t		*sctp;
1611d8c4025Svi 	sctp_t		*sctp_prev;
1621d8c4025Svi 	cl_sctp_info_t	cl_sctpi;
1631d8c4025Svi 	uchar_t		*slist;
1641d8c4025Svi 	uchar_t		*flist;
1651d8c4025Svi 
1661d8c4025Svi 	sctp_prev = NULL;
167f4b3ec61Sdh 	mutex_enter(&sctps->sctps_g_lock);
168bd670b35SErik Nordmark 	sctp = list_head(&sctps->sctps_g_list);
1691d8c4025Svi 	while (sctp != NULL) {
1701d8c4025Svi 		size_t	ssize;
1711d8c4025Svi 		size_t	fsize;
1721d8c4025Svi 
1731d8c4025Svi 		mutex_enter(&sctp->sctp_reflock);
1741d8c4025Svi 		if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) {
1751d8c4025Svi 			mutex_exit(&sctp->sctp_reflock);
176f4b3ec61Sdh 			sctp = list_next(&sctps->sctps_g_list, sctp);
1771d8c4025Svi 			continue;
1781d8c4025Svi 		}
1791d8c4025Svi 		sctp->sctp_refcnt++;
1801d8c4025Svi 		mutex_exit(&sctp->sctp_reflock);
181f4b3ec61Sdh 		mutex_exit(&sctps->sctps_g_lock);
1821d8c4025Svi 		if (sctp_prev != NULL)
1831d8c4025Svi 			SCTP_REFRELE(sctp_prev);
1841d8c4025Svi 		RUN_SCTP(sctp);
1851d8c4025Svi 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
1861d8c4025Svi 		fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
1871d8c4025Svi 
1881d8c4025Svi 		slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP);
1891d8c4025Svi 		flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP);
1901d8c4025Svi 		if (slist == NULL || flist == NULL) {
1911d8c4025Svi 			WAKE_SCTP(sctp);
1921d8c4025Svi 			if (slist != NULL)
1931d8c4025Svi 				kmem_free(slist, ssize);
1941d8c4025Svi 			if (flist != NULL)
1951d8c4025Svi 				kmem_free(flist, fsize);
1961d8c4025Svi 			SCTP_REFRELE(sctp);
1971d8c4025Svi 			return (1);
1981d8c4025Svi 		}
1991d8c4025Svi 		cl_sctpi.cl_sctpi_version = CL_SCTPI_V1;
2001d8c4025Svi 		sctp_get_saddr_list(sctp, slist, ssize);
2011d8c4025Svi 		sctp_get_faddr_list(sctp, flist, fsize);
2021d8c4025Svi 		cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs;
2031d8c4025Svi 		cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs;
204bd670b35SErik Nordmark 		cl_sctpi.cl_sctpi_family = sctp->sctp_connp->conn_family;
205bd670b35SErik Nordmark 		if (cl_sctpi.cl_sctpi_family == AF_INET)
206bd670b35SErik Nordmark 			cl_sctpi.cl_sctpi_ipversion = IPV4_VERSION;
207bd670b35SErik Nordmark 		else
208bd670b35SErik Nordmark 			cl_sctpi.cl_sctpi_ipversion = IPV6_VERSION;
2091d8c4025Svi 		cl_sctpi.cl_sctpi_state = sctp->sctp_state;
210bd670b35SErik Nordmark 		cl_sctpi.cl_sctpi_lport = sctp->sctp_connp->conn_lport;
211bd670b35SErik Nordmark 		cl_sctpi.cl_sctpi_fport = sctp->sctp_connp->conn_fport;
2121d8c4025Svi 		cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp;
2131d8c4025Svi 		WAKE_SCTP(sctp);
2141d8c4025Svi 		cl_sctpi.cl_sctpi_laddrp = slist;
2151d8c4025Svi 		cl_sctpi.cl_sctpi_faddrp = flist;
2161d8c4025Svi 		if ((*cl_callback)(&cl_sctpi, arg) != 0) {
2171d8c4025Svi 			kmem_free(slist, ssize);
2181d8c4025Svi 			kmem_free(flist, fsize);
2191d8c4025Svi 			SCTP_REFRELE(sctp);
2201d8c4025Svi 			return (1);
2211d8c4025Svi 		}
2221d8c4025Svi 		/* list will be freed by cl_callback */
2231d8c4025Svi 		sctp_prev = sctp;
224f4b3ec61Sdh 		mutex_enter(&sctps->sctps_g_lock);
225f4b3ec61Sdh 		sctp = list_next(&sctps->sctps_g_list, sctp);
2261d8c4025Svi 	}
227f4b3ec61Sdh 	mutex_exit(&sctps->sctps_g_lock);
2281d8c4025Svi 	if (sctp_prev != NULL)
2291d8c4025Svi 		SCTP_REFRELE(sctp_prev);
2301d8c4025Svi 	return (0);
2311d8c4025Svi }
2321d8c4025Svi 
2337c478bd9Sstevel@tonic-gate sctp_t *
sctp_conn_match(in6_addr_t ** faddrpp,uint32_t nfaddr,in6_addr_t * laddr,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)234a5407c02SAnil udupa sctp_conn_match(in6_addr_t **faddrpp, uint32_t nfaddr, in6_addr_t *laddr,
235a5407c02SAnil udupa     uint32_t ports, zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	sctp_tf_t		*tf;
2387c478bd9Sstevel@tonic-gate 	sctp_t			*sctp;
2397c478bd9Sstevel@tonic-gate 	sctp_faddr_t		*fp;
240bd670b35SErik Nordmark 	conn_t			*connp;
241a5407c02SAnil udupa 	in6_addr_t		**faddrs, **endaddrs = &faddrpp[nfaddr];
2427c478bd9Sstevel@tonic-gate 
243f4b3ec61Sdh 	tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]);
2447c478bd9Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
2457c478bd9Sstevel@tonic-gate 
246a5407c02SAnil udupa 	for (sctp = tf->tf_sctp; sctp != NULL; sctp =
247a5407c02SAnil udupa 	    sctp->sctp_conn_hash_next) {
248bd670b35SErik Nordmark 		connp = sctp->sctp_connp;
249bd670b35SErik Nordmark 		if (ports != connp->conn_ports)
250bd670b35SErik Nordmark 			continue;
251bd670b35SErik Nordmark 		if (!(connp->conn_zoneid == zoneid ||
252bd670b35SErik Nordmark 		    connp->conn_allzones ||
253bd670b35SErik Nordmark 		    ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
254bd670b35SErik Nordmark 		    (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
255bd670b35SErik Nordmark 		    (iraflags & IRAF_TX_SHARED_ADDR))))
2567c478bd9Sstevel@tonic-gate 			continue;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		/* check for faddr match */
2596be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
260a5407c02SAnil udupa 			for (faddrs = faddrpp; faddrs < endaddrs; faddrs++) {
2616be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				if (IN6_ARE_ADDR_EQUAL(*faddrs,
2626be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				    &fp->sf_faddr)) {
263a5407c02SAnil udupa 					/* check for laddr match */
264a5407c02SAnil udupa 					if (sctp_saddr_lookup(sctp, laddr, 0)
265a5407c02SAnil udupa 					    != NULL) {
266a5407c02SAnil udupa 						SCTP_REFHOLD(sctp);
267a5407c02SAnil udupa 						mutex_exit(&tf->tf_lock);
268a5407c02SAnil udupa 						return (sctp);
269a5407c02SAnil udupa 					}
270a5407c02SAnil udupa 				}
2717c478bd9Sstevel@tonic-gate 			}
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 
274e35d2278Svi 		/* no match; continue to the next in the chain */
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
2787c478bd9Sstevel@tonic-gate 	return (sctp);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate static sctp_t *
listen_match(in6_addr_t * laddr,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)282e35d2278Svi listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid,
283bd670b35SErik Nordmark     iaflags_t iraflags, sctp_stack_t *sctps)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	sctp_t			*sctp;
2867c478bd9Sstevel@tonic-gate 	sctp_tf_t		*tf;
2877c478bd9Sstevel@tonic-gate 	uint16_t		lport;
288bd670b35SErik Nordmark 	conn_t			*connp;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	lport = ((uint16_t *)&ports)[1];
2917c478bd9Sstevel@tonic-gate 
292f4b3ec61Sdh 	tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]);
2937c478bd9Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) {
296bd670b35SErik Nordmark 		connp = sctp->sctp_connp;
297bd670b35SErik Nordmark 		if (lport != connp->conn_lport)
298bd670b35SErik Nordmark 			continue;
299bd670b35SErik Nordmark 
300bd670b35SErik Nordmark 		if (!(connp->conn_zoneid == zoneid ||
301bd670b35SErik Nordmark 		    connp->conn_allzones ||
302bd670b35SErik Nordmark 		    ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
303bd670b35SErik Nordmark 		    (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
304bd670b35SErik Nordmark 		    (iraflags & IRAF_TX_SHARED_ADDR))))
3057c478bd9Sstevel@tonic-gate 			continue;
3067c478bd9Sstevel@tonic-gate 
307e35d2278Svi 		if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) {
308e35d2278Svi 			SCTP_REFHOLD(sctp);
309e35d2278Svi 			goto done;
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 		/* no match; continue to the next in the chain */
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate done:
3157c478bd9Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
3167c478bd9Sstevel@tonic-gate 	return (sctp);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
31945916cd2Sjpk /* called by ipsec_sctp_pol */
3207c478bd9Sstevel@tonic-gate conn_t *
sctp_find_conn(in6_addr_t * src,in6_addr_t * dst,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)3217c478bd9Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
322bd670b35SErik Nordmark     zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	sctp_t *sctp;
3257c478bd9Sstevel@tonic-gate 
326a5407c02SAnil udupa 	sctp = sctp_conn_match(&src, 1, dst, ports, zoneid, iraflags, sctps);
327bd670b35SErik Nordmark 	if (sctp == NULL) {
3287c478bd9Sstevel@tonic-gate 		/* Not in conn fanout; check listen fanout */
329bd670b35SErik Nordmark 		sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
330bd670b35SErik Nordmark 		if (sctp == NULL)
3317c478bd9Sstevel@tonic-gate 			return (NULL);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 	return (sctp->sctp_connp);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
336a5407c02SAnil udupa /*
337a5407c02SAnil udupa  * This is called from sctp_fanout() with IP header src & dst addresses.
338a5407c02SAnil udupa  * First call sctp_conn_match() to get a match by passing in src & dst
339a5407c02SAnil udupa  * addresses from IP header.
340a5407c02SAnil udupa  * However sctp_conn_match() can return no match under condition such as :
341a5407c02SAnil udupa  * A host can send an INIT ACK from a different address than the INIT was sent
342a5407c02SAnil udupa  * to (in a multi-homed env).
343a5407c02SAnil udupa  * According to RFC4960, a host can send additional addresses in an INIT
344a5407c02SAnil udupa  * ACK chunk.
345a5407c02SAnil udupa  * Therefore extract all addresses from the INIT ACK chunk, pass to
346a5407c02SAnil udupa  * sctp_conn_match() to get a match.
347a5407c02SAnil udupa  */
348a5407c02SAnil udupa static sctp_t *
sctp_lookup_by_faddrs(mblk_t * mp,sctp_hdr_t * sctph,in6_addr_t * srcp,in6_addr_t * dstp,uint32_t ports,zoneid_t zoneid,sctp_stack_t * sctps,iaflags_t iraflags)349a5407c02SAnil udupa sctp_lookup_by_faddrs(mblk_t *mp, sctp_hdr_t *sctph, in6_addr_t *srcp,
350a5407c02SAnil udupa     in6_addr_t *dstp, uint32_t ports, zoneid_t zoneid, sctp_stack_t *sctps,
351a5407c02SAnil udupa     iaflags_t iraflags)
352a5407c02SAnil udupa {
353a5407c02SAnil udupa 	sctp_t			*sctp;
354a5407c02SAnil udupa 	sctp_chunk_hdr_t	*ich;
355a5407c02SAnil udupa 	sctp_init_chunk_t	*iack;
356a5407c02SAnil udupa 	sctp_parm_hdr_t		*ph;
357a5407c02SAnil udupa 	ssize_t			mlen, remaining;
358a5407c02SAnil udupa 	uint16_t		param_type, addr_len = PARM_ADDR4_LEN;
359a5407c02SAnil udupa 	in6_addr_t		src;
360a5407c02SAnil udupa 	in6_addr_t		**addrbuf = NULL, **faddrpp = NULL;
361a5407c02SAnil udupa 	boolean_t		isv4;
362a5407c02SAnil udupa 	uint32_t		totaddr, nfaddr = 0;
363a5407c02SAnil udupa 
364a5407c02SAnil udupa 	/*
365a5407c02SAnil udupa 	 * If we get a match with the passed-in IP header src & dst addresses,
366a5407c02SAnil udupa 	 * quickly return the matched sctp.
367a5407c02SAnil udupa 	 */
368a5407c02SAnil udupa 	if ((sctp = sctp_conn_match(&srcp, 1, dstp, ports, zoneid, iraflags,
369a5407c02SAnil udupa 	    sctps)) != NULL) {
370a5407c02SAnil udupa 		return (sctp);
371a5407c02SAnil udupa 	}
372a5407c02SAnil udupa 
373a5407c02SAnil udupa 	/*
374a5407c02SAnil udupa 	 * Currently sctph is set to NULL in icmp error fanout case
375a5407c02SAnil udupa 	 * (ip_fanout_sctp()).
376a5407c02SAnil udupa 	 * The above sctp_conn_match() should handle that, otherwise
377a5407c02SAnil udupa 	 * return no match found.
378a5407c02SAnil udupa 	 */
379a5407c02SAnil udupa 	if (sctph == NULL)
380a5407c02SAnil udupa 		return (NULL);
381a5407c02SAnil udupa 
382a5407c02SAnil udupa 	/*
383a5407c02SAnil udupa 	 * Do a pullup again in case the previous one was partially successful,
384a5407c02SAnil udupa 	 * so try to complete the pullup here and have a single contiguous
385a5407c02SAnil udupa 	 * chunk for processing of entire INIT ACK chunk below.
386a5407c02SAnil udupa 	 */
387a5407c02SAnil udupa 	if (mp->b_cont != NULL) {
388a5407c02SAnil udupa 		if (pullupmsg(mp, -1) == 0) {
389a5407c02SAnil udupa 			return (NULL);
390a5407c02SAnil udupa 		}
391a5407c02SAnil udupa 	}
392a5407c02SAnil udupa 
393a5407c02SAnil udupa 	mlen = mp->b_wptr - (uchar_t *)(sctph + 1);
394a5407c02SAnil udupa 	if ((ich = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) {
395a5407c02SAnil udupa 		return (NULL);
396a5407c02SAnil udupa 	}
397a5407c02SAnil udupa 
398a5407c02SAnil udupa 	if (ich->sch_id == CHUNK_INIT_ACK) {
399a5407c02SAnil udupa 		remaining = ntohs(ich->sch_len) - sizeof (*ich) -
400a5407c02SAnil udupa 		    sizeof (*iack);
401a5407c02SAnil udupa 		if (remaining < sizeof (*ph)) {
402a5407c02SAnil udupa 			return (NULL);
403a5407c02SAnil udupa 		}
404a5407c02SAnil udupa 
405a5407c02SAnil udupa 		isv4 = (iraflags & IRAF_IS_IPV4) ? B_TRUE : B_FALSE;
406a5407c02SAnil udupa 		if (!isv4)
407a5407c02SAnil udupa 			addr_len = PARM_ADDR6_LEN;
408a5407c02SAnil udupa 		totaddr = remaining/addr_len;
409a5407c02SAnil udupa 
410a5407c02SAnil udupa 		iack = (sctp_init_chunk_t *)(ich + 1);
411a5407c02SAnil udupa 		ph = (sctp_parm_hdr_t *)(iack + 1);
412a5407c02SAnil udupa 
413a5407c02SAnil udupa 		addrbuf = (in6_addr_t **)
414a5407c02SAnil udupa 		    kmem_zalloc(totaddr * sizeof (in6_addr_t *), KM_NOSLEEP);
415a5407c02SAnil udupa 		if (addrbuf == NULL)
416a5407c02SAnil udupa 			return (NULL);
417a5407c02SAnil udupa 		faddrpp = addrbuf;
418a5407c02SAnil udupa 
419a5407c02SAnil udupa 		while (ph != NULL) {
420a5407c02SAnil udupa 			/*
421a5407c02SAnil udupa 			 * According to RFC4960 :
422a5407c02SAnil udupa 			 * All integer fields in an SCTP packet MUST be
423a5407c02SAnil udupa 			 * transmitted in network byte order,
424a5407c02SAnil udupa 			 * unless otherwise stated.
425a5407c02SAnil udupa 			 * Therefore convert the param type to host byte order.
426a5407c02SAnil udupa 			 * Also do not add src address present in IP header
427a5407c02SAnil udupa 			 * as it has already been thru sctp_conn_match() above.
428a5407c02SAnil udupa 			 */
429a5407c02SAnil udupa 			param_type = ntohs(ph->sph_type);
430a5407c02SAnil udupa 			switch (param_type) {
431a5407c02SAnil udupa 			case PARM_ADDR4:
432a5407c02SAnil udupa 				IN6_INADDR_TO_V4MAPPED((struct in_addr *)
433a5407c02SAnil udupa 				    (ph + 1), &src);
434a5407c02SAnil udupa 				if (IN6_ARE_ADDR_EQUAL(&src, srcp))
435a5407c02SAnil udupa 					break;
436a5407c02SAnil udupa 				*faddrpp = (in6_addr_t *)
437a5407c02SAnil udupa 				    kmem_zalloc(sizeof (in6_addr_t),
438a5407c02SAnil udupa 				    KM_NOSLEEP);
439a5407c02SAnil udupa 				if (*faddrpp == NULL)
440a5407c02SAnil udupa 					break;
441a5407c02SAnil udupa 				IN6_INADDR_TO_V4MAPPED((struct in_addr *)
442a5407c02SAnil udupa 				    (ph + 1), *faddrpp);
443a5407c02SAnil udupa 				nfaddr++;
444a5407c02SAnil udupa 				faddrpp++;
445a5407c02SAnil udupa 				break;
446a5407c02SAnil udupa 			case PARM_ADDR6:
447a5407c02SAnil udupa 				*faddrpp = (in6_addr_t *)(ph + 1);
448a5407c02SAnil udupa 				if (IN6_ARE_ADDR_EQUAL(*faddrpp, srcp))
449a5407c02SAnil udupa 					break;
450a5407c02SAnil udupa 				nfaddr++;
451a5407c02SAnil udupa 				faddrpp++;
452a5407c02SAnil udupa 				break;
453a5407c02SAnil udupa 			default:
454a5407c02SAnil udupa 				break;
455a5407c02SAnil udupa 			}
456a5407c02SAnil udupa 			ph = sctp_next_parm(ph, &remaining);
457a5407c02SAnil udupa 		}
458a5407c02SAnil udupa 
459a5407c02SAnil udupa 		ASSERT(nfaddr < totaddr);
460a5407c02SAnil udupa 
461a5407c02SAnil udupa 		if (nfaddr > 0) {
462a5407c02SAnil udupa 			sctp = sctp_conn_match(addrbuf, nfaddr, dstp, ports,
463a5407c02SAnil udupa 			    zoneid, iraflags, sctps);
464a5407c02SAnil udupa 
465a5407c02SAnil udupa 			if (isv4) {
466a5407c02SAnil udupa 				for (faddrpp = addrbuf; nfaddr > 0;
467a5407c02SAnil udupa 				    faddrpp++, nfaddr--) {
468a5407c02SAnil udupa 					if (IN6_IS_ADDR_V4MAPPED(*faddrpp)) {
469a5407c02SAnil udupa 						kmem_free(*faddrpp,
470a5407c02SAnil udupa 						    sizeof (in6_addr_t));
471a5407c02SAnil udupa 					}
472a5407c02SAnil udupa 				}
473a5407c02SAnil udupa 			}
474a5407c02SAnil udupa 		}
475a5407c02SAnil udupa 		kmem_free(addrbuf, totaddr * sizeof (in6_addr_t *));
476a5407c02SAnil udupa 	}
477a5407c02SAnil udupa 	return (sctp);
478a5407c02SAnil udupa }
479a5407c02SAnil udupa 
480bd670b35SErik Nordmark /*
481bd670b35SErik Nordmark  * Fanout to a sctp instance.
482bd670b35SErik Nordmark  */
48345916cd2Sjpk conn_t *
sctp_fanout(in6_addr_t * src,in6_addr_t * dst,uint32_t ports,ip_recv_attr_t * ira,mblk_t * mp,sctp_stack_t * sctps,sctp_hdr_t * sctph)48445916cd2Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
485a5407c02SAnil udupa     ip_recv_attr_t *ira, mblk_t *mp, sctp_stack_t *sctps, sctp_hdr_t *sctph)
48645916cd2Sjpk {
487bd670b35SErik Nordmark 	zoneid_t zoneid = ira->ira_zoneid;
488bd670b35SErik Nordmark 	iaflags_t iraflags = ira->ira_flags;
48945916cd2Sjpk 	sctp_t *sctp;
490bd670b35SErik Nordmark 
491a5407c02SAnil udupa 	sctp = sctp_lookup_by_faddrs(mp, sctph, src, dst, ports, zoneid,
492a5407c02SAnil udupa 	    sctps, iraflags);
493bd670b35SErik Nordmark 	if (sctp == NULL) {
49445916cd2Sjpk 		/* Not in conn fanout; check listen fanout */
495bd670b35SErik Nordmark 		sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
496bd670b35SErik Nordmark 		if (sctp == NULL)
49745916cd2Sjpk 			return (NULL);
498d7ab25acSkp 		/*
499d7ab25acSkp 		 * On systems running trusted extensions, check if dst
500d7ab25acSkp 		 * should accept the packet. "IPV6_VERSION" indicates
501d7ab25acSkp 		 * that dst is in 16 byte AF_INET6 format. IPv4-mapped
502d7ab25acSkp 		 * IPv6 addresses are supported.
503d7ab25acSkp 		 */
504bd670b35SErik Nordmark 		if ((iraflags & IRAF_SYSTEM_LABELED) &&
505bd670b35SErik Nordmark 		    !tsol_receive_local(mp, dst, IPV6_VERSION, ira,
506bd670b35SErik Nordmark 		    sctp->sctp_connp)) {
507d7ab25acSkp 			DTRACE_PROBE3(
508d7ab25acSkp 			    tx__ip__log__info__classify__sctp,
509d7ab25acSkp 			    char *,
510d7ab25acSkp 			    "connp(1) could not receive mp(2)",
511d7ab25acSkp 			    conn_t *, sctp->sctp_connp, mblk_t *, mp);
512d7ab25acSkp 			SCTP_REFRELE(sctp);
513d7ab25acSkp 			return (NULL);
514d7ab25acSkp 		}
51545916cd2Sjpk 	}
516bd670b35SErik Nordmark 	/*
517bd670b35SErik Nordmark 	 * For labeled systems, there's no need to check the
518bd670b35SErik Nordmark 	 * label here.  It's known to be good as we checked
519bd670b35SErik Nordmark 	 * before allowing the connection to become bound.
520bd670b35SErik Nordmark 	 */
52145916cd2Sjpk 	return (sctp->sctp_connp);
52245916cd2Sjpk }
52345916cd2Sjpk 
5247c478bd9Sstevel@tonic-gate /*
525bd670b35SErik Nordmark  * Fanout for ICMP errors for SCTP
5267c478bd9Sstevel@tonic-gate  * The caller puts <fport, lport> in the ports parameter.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate void
ip_fanout_sctp(mblk_t * mp,ipha_t * ipha,ip6_t * ip6h,uint32_t ports,ip_recv_attr_t * ira)529bd670b35SErik Nordmark ip_fanout_sctp(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, uint32_t ports,
530bd670b35SErik Nordmark     ip_recv_attr_t *ira)
5317c478bd9Sstevel@tonic-gate {
532bd670b35SErik Nordmark 	sctp_t		*sctp;
533bd670b35SErik Nordmark 	conn_t		*connp;
534bd670b35SErik Nordmark 	in6_addr_t	map_src, map_dst;
535bd670b35SErik Nordmark 	in6_addr_t	*src, *dst;
536bd670b35SErik Nordmark 	boolean_t	secure;
537bd670b35SErik Nordmark 	ill_t		*ill = ira->ira_ill;
538bd670b35SErik Nordmark 	ip_stack_t	*ipst = ill->ill_ipst;
539bd670b35SErik Nordmark 	netstack_t	*ns = ipst->ips_netstack;
540bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
541bd670b35SErik Nordmark 	sctp_stack_t	*sctps = ns->netstack_sctp;
542bd670b35SErik Nordmark 	iaflags_t	iraflags = ira->ira_flags;
543bd670b35SErik Nordmark 	ill_t		*rill = ira->ira_rill;
544bd670b35SErik Nordmark 
545bd670b35SErik Nordmark 	ASSERT(iraflags & IRAF_ICMP_ERROR);
546bd670b35SErik Nordmark 
547bd670b35SErik Nordmark 	secure = iraflags & IRAF_IPSEC_SECURE;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/* Assume IP provides aligned packets - otherwise toss */
5507c478bd9Sstevel@tonic-gate 	if (!OK_32PTR(mp->b_rptr)) {
551bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
552bd670b35SErik Nordmark 		ip_drop_input("ipIfStatsInDiscards", mp, ill);
553bd670b35SErik Nordmark 		freemsg(mp);
5547c478bd9Sstevel@tonic-gate 		return;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
557bd670b35SErik Nordmark 	if (!(iraflags & IRAF_IS_IPV4)) {
5587c478bd9Sstevel@tonic-gate 		src = &ip6h->ip6_src;
5597c478bd9Sstevel@tonic-gate 		dst = &ip6h->ip6_dst;
5607c478bd9Sstevel@tonic-gate 	} else {
5617c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src);
5627c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst);
5637c478bd9Sstevel@tonic-gate 		src = &map_src;
5647c478bd9Sstevel@tonic-gate 		dst = &map_dst;
5657c478bd9Sstevel@tonic-gate 	}
566a5407c02SAnil udupa 	connp = sctp_fanout(src, dst, ports, ira, mp, sctps, NULL);
567f4b3ec61Sdh 	if (connp == NULL) {
568bd670b35SErik Nordmark 		ip_fanout_sctp_raw(mp, ipha, ip6h, ports, ira);
5697c478bd9Sstevel@tonic-gate 		return;
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 	sctp = CONN2SCTP(connp);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	/*
5747c478bd9Sstevel@tonic-gate 	 * We check some fields in conn_t without holding a lock.
5757c478bd9Sstevel@tonic-gate 	 * This should be fine.
5767c478bd9Sstevel@tonic-gate 	 */
577bd670b35SErik Nordmark 	if (((iraflags & IRAF_IS_IPV4) ?
578bd670b35SErik Nordmark 	    CONN_INBOUND_POLICY_PRESENT(connp, ipss) :
579bd670b35SErik Nordmark 	    CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) ||
580bd670b35SErik Nordmark 	    secure) {
581bd670b35SErik Nordmark 		mp = ipsec_check_inbound_policy(mp, connp, ipha,
582bd670b35SErik Nordmark 		    ip6h, ira);
5837c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
5847c478bd9Sstevel@tonic-gate 			SCTP_REFRELE(sctp);
5857c478bd9Sstevel@tonic-gate 			return;
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
589bd670b35SErik Nordmark 	ira->ira_ill = ira->ira_rill = NULL;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	mutex_enter(&sctp->sctp_lock);
5927c478bd9Sstevel@tonic-gate 	if (sctp->sctp_running) {
593bd670b35SErik Nordmark 		sctp_add_recvq(sctp, mp, B_FALSE, ira);
5947c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
5957c478bd9Sstevel@tonic-gate 	} else {
5967c478bd9Sstevel@tonic-gate 		sctp->sctp_running = B_TRUE;
5977c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_recvq_lock);
6007c478bd9Sstevel@tonic-gate 		if (sctp->sctp_recvq != NULL) {
601bd670b35SErik Nordmark 			sctp_add_recvq(sctp, mp, B_TRUE, ira);
6027c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_recvq_lock);
6037c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
6047c478bd9Sstevel@tonic-gate 		} else {
6057c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_recvq_lock);
606bd670b35SErik Nordmark 			if (ira->ira_flags & IRAF_ICMP_ERROR) {
607bd670b35SErik Nordmark 				sctp_icmp_error(sctp, mp);
608bd670b35SErik Nordmark 			} else {
609bd670b35SErik Nordmark 				sctp_input_data(sctp, mp, ira);
610bd670b35SErik Nordmark 			}
6117c478bd9Sstevel@tonic-gate 			WAKE_SCTP(sctp);
6127c478bd9Sstevel@tonic-gate 		}
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 	SCTP_REFRELE(sctp);
615bd670b35SErik Nordmark 	ira->ira_ill = ill;
616bd670b35SErik Nordmark 	ira->ira_rill = rill;
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate void
sctp_conn_hash_remove(sctp_t * sctp)6207c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate 	sctp_tf_t *tf = sctp->sctp_conn_tfp;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (!tf) {
6257c478bd9Sstevel@tonic-gate 		return;
6267c478bd9Sstevel@tonic-gate 	}
6271d8c4025Svi 	/*
6281d8c4025Svi 	 * On a clustered note send this notification to the clustering
6291d8c4025Svi 	 * subsystem.
6301d8c4025Svi 	 */
6311d8c4025Svi 	if (cl_sctp_disconnect != NULL) {
632bd670b35SErik Nordmark 		(*cl_sctp_disconnect)(sctp->sctp_connp->conn_family,
6331d8c4025Svi 		    (cl_sctp_handle_t)sctp);
6341d8c4025Svi 	}
6351d8c4025Svi 
6367c478bd9Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
6377c478bd9Sstevel@tonic-gate 	ASSERT(tf->tf_sctp);
6387c478bd9Sstevel@tonic-gate 	if (tf->tf_sctp == sctp) {
6397c478bd9Sstevel@tonic-gate 		tf->tf_sctp = sctp->sctp_conn_hash_next;
6407c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_hash_next) {
6417c478bd9Sstevel@tonic-gate 			ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp);
6427c478bd9Sstevel@tonic-gate 			tf->tf_sctp->sctp_conn_hash_prev = NULL;
6437c478bd9Sstevel@tonic-gate 		}
6447c478bd9Sstevel@tonic-gate 	} else {
6457c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_conn_hash_prev);
6467c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp);
6477c478bd9Sstevel@tonic-gate 		sctp->sctp_conn_hash_prev->sctp_conn_hash_next =
6487c478bd9Sstevel@tonic-gate 		    sctp->sctp_conn_hash_next;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_hash_next) {
6517c478bd9Sstevel@tonic-gate 			ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev
6527c478bd9Sstevel@tonic-gate 			    == sctp);
6537c478bd9Sstevel@tonic-gate 			sctp->sctp_conn_hash_next->sctp_conn_hash_prev =
6547c478bd9Sstevel@tonic-gate 			    sctp->sctp_conn_hash_prev;
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_hash_next = NULL;
6587c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_hash_prev = NULL;
6597c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_tfp = NULL;
6607c478bd9Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate void
sctp_conn_hash_insert(sctp_tf_t * tf,sctp_t * sctp,int caller_holds_lock)6647c478bd9Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp) {
6677c478bd9Sstevel@tonic-gate 		sctp_conn_hash_remove(sctp);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	if (!caller_holds_lock) {
6717c478bd9Sstevel@tonic-gate 		mutex_enter(&tf->tf_lock);
6727c478bd9Sstevel@tonic-gate 	} else {
6737c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&tf->tf_lock));
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_hash_next = tf->tf_sctp;
6777c478bd9Sstevel@tonic-gate 	if (tf->tf_sctp) {
6787c478bd9Sstevel@tonic-gate 		tf->tf_sctp->sctp_conn_hash_prev = sctp;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_hash_prev = NULL;
6817c478bd9Sstevel@tonic-gate 	tf->tf_sctp = sctp;
6827c478bd9Sstevel@tonic-gate 	sctp->sctp_conn_tfp = tf;
6837c478bd9Sstevel@tonic-gate 	if (!caller_holds_lock) {
6847c478bd9Sstevel@tonic-gate 		mutex_exit(&tf->tf_lock);
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate void
sctp_listen_hash_remove(sctp_t * sctp)6897c478bd9Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	sctp_tf_t *tf = sctp->sctp_listen_tfp;
692bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	if (!tf) {
6957c478bd9Sstevel@tonic-gate 		return;
6967c478bd9Sstevel@tonic-gate 	}
6971d8c4025Svi 	/*
6981d8c4025Svi 	 * On a clustered note send this notification to the clustering
6991d8c4025Svi 	 * subsystem.
7001d8c4025Svi 	 */
7011d8c4025Svi 	if (cl_sctp_unlisten != NULL) {
7021d8c4025Svi 		uchar_t	*slist;
7031d8c4025Svi 		ssize_t	ssize;
7041d8c4025Svi 
7051d8c4025Svi 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
7061d8c4025Svi 		slist = kmem_alloc(ssize, KM_SLEEP);
7071d8c4025Svi 		sctp_get_saddr_list(sctp, slist, ssize);
708bd670b35SErik Nordmark 		(*cl_sctp_unlisten)(connp->conn_family, slist,
709bd670b35SErik Nordmark 		    sctp->sctp_nsaddrs, connp->conn_lport);
7101d8c4025Svi 		/* list will be freed by the clustering module */
7111d8c4025Svi 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
7147c478bd9Sstevel@tonic-gate 	ASSERT(tf->tf_sctp);
7157c478bd9Sstevel@tonic-gate 	if (tf->tf_sctp == sctp) {
7167c478bd9Sstevel@tonic-gate 		tf->tf_sctp = sctp->sctp_listen_hash_next;
717e6f13f86SKacheong Poon 		if (sctp->sctp_listen_hash_next != NULL) {
7187c478bd9Sstevel@tonic-gate 			ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp);
7197c478bd9Sstevel@tonic-gate 			tf->tf_sctp->sctp_listen_hash_prev = NULL;
7207c478bd9Sstevel@tonic-gate 		}
7217c478bd9Sstevel@tonic-gate 	} else {
7227c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_listen_hash_prev);
7237c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next ==
7247c478bd9Sstevel@tonic-gate 		    sctp);
725e6f13f86SKacheong Poon 		ASSERT(sctp->sctp_listen_hash_next == NULL ||
726e6f13f86SKacheong Poon 		    sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp);
727e6f13f86SKacheong Poon 
7287c478bd9Sstevel@tonic-gate 		sctp->sctp_listen_hash_prev->sctp_listen_hash_next =
7297c478bd9Sstevel@tonic-gate 		    sctp->sctp_listen_hash_next;
7307c478bd9Sstevel@tonic-gate 
731e6f13f86SKacheong Poon 		if (sctp->sctp_listen_hash_next != NULL) {
732bd670b35SErik Nordmark 			sctp_t *next = sctp->sctp_listen_hash_next;
733bd670b35SErik Nordmark 
734bd670b35SErik Nordmark 			ASSERT(next->sctp_listen_hash_prev == sctp);
735bd670b35SErik Nordmark 			next->sctp_listen_hash_prev =
7367c478bd9Sstevel@tonic-gate 			    sctp->sctp_listen_hash_prev;
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_hash_next = NULL;
7407c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_hash_prev = NULL;
7417c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_tfp = NULL;
7427c478bd9Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate void
sctp_listen_hash_insert(sctp_tf_t * tf,sctp_t * sctp)7467c478bd9Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp)
7477c478bd9Sstevel@tonic-gate {
748bd670b35SErik Nordmark 	conn_t	*connp = sctp->sctp_connp;
749bd670b35SErik Nordmark 
7507c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp) {
7517c478bd9Sstevel@tonic-gate 		sctp_listen_hash_remove(sctp);
7527c478bd9Sstevel@tonic-gate 	}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	mutex_enter(&tf->tf_lock);
7557c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_hash_next = tf->tf_sctp;
7567c478bd9Sstevel@tonic-gate 	if (tf->tf_sctp) {
7577c478bd9Sstevel@tonic-gate 		tf->tf_sctp->sctp_listen_hash_prev = sctp;
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_hash_prev = NULL;
7607c478bd9Sstevel@tonic-gate 	tf->tf_sctp = sctp;
7617c478bd9Sstevel@tonic-gate 	sctp->sctp_listen_tfp = tf;
7627c478bd9Sstevel@tonic-gate 	mutex_exit(&tf->tf_lock);
7631d8c4025Svi 	/*
7641d8c4025Svi 	 * On a clustered note send this notification to the clustering
7651d8c4025Svi 	 * subsystem.
7661d8c4025Svi 	 */
7671d8c4025Svi 	if (cl_sctp_listen != NULL) {
7681d8c4025Svi 		uchar_t	*slist;
7691d8c4025Svi 		ssize_t	ssize;
7701d8c4025Svi 
7711d8c4025Svi 		ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
7721d8c4025Svi 		slist = kmem_alloc(ssize, KM_SLEEP);
7731d8c4025Svi 		sctp_get_saddr_list(sctp, slist, ssize);
774bd670b35SErik Nordmark 		(*cl_sctp_listen)(connp->conn_family, slist,
775bd670b35SErik Nordmark 		    sctp->sctp_nsaddrs, connp->conn_lport);
7761d8c4025Svi 		/* list will be freed by the clustering module */
7771d8c4025Svi 	}
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate /*
7817c478bd9Sstevel@tonic-gate  * Hash list insertion routine for sctp_t structures.
7827c478bd9Sstevel@tonic-gate  * Inserts entries with the ones bound to a specific IP address first
7837c478bd9Sstevel@tonic-gate  * followed by those bound to INADDR_ANY.
7847c478bd9Sstevel@tonic-gate  */
7857c478bd9Sstevel@tonic-gate void
sctp_bind_hash_insert(sctp_tf_t * tbf,sctp_t * sctp,int caller_holds_lock)7867c478bd9Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	sctp_t	**sctpp;
7897c478bd9Sstevel@tonic-gate 	sctp_t	*sctpnext;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn != NULL) {
7927c478bd9Sstevel@tonic-gate 		ASSERT(!caller_holds_lock);
7937c478bd9Sstevel@tonic-gate 		sctp_bind_hash_remove(sctp);
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate 	sctpp = &tbf->tf_sctp;
7967c478bd9Sstevel@tonic-gate 	if (!caller_holds_lock) {
7977c478bd9Sstevel@tonic-gate 		mutex_enter(&tbf->tf_lock);
7987c478bd9Sstevel@tonic-gate 	} else {
7997c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&tbf->tf_lock));
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 	sctpnext = sctpp[0];
8027c478bd9Sstevel@tonic-gate 	if (sctpnext) {
8037c478bd9Sstevel@tonic-gate 		sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash;
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 	sctp->sctp_bind_hash = sctpnext;
8067c478bd9Sstevel@tonic-gate 	sctp->sctp_ptpbhn = sctpp;
8077c478bd9Sstevel@tonic-gate 	sctpp[0] = sctp;
8087c478bd9Sstevel@tonic-gate 	/* For sctp_*_hash_remove */
8097c478bd9Sstevel@tonic-gate 	sctp->sctp_bind_lockp = &tbf->tf_lock;
8107c478bd9Sstevel@tonic-gate 	if (!caller_holds_lock)
8117c478bd9Sstevel@tonic-gate 		mutex_exit(&tbf->tf_lock);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate  * Hash list removal routine for sctp_t structures.
8167c478bd9Sstevel@tonic-gate  */
8177c478bd9Sstevel@tonic-gate void
sctp_bind_hash_remove(sctp_t * sctp)8187c478bd9Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp)
8197c478bd9Sstevel@tonic-gate {
8207c478bd9Sstevel@tonic-gate 	sctp_t	*sctpnext;
8217c478bd9Sstevel@tonic-gate 	kmutex_t *lockp;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	lockp = sctp->sctp_bind_lockp;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn == NULL)
8267c478bd9Sstevel@tonic-gate 		return;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	ASSERT(lockp != NULL);
8297c478bd9Sstevel@tonic-gate 	mutex_enter(lockp);
8307c478bd9Sstevel@tonic-gate 	if (sctp->sctp_ptpbhn) {
8317c478bd9Sstevel@tonic-gate 		sctpnext = sctp->sctp_bind_hash;
8327c478bd9Sstevel@tonic-gate 		if (sctpnext) {
8337c478bd9Sstevel@tonic-gate 			sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn;
8347c478bd9Sstevel@tonic-gate 			sctp->sctp_bind_hash = NULL;
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 		*sctp->sctp_ptpbhn = sctpnext;
8377c478bd9Sstevel@tonic-gate 		sctp->sctp_ptpbhn = NULL;
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 	mutex_exit(lockp);
8407c478bd9Sstevel@tonic-gate 	sctp->sctp_bind_lockp = NULL;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
844e6f13f86SKacheong Poon  * Similar to but different from sctp_conn_match().
8457c478bd9Sstevel@tonic-gate  *
8467c478bd9Sstevel@tonic-gate  * Matches sets of addresses as follows: if the argument addr set is
8477c478bd9Sstevel@tonic-gate  * a complete subset of the corresponding addr set in the sctp_t, it
8487c478bd9Sstevel@tonic-gate  * is a match.
8497c478bd9Sstevel@tonic-gate  *
8507c478bd9Sstevel@tonic-gate  * Caller must hold tf->tf_lock.
8517c478bd9Sstevel@tonic-gate  *
8527c478bd9Sstevel@tonic-gate  * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE.
8537c478bd9Sstevel@tonic-gate  */
8547c478bd9Sstevel@tonic-gate sctp_t *
sctp_lookup(sctp_t * sctp1,in6_addr_t * faddr,sctp_tf_t * tf,uint32_t * ports,int min_state)8557c478bd9Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports,
8567c478bd9Sstevel@tonic-gate     int min_state)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate 	sctp_t *sctp;
8597c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&tf->tf_lock));
8627c478bd9Sstevel@tonic-gate 
863e6f13f86SKacheong Poon 	for (sctp = tf->tf_sctp; sctp != NULL;
864e6f13f86SKacheong Poon 	    sctp = sctp->sctp_conn_hash_next) {
865bd670b35SErik Nordmark 		if (*ports != sctp->sctp_connp->conn_ports ||
866bd670b35SErik Nordmark 		    sctp->sctp_state < min_state) {
8677c478bd9Sstevel@tonic-gate 			continue;
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		/* check for faddr match */
8716be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
8726be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			if (IN6_ARE_ADDR_EQUAL(faddr, &fp->sf_faddr)) {
8737c478bd9Sstevel@tonic-gate 				break;
8747c478bd9Sstevel@tonic-gate 			}
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 
877e6f13f86SKacheong Poon 		if (fp == NULL) {
8787c478bd9Sstevel@tonic-gate 			/* no faddr match; keep looking */
8797c478bd9Sstevel@tonic-gate 			continue;
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 
882e6f13f86SKacheong Poon 		/*
883e6f13f86SKacheong Poon 		 * There is an existing association with the same peer
884e6f13f86SKacheong Poon 		 * address.  So now we need to check if our local address
885e6f13f86SKacheong Poon 		 * set overlaps with the one of the existing association.
886e6f13f86SKacheong Poon 		 * If they overlap, we should return it.
887e6f13f86SKacheong Poon 		 */
888e6f13f86SKacheong Poon 		if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) {
8897c478bd9Sstevel@tonic-gate 			goto done;
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 		/* no match; continue searching */
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate done:
896e6f13f86SKacheong Poon 	if (sctp != NULL) {
8977c478bd9Sstevel@tonic-gate 		SCTP_REFHOLD(sctp);
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 	return (sctp);
9007c478bd9Sstevel@tonic-gate }
901