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 /*
22f4b3ec61Sdh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/stream.h>
31*1d19ca10Svi #include <sys/cmn_err.h>
327c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/socket.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/list.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <netinet/in.h>
407c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
417c478bd9Sstevel@tonic-gate #include <netinet/sctp.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <inet/common.h>
447c478bd9Sstevel@tonic-gate #include <inet/ip.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
467c478bd9Sstevel@tonic-gate #include <inet/ip_if.h>
477c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
487c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
497c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
507c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static void		sctp_ipif_inactive(sctp_ipif_t *);
537c478bd9Sstevel@tonic-gate static sctp_ipif_t	*sctp_lookup_ipif_addr(in6_addr_t *, boolean_t,
54e35d2278Svi 			    zoneid_t, boolean_t, uint_t, uint_t, boolean_t,
55e35d2278Svi 			    sctp_stack_t *);
567c478bd9Sstevel@tonic-gate static int		sctp_get_all_ipifs(sctp_t *, int);
57f551bb10Svi static int		sctp_ipif_hash_insert(sctp_t *, sctp_ipif_t *, int,
58e35d2278Svi 			    boolean_t, boolean_t);
597c478bd9Sstevel@tonic-gate static void		sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *);
607c478bd9Sstevel@tonic-gate static int		sctp_compare_ipif_list(sctp_ipif_hash_t *,
617c478bd9Sstevel@tonic-gate 			    sctp_ipif_hash_t *);
627c478bd9Sstevel@tonic-gate static int		sctp_copy_ipifs(sctp_ipif_hash_t *, sctp_t *, int);
63f551bb10Svi 
64e35d2278Svi #define	SCTP_ADDR4_HASH(addr)	\
65e35d2278Svi 	(((addr) ^ ((addr) >> 8) ^ ((addr) >> 16) ^ ((addr) >> 24)) &	\
66e35d2278Svi 	(SCTP_IPIF_HASH - 1))
67e35d2278Svi 
68e35d2278Svi #define	SCTP_ADDR6_HASH(addr)	\
69e35d2278Svi 	(((addr).s6_addr32[3] ^						\
70e35d2278Svi 	(((addr).s6_addr32[3] ^ (addr).s6_addr32[2]) >> 12)) &		\
71e35d2278Svi 	(SCTP_IPIF_HASH - 1))
72e35d2278Svi 
73e35d2278Svi #define	SCTP_IPIF_ADDR_HASH(addr, isv6)					\
74e35d2278Svi 	((isv6) ? SCTP_ADDR6_HASH((addr)) : 				\
75e35d2278Svi 	SCTP_ADDR4_HASH((addr)._S6_un._S6_u32[3]))
76e35d2278Svi 
777c478bd9Sstevel@tonic-gate #define	SCTP_IPIF_USABLE(sctp_ipif_state)	\
787c478bd9Sstevel@tonic-gate 	((sctp_ipif_state) == SCTP_IPIFS_UP ||	\
79f551bb10Svi 	(sctp_ipif_state) ==  SCTP_IPIFS_DOWN)
80f551bb10Svi 
81f551bb10Svi #define	SCTP_IPIF_DISCARD(sctp_ipif_flags)	\
82f551bb10Svi 	((sctp_ipif_flags) & (IPIF_PRIVATE | IPIF_DEPRECATED))
83f551bb10Svi 
841d8c4025Svi #define	SCTP_IS_IPIF_LOOPBACK(ipif)		\
851d8c4025Svi 	((ipif)->sctp_ipif_ill->sctp_ill_flags & PHYI_LOOPBACK)
861d8c4025Svi 
871d8c4025Svi #define	SCTP_IS_IPIF_LINKLOCAL(ipif)		\
881d8c4025Svi 	((ipif)->sctp_ipif_isv6 && 		\
891d8c4025Svi 	IN6_IS_ADDR_LINKLOCAL(&(ipif)->sctp_ipif_saddr))
90f551bb10Svi 
91f551bb10Svi #define	SCTP_UNSUPP_AF(ipif, supp_af)	\
92f551bb10Svi 	((!(ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V4)) ||	\
93f551bb10Svi 	((ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V6)))
947c478bd9Sstevel@tonic-gate 
955d0bc3edSsommerfe #define	SCTP_IPIF_ZONE_MATCH(sctp, ipif) 				\
965d0bc3edSsommerfe 	IPCL_ZONE_MATCH((sctp)->sctp_connp, (ipif)->sctp_ipif_zoneid)
975d0bc3edSsommerfe 
987c478bd9Sstevel@tonic-gate #define	SCTP_ILL_HASH_FN(index)		((index) % SCTP_ILL_HASH)
997c478bd9Sstevel@tonic-gate #define	SCTP_ILL_TO_PHYINDEX(ill)	((ill)->ill_phyint->phyint_ifindex)
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * SCTP Interface list manipulation functions, locking used.
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Delete an SCTP IPIF from the list if the refcount goes to 0 and it is
1077c478bd9Sstevel@tonic-gate  * marked as condemned. Also, check if the ILL needs to go away.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static void
1107c478bd9Sstevel@tonic-gate sctp_ipif_inactive(sctp_ipif_t *sctp_ipif)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
113e35d2278Svi 	uint_t		hindex;
1147c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
115f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp_ipif->sctp_ipif_ill->
116f4b3ec61Sdh 	    sctp_ill_netstack->netstack_sctp;
1177c478bd9Sstevel@tonic-gate 
118f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
119f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1207c478bd9Sstevel@tonic-gate 
121e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(sctp_ipif->sctp_ipif_saddr,
122e35d2278Svi 	    sctp_ipif->sctp_ipif_isv6);
123e35d2278Svi 
1247c478bd9Sstevel@tonic-gate 	sctp_ill = sctp_ipif->sctp_ipif_ill;
1257c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ill != NULL);
1267c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(sctp_ill->sctp_ill_index);
1277c478bd9Sstevel@tonic-gate 	if (sctp_ipif->sctp_ipif_state != SCTP_IPIFS_CONDEMNED ||
1287c478bd9Sstevel@tonic-gate 	    sctp_ipif->sctp_ipif_refcnt != 0) {
129f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
130f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
1317c478bd9Sstevel@tonic-gate 		return;
1327c478bd9Sstevel@tonic-gate 	}
133e35d2278Svi 	list_remove(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
134f4b3ec61Sdh 	    sctp_ipif);
135e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count--;
136f4b3ec61Sdh 	sctps->sctps_g_ipifs_count--;
1377c478bd9Sstevel@tonic-gate 	rw_destroy(&sctp_ipif->sctp_ipif_lock);
1387c478bd9Sstevel@tonic-gate 	kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
141f4b3ec61Sdh 	if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
142f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
1437c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0 &&
1447c478bd9Sstevel@tonic-gate 		    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
145f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[ill_index].
146f4b3ec61Sdh 			    sctp_ill_list, (void *)sctp_ill);
147f4b3ec61Sdh 			sctps->sctps_g_ills[ill_index].ill_count--;
148f4b3ec61Sdh 			sctps->sctps_ills_count--;
1497c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
1507c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_name_length);
1517c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 	}
154f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
155f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Lookup an SCTP IPIF given an IP address. Increments sctp_ipif refcnt.
160e35d2278Svi  * We are either looking for a IPIF with the given address before
161e35d2278Svi  * inserting it into the global list or looking for an IPIF for an
162e35d2278Svi  * address given an SCTP. In the former case we always check the zoneid,
163e35d2278Svi  * but for the latter case, check_zid could be B_FALSE if the connp
164e35d2278Svi  * for the sctp has conn_all_zones set. When looking for an address we
165e35d2278Svi  * give preference to one that is up, so even though we may find one that
166e35d2278Svi  * is not up we keep looking if there is one up, we hold the down addr
167e35d2278Svi  * in backup_ipif in case we don't find one that is up - i.e. we return
168e35d2278Svi  * the backup_ipif in that case. Note that if we are looking for. If we
169e35d2278Svi  * are specifically looking for an up address, then usable will be set
170e35d2278Svi  * to true.
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static sctp_ipif_t *
173e35d2278Svi sctp_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid,
174e35d2278Svi     boolean_t check_zid, uint_t ifindex, uint_t seqid, boolean_t usable,
175e35d2278Svi     sctp_stack_t *sctps)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	int		j;
1787c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
179e35d2278Svi 	sctp_ipif_t	*backup_ipif = NULL;
180e35d2278Svi 	int		hindex;
181e35d2278Svi 
182e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1837c478bd9Sstevel@tonic-gate 
184f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
185e35d2278Svi 	if (sctps->sctps_g_ipifs[hindex].ipif_count == 0) {
186e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
187e35d2278Svi 		return (NULL);
188e35d2278Svi 	}
189e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
190e35d2278Svi 	for (j = 0; j < sctps->sctps_g_ipifs[hindex].ipif_count; j++) {
191e35d2278Svi 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
192e35d2278Svi 		if ((!check_zid ||
193e35d2278Svi 		    (sctp_ipif->sctp_ipif_zoneid == ALL_ZONES ||
194e35d2278Svi 		    zoneid == sctp_ipif->sctp_ipif_zoneid)) &&
195e35d2278Svi 		    (ifindex == 0 || ifindex ==
196e35d2278Svi 		    sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
197e35d2278Svi 		    ((seqid != 0 && seqid == sctp_ipif->sctp_ipif_id) ||
198e35d2278Svi 		    (IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
199e35d2278Svi 		    addr)))) {
200e35d2278Svi 			if (!usable || sctp_ipif->sctp_ipif_state ==
201e35d2278Svi 			    SCTP_IPIFS_UP) {
2027c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2037c478bd9Sstevel@tonic-gate 				if (refhold)
2047c478bd9Sstevel@tonic-gate 					SCTP_IPIF_REFHOLD(sctp_ipif);
205f4b3ec61Sdh 				rw_exit(&sctps->sctps_g_ipifs_lock);
2067c478bd9Sstevel@tonic-gate 				return (sctp_ipif);
207e35d2278Svi 			} else if (sctp_ipif->sctp_ipif_state ==
208e35d2278Svi 			    SCTP_IPIFS_DOWN && backup_ipif == NULL) {
209e35d2278Svi 				backup_ipif = sctp_ipif;
2107c478bd9Sstevel@tonic-gate 			}
2117c478bd9Sstevel@tonic-gate 		}
212e35d2278Svi 		rw_exit(&sctp_ipif->sctp_ipif_lock);
213e35d2278Svi 		sctp_ipif = list_next(
214e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
215e35d2278Svi 	}
216e35d2278Svi 	if (backup_ipif != NULL) {
217e35d2278Svi 		if (refhold)
218e35d2278Svi 			SCTP_IPIF_REFHOLD(backup_ipif);
219e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
220e35d2278Svi 		return (backup_ipif);
2217c478bd9Sstevel@tonic-gate 	}
222f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2237c478bd9Sstevel@tonic-gate 	return (NULL);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate  * Populate the list with all the SCTP ipifs for a given ipversion.
2287c478bd9Sstevel@tonic-gate  * Increments sctp_ipif refcnt.
2297c478bd9Sstevel@tonic-gate  * Called with no locks held.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate static int
2327c478bd9Sstevel@tonic-gate sctp_get_all_ipifs(sctp_t *sctp, int sleep)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
2357c478bd9Sstevel@tonic-gate 	int			i;
2367c478bd9Sstevel@tonic-gate 	int			j;
2377c478bd9Sstevel@tonic-gate 	int			error = 0;
238f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
2397c478bd9Sstevel@tonic-gate 
240f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
2417c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
242f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[i].ipif_count == 0)
2437c478bd9Sstevel@tonic-gate 			continue;
244f4b3ec61Sdh 		sctp_ipif = list_head(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
245f4b3ec61Sdh 		for (j = 0; j < sctps->sctps_g_ipifs[i].ipif_count; j++) {
2467c478bd9Sstevel@tonic-gate 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
247f551bb10Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
2487c478bd9Sstevel@tonic-gate 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
2495d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
2507c478bd9Sstevel@tonic-gate 			    (sctp->sctp_ipversion == IPV4_VERSION &&
251f551bb10Svi 			    sctp_ipif->sctp_ipif_isv6) ||
2527c478bd9Sstevel@tonic-gate 			    (sctp->sctp_connp->conn_ipv6_v6only &&
253f551bb10Svi 			    !sctp_ipif->sctp_ipif_isv6)) {
2547c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2557c478bd9Sstevel@tonic-gate 				sctp_ipif = list_next(
256f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
257f4b3ec61Sdh 				    sctp_ipif);
2587c478bd9Sstevel@tonic-gate 				continue;
2597c478bd9Sstevel@tonic-gate 			}
2607c478bd9Sstevel@tonic-gate 			rw_exit(&sctp_ipif->sctp_ipif_lock);
2617c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFHOLD(sctp_ipif);
262f551bb10Svi 			error = sctp_ipif_hash_insert(sctp, sctp_ipif, sleep,
263e35d2278Svi 			    B_FALSE, B_FALSE);
264e35d2278Svi 			if (error != 0 && error != EALREADY)
2657c478bd9Sstevel@tonic-gate 				goto free_stuff;
266f4b3ec61Sdh 			sctp_ipif = list_next(
267f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2687c478bd9Sstevel@tonic-gate 			    sctp_ipif);
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 	}
271f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2727c478bd9Sstevel@tonic-gate 	return (0);
2737c478bd9Sstevel@tonic-gate free_stuff:
274f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2757c478bd9Sstevel@tonic-gate 	sctp_free_saddrs(sctp);
2767c478bd9Sstevel@tonic-gate 	return (ENOMEM);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Given a list of address, fills in the list of SCTP ipifs if all the addresses
2817c478bd9Sstevel@tonic-gate  * are present in the SCTP interface list, return number of addresses filled
2821d8c4025Svi  * or error. If the caller wants the list of addresses, it sends a pre-allocated
2831d8c4025Svi  * buffer - list. Currently, this list is only used on a clustered node when
2841d8c4025Svi  * the SCTP is in the listen state (from sctp_bind_add()). When called on a
2851d8c4025Svi  * clustered node, the input is always a list of addresses (even if the
2861d8c4025Svi  * original bind() was to INADDR_ANY).
2877c478bd9Sstevel@tonic-gate  * Called with no locks held.
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate int
2901d8c4025Svi sctp_valid_addr_list(sctp_t *sctp, const void *addrs, uint32_t addrcnt,
2911d8c4025Svi     uchar_t *list, size_t lsize)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
2947c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
2957c478bd9Sstevel@tonic-gate 	struct in_addr		*addr4;
2967c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
2977c478bd9Sstevel@tonic-gate 	int			cnt;
2987c478bd9Sstevel@tonic-gate 	int			err = 0;
2997c478bd9Sstevel@tonic-gate 	int			saddr_cnt = 0;
3007c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*ipif;
3017c478bd9Sstevel@tonic-gate 	boolean_t		bind_to_all = B_FALSE;
3027c478bd9Sstevel@tonic-gate 	boolean_t		check_addrs = B_FALSE;
3037c478bd9Sstevel@tonic-gate 	boolean_t		check_lport = B_FALSE;
3041d8c4025Svi 	uchar_t			*p = list;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * Need to check for port and address depending on the state.
3087c478bd9Sstevel@tonic-gate 	 * After a socket is bound, we need to make sure that subsequent
3097c478bd9Sstevel@tonic-gate 	 * bindx() has correct port.  After an association is established,
3107c478bd9Sstevel@tonic-gate 	 * we need to check for changing the bound address to invalid
3117c478bd9Sstevel@tonic-gate 	 * addresses.
3127c478bd9Sstevel@tonic-gate 	 */
3137c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state >= SCTPS_BOUND) {
3147c478bd9Sstevel@tonic-gate 		check_lport = B_TRUE;
3157c478bd9Sstevel@tonic-gate 		if (sctp->sctp_state > SCTPS_LISTEN)
3167c478bd9Sstevel@tonic-gate 			check_addrs = B_TRUE;
3177c478bd9Sstevel@tonic-gate 	}
3181d8c4025Svi 
3197c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
3207c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
3217c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
3227c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
3237c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addrcnt; cnt++) {
3247c478bd9Sstevel@tonic-gate 		boolean_t	lookup_saddr = B_TRUE;
3251d8c4025Svi 		uint_t		ifindex = 0;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		switch (sctp->sctp_family) {
3287c478bd9Sstevel@tonic-gate 		case AF_INET:
3297c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
3307c478bd9Sstevel@tonic-gate 			if (sin4->sin_family != AF_INET || (check_lport &&
3317c478bd9Sstevel@tonic-gate 			    sin4->sin_port != sctp->sctp_lport)) {
3327c478bd9Sstevel@tonic-gate 				err = EINVAL;
3337c478bd9Sstevel@tonic-gate 				goto free_ret;
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 			addr4 = &sin4->sin_addr;
3367c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3377c478bd9Sstevel@tonic-gate 			    (addr4->s_addr == INADDR_ANY ||
3387c478bd9Sstevel@tonic-gate 			    addr4->s_addr == INADDR_BROADCAST ||
3397c478bd9Sstevel@tonic-gate 			    IN_MULTICAST(addr4->s_addr))) {
3407c478bd9Sstevel@tonic-gate 				err = EINVAL;
3417c478bd9Sstevel@tonic-gate 				goto free_ret;
3427c478bd9Sstevel@tonic-gate 			}
3437c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(addr4, &addr);
3447c478bd9Sstevel@tonic-gate 			if (!check_addrs && addr4->s_addr == INADDR_ANY) {
3457c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3467c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 			break;
3507c478bd9Sstevel@tonic-gate 		case AF_INET6:
3517c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
3527c478bd9Sstevel@tonic-gate 			if (sin6->sin6_family != AF_INET6 || (check_lport &&
3537c478bd9Sstevel@tonic-gate 			    sin6->sin6_port != sctp->sctp_lport)) {
3547c478bd9Sstevel@tonic-gate 				err = EINVAL;
3557c478bd9Sstevel@tonic-gate 				goto free_ret;
3567c478bd9Sstevel@tonic-gate 			}
3577c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
3581d8c4025Svi 			/* Contains the interface index */
3591d8c4025Svi 			ifindex = sin6->sin6_scope_id;
3607c478bd9Sstevel@tonic-gate 			if (sctp->sctp_connp->conn_ipv6_v6only &&
3617c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&addr)) {
3627c478bd9Sstevel@tonic-gate 				err = EAFNOSUPPORT;
3637c478bd9Sstevel@tonic-gate 				goto free_ret;
3647c478bd9Sstevel@tonic-gate 			}
3657c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3667c478bd9Sstevel@tonic-gate 			    (IN6_IS_ADDR_LINKLOCAL(&addr) ||
3677c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&addr) ||
3687c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_UNSPECIFIED(&addr))) {
3697c478bd9Sstevel@tonic-gate 				err = EINVAL;
3707c478bd9Sstevel@tonic-gate 				goto free_ret;
3717c478bd9Sstevel@tonic-gate 			}
3727c478bd9Sstevel@tonic-gate 			if (!check_addrs && IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3737c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3747c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 			break;
3787c478bd9Sstevel@tonic-gate 		default:
3797c478bd9Sstevel@tonic-gate 			err = EAFNOSUPPORT;
3807c478bd9Sstevel@tonic-gate 			goto free_ret;
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 		if (lookup_saddr) {
383e35d2278Svi 			ipif = sctp_lookup_ipif_addr(&addr, B_TRUE,
384e35d2278Svi 			    sctp->sctp_zoneid, !sctp->sctp_connp->conn_allzones,
385e35d2278Svi 			    ifindex, 0, B_TRUE, sctp->sctp_sctps);
3867c478bd9Sstevel@tonic-gate 			if (ipif == NULL) {
3877c478bd9Sstevel@tonic-gate 				/* Address not in the list */
3887c478bd9Sstevel@tonic-gate 				err = EINVAL;
3897c478bd9Sstevel@tonic-gate 				goto free_ret;
3901d8c4025Svi 			} else if (check_addrs && SCTP_IS_IPIF_LOOPBACK(ipif) &&
3911d8c4025Svi 			    cl_sctp_check_addrs == NULL) {
3927c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
3937c478bd9Sstevel@tonic-gate 				err = EINVAL;
3947c478bd9Sstevel@tonic-gate 				goto free_ret;
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 		if (!bind_to_all) {
398f551bb10Svi 			/*
399f551bb10Svi 			 * If an address is added after association setup,
400f551bb10Svi 			 * we need to wait for the peer to send us an ASCONF
401f551bb10Svi 			 * ACK before we can start using it.
402f551bb10Svi 			 * saddr_ipif_dontsrc will be reset (to 0) when we
403f551bb10Svi 			 * get the ASCONF ACK for this address.
404f551bb10Svi 			 */
405f551bb10Svi 			err = sctp_ipif_hash_insert(sctp, ipif, KM_SLEEP,
406e35d2278Svi 			    check_addrs ? B_TRUE : B_FALSE, B_FALSE);
4077c478bd9Sstevel@tonic-gate 			if (err != 0) {
4087c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
4097c478bd9Sstevel@tonic-gate 				if (check_addrs && err == EALREADY)
4107c478bd9Sstevel@tonic-gate 					err = EADDRINUSE;
4117c478bd9Sstevel@tonic-gate 				goto free_ret;
4127c478bd9Sstevel@tonic-gate 			}
4137c478bd9Sstevel@tonic-gate 			saddr_cnt++;
4141d8c4025Svi 			if (lsize >= sizeof (addr)) {
4151d8c4025Svi 				bcopy(&addr, p, sizeof (addr));
4161d8c4025Svi 				p += sizeof (addr);
4171d8c4025Svi 				lsize -= sizeof (addr);
4181d8c4025Svi 			}
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 	if (bind_to_all) {
4227c478bd9Sstevel@tonic-gate 		/*
4237c478bd9Sstevel@tonic-gate 		 * Free whatever we might have added before encountering
4247c478bd9Sstevel@tonic-gate 		 * inaddr_any.
4257c478bd9Sstevel@tonic-gate 		 */
4267c478bd9Sstevel@tonic-gate 		if (sctp->sctp_nsaddrs > 0) {
4277c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp);
4287c478bd9Sstevel@tonic-gate 			ASSERT(sctp->sctp_nsaddrs == 0);
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		err = sctp_get_all_ipifs(sctp, KM_SLEEP);
4317c478bd9Sstevel@tonic-gate 		if (err != 0)
4327c478bd9Sstevel@tonic-gate 			return (err);
4337c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4367c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4377c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4387c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4397c478bd9Sstevel@tonic-gate 	return (0);
4407c478bd9Sstevel@tonic-gate free_ret:
4417c478bd9Sstevel@tonic-gate 	if (saddr_cnt != 0)
4427c478bd9Sstevel@tonic-gate 		sctp_del_saddr_list(sctp, addrs, saddr_cnt, B_TRUE);
4437c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4447c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4457c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4467c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4477c478bd9Sstevel@tonic-gate 	return (err);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate static int
451f551bb10Svi sctp_ipif_hash_insert(sctp_t *sctp, sctp_ipif_t *ipif, int sleep,
452e35d2278Svi     boolean_t dontsrc, boolean_t allow_dup)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	int			cnt;
4557c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
456e35d2278Svi 	int			hindex;
457e35d2278Svi 
458e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
459e35d2278Svi 	    ipif->sctp_ipif_isv6);
460e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
461e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
462e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
463e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
464e35d2278Svi 			if (ipif->sctp_ipif_id !=
465e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id &&
466e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_state ==
467e35d2278Svi 			    SCTP_IPIFS_DOWN && ipif->sctp_ipif_state ==
468e35d2278Svi 			    SCTP_IPIFS_UP) {
469e35d2278Svi 				SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
470e35d2278Svi 				ipif_obj->saddr_ipifp = ipif;
471e35d2278Svi 				ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
472e35d2278Svi 				return (0);
473e35d2278Svi 			} else if (!allow_dup || ipif->sctp_ipif_id ==
474e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id) {
475e35d2278Svi 				return (EALREADY);
476e35d2278Svi 			}
477e35d2278Svi 		}
478e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
4797c478bd9Sstevel@tonic-gate 		    ipif_obj);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 	ipif_obj = kmem_zalloc(sizeof (sctp_saddr_ipif_t), sleep);
4827c478bd9Sstevel@tonic-gate 	if (ipif_obj == NULL) {
4837c478bd9Sstevel@tonic-gate 		/* Need to do something */
4847c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 	ipif_obj->saddr_ipifp = ipif;
487f551bb10Svi 	ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
488e35d2278Svi 	list_insert_tail(&sctp->sctp_saddrs[hindex].sctp_ipif_list, ipif_obj);
489e35d2278Svi 	sctp->sctp_saddrs[hindex].ipif_count++;
4907c478bd9Sstevel@tonic-gate 	sctp->sctp_nsaddrs++;
4917c478bd9Sstevel@tonic-gate 	return (0);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate static void
4957c478bd9Sstevel@tonic-gate sctp_ipif_hash_remove(sctp_t *sctp, sctp_ipif_t *ipif)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	int			cnt;
4987c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
499e35d2278Svi 	int			hindex;
500e35d2278Svi 
501e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
502e35d2278Svi 	    ipif->sctp_ipif_isv6);
503e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
504e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
505e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
506e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
507e35d2278Svi 			list_remove(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5087c478bd9Sstevel@tonic-gate 			    ipif_obj);
509e35d2278Svi 			sctp->sctp_saddrs[hindex].ipif_count--;
5107c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
5117c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
5127c478bd9Sstevel@tonic-gate 			kmem_free(ipif_obj, sizeof (sctp_saddr_ipif_t));
5137c478bd9Sstevel@tonic-gate 			break;
5147c478bd9Sstevel@tonic-gate 		}
515e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5167c478bd9Sstevel@tonic-gate 		    ipif_obj);
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static int
5217c478bd9Sstevel@tonic-gate sctp_compare_ipif_list(sctp_ipif_hash_t *list1, sctp_ipif_hash_t *list2)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	int			i;
5247c478bd9Sstevel@tonic-gate 	int			j;
5257c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj1;
5267c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj2;
5277c478bd9Sstevel@tonic-gate 	int			overlap = 0;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	obj1 = list_head(&list1->sctp_ipif_list);
5307c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
5317c478bd9Sstevel@tonic-gate 		obj2 = list_head(&list2->sctp_ipif_list);
5327c478bd9Sstevel@tonic-gate 		for (j = 0; j < list2->ipif_count; j++) {
533e35d2278Svi 			if (IN6_ARE_ADDR_EQUAL(
534e35d2278Svi 			    &obj1->saddr_ipifp->sctp_ipif_saddr,
535e35d2278Svi 			    &obj2->saddr_ipifp->sctp_ipif_saddr)) {
5367c478bd9Sstevel@tonic-gate 				overlap++;
5377c478bd9Sstevel@tonic-gate 				break;
5387c478bd9Sstevel@tonic-gate 			}
5397c478bd9Sstevel@tonic-gate 			obj2 = list_next(&list2->sctp_ipif_list,
5407c478bd9Sstevel@tonic-gate 			    obj2);
5417c478bd9Sstevel@tonic-gate 		}
5427c478bd9Sstevel@tonic-gate 		obj1 = list_next(&list1->sctp_ipif_list, obj1);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	return (overlap);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate int
5487c478bd9Sstevel@tonic-gate sctp_compare_saddrs(sctp_t *sctp1, sctp_t *sctp2)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	int		i;
5517c478bd9Sstevel@tonic-gate 	int		overlap = 0;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
5547c478bd9Sstevel@tonic-gate 		overlap += sctp_compare_ipif_list(&sctp1->sctp_saddrs[i],
5557c478bd9Sstevel@tonic-gate 		    &sctp2->sctp_saddrs[i]);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (sctp1->sctp_nsaddrs == sctp2->sctp_nsaddrs &&
5597c478bd9Sstevel@tonic-gate 	    overlap == sctp1->sctp_nsaddrs) {
5607c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_EQUAL);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if (overlap == sctp1->sctp_nsaddrs)
5647c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_SUBSET);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (overlap > 0)
5677c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_OVERLAP);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	return (SCTP_ADDR_DISJOINT);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate static int
5737c478bd9Sstevel@tonic-gate sctp_copy_ipifs(sctp_ipif_hash_t *list1, sctp_t *sctp2, int sleep)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	int			i;
5767c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
5777c478bd9Sstevel@tonic-gate 	int			error = 0;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	obj = list_head(&list1->sctp_ipif_list);
5807c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
5817c478bd9Sstevel@tonic-gate 		SCTP_IPIF_REFHOLD(obj->saddr_ipifp);
582f551bb10Svi 		error = sctp_ipif_hash_insert(sctp2, obj->saddr_ipifp, sleep,
583e35d2278Svi 		    B_FALSE, B_FALSE);
584e35d2278Svi 		ASSERT(error != EALREADY);
5857c478bd9Sstevel@tonic-gate 		if (error != 0)
5867c478bd9Sstevel@tonic-gate 			return (error);
5877c478bd9Sstevel@tonic-gate 		obj = list_next(&list1->sctp_ipif_list, obj);
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 	return (error);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate int
5937c478bd9Sstevel@tonic-gate sctp_dup_saddrs(sctp_t *sctp1, sctp_t *sctp2, int sleep)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	int	error = 0;
5967c478bd9Sstevel@tonic-gate 	int	i;
5977c478bd9Sstevel@tonic-gate 
598f551bb10Svi 	if (sctp1 == NULL || sctp1->sctp_bound_to_all == 1)
5997c478bd9Sstevel@tonic-gate 		return (sctp_get_all_ipifs(sctp2, sleep));
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
6027c478bd9Sstevel@tonic-gate 		if (sctp1->sctp_saddrs[i].ipif_count == 0)
6037c478bd9Sstevel@tonic-gate 			continue;
6047c478bd9Sstevel@tonic-gate 		error = sctp_copy_ipifs(&sctp1->sctp_saddrs[i], sctp2, sleep);
6057c478bd9Sstevel@tonic-gate 		if (error != 0) {
6067c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp2);
6077c478bd9Sstevel@tonic-gate 			return (error);
6087c478bd9Sstevel@tonic-gate 		}
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate void
6147c478bd9Sstevel@tonic-gate sctp_free_saddrs(sctp_t *sctp)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	int			i;
6177c478bd9Sstevel@tonic-gate 	int			l;
6187c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
6217c478bd9Sstevel@tonic-gate 		return;
6227c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
6237c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
6247c478bd9Sstevel@tonic-gate 			continue;
6257c478bd9Sstevel@tonic-gate 		obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6267c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
6277c478bd9Sstevel@tonic-gate 			list_remove(&sctp->sctp_saddrs[i].sctp_ipif_list, obj);
6287c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(obj->saddr_ipifp);
6297c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
6307c478bd9Sstevel@tonic-gate 			kmem_free(obj, sizeof (sctp_saddr_ipif_t));
6317c478bd9Sstevel@tonic-gate 			obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 		sctp->sctp_saddrs[i].ipif_count = 0;
6347c478bd9Sstevel@tonic-gate 	}
635f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
636f551bb10Svi 		sctp->sctp_bound_to_all = 0;
6377c478bd9Sstevel@tonic-gate 	ASSERT(sctp->sctp_nsaddrs == 0);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * Add/Delete the given ILL from the SCTP ILL list. Called with no locks
6427c478bd9Sstevel@tonic-gate  * held.
6437c478bd9Sstevel@tonic-gate  */
6447c478bd9Sstevel@tonic-gate void
6457c478bd9Sstevel@tonic-gate sctp_update_ill(ill_t *ill, int op)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	int		i;
6487c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill = NULL;
6497c478bd9Sstevel@tonic-gate 	uint_t		index;
650f4b3ec61Sdh 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
651f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
6527c478bd9Sstevel@tonic-gate 
653f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
656f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
657f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
658*1d19ca10Svi 		if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
659*1d19ca10Svi 		    (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
6607c478bd9Sstevel@tonic-gate 			break;
661*1d19ca10Svi 		}
662f4b3ec61Sdh 		sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
6637c478bd9Sstevel@tonic-gate 		    sctp_ill);
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	switch (op) {
6677c478bd9Sstevel@tonic-gate 	case SCTP_ILL_INSERT:
6687c478bd9Sstevel@tonic-gate 		if (sctp_ill != NULL) {
6697c478bd9Sstevel@tonic-gate 			/* Unmark it if it is condemned */
6707c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED)
6717c478bd9Sstevel@tonic-gate 				sctp_ill->sctp_ill_state = 0;
672f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
6737c478bd9Sstevel@tonic-gate 			return;
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 		sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
6767c478bd9Sstevel@tonic-gate 		/* Need to re-try? */
6777c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
678*1d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
679*1d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
680f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
6817c478bd9Sstevel@tonic-gate 			return;
6827c478bd9Sstevel@tonic-gate 		}
683e35d2278Svi 		sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
684e35d2278Svi 		    KM_NOSLEEP);
6857c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_name == NULL) {
686*1d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
687*1d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
6887c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
689f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
6907c478bd9Sstevel@tonic-gate 			return;
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 		bcopy(ill->ill_name, sctp_ill->sctp_ill_name,
6937c478bd9Sstevel@tonic-gate 		    ill->ill_name_length);
6947c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_name_length = ill->ill_name_length;
6957c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
6967c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
697f4b3ec61Sdh 		sctp_ill->sctp_ill_netstack = ns;	/* No netstack_hold */
698*1d19ca10Svi 		sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
699f4b3ec61Sdh 		list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
7007c478bd9Sstevel@tonic-gate 		    (void *)sctp_ill);
701f4b3ec61Sdh 		sctps->sctps_g_ills[index].ill_count++;
702f4b3ec61Sdh 		sctps->sctps_ills_count++;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 		break;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	case SCTP_ILL_REMOVE:
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
709f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7107c478bd9Sstevel@tonic-gate 			return;
7117c478bd9Sstevel@tonic-gate 		}
7127c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0) {
713f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[index].sctp_ill_list,
7147c478bd9Sstevel@tonic-gate 			    (void *)sctp_ill);
715f4b3ec61Sdh 			sctps->sctps_g_ills[index].ill_count--;
716f4b3ec61Sdh 			sctps->sctps_ills_count--;
7177c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
7187c478bd9Sstevel@tonic-gate 			    ill->ill_name_length);
7197c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
7207c478bd9Sstevel@tonic-gate 		} else {
7217c478bd9Sstevel@tonic-gate 			sctp_ill->sctp_ill_state = SCTP_ILLS_CONDEMNED;
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		break;
7257c478bd9Sstevel@tonic-gate 	}
726f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
729*1d19ca10Svi /*
730*1d19ca10Svi  * The ILL's index is being changed, just remove it from the old list,
731*1d19ca10Svi  * change the SCTP ILL's index and re-insert using the new index.
732*1d19ca10Svi  */
733*1d19ca10Svi void
734*1d19ca10Svi sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
735*1d19ca10Svi {
736*1d19ca10Svi 	sctp_ill_t	*sctp_ill = NULL;
737*1d19ca10Svi 	sctp_ill_t	*nxt_sill;
738*1d19ca10Svi 	uint_t		indx;
739*1d19ca10Svi 	uint_t		nindx;
740*1d19ca10Svi 	boolean_t	once = B_FALSE;
741*1d19ca10Svi 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
742*1d19ca10Svi 	sctp_stack_t	*sctps = ns->netstack_sctp;
743*1d19ca10Svi 
744*1d19ca10Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
745*1d19ca10Svi 
746*1d19ca10Svi 	indx = SCTP_ILL_HASH_FN(orig_ill_index);
747*1d19ca10Svi 	nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
748*1d19ca10Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
749*1d19ca10Svi 	while (sctp_ill != NULL) {
750*1d19ca10Svi 		nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
751*1d19ca10Svi 		    sctp_ill);
752*1d19ca10Svi 		if (sctp_ill->sctp_ill_index == orig_ill_index) {
753*1d19ca10Svi 			sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
754*1d19ca10Svi 			/*
755*1d19ca10Svi 			 * if the new index hashes to the same value, all's
756*1d19ca10Svi 			 * done.
757*1d19ca10Svi 			 */
758*1d19ca10Svi 			if (nindx != indx) {
759*1d19ca10Svi 				list_remove(
760*1d19ca10Svi 				    &sctps->sctps_g_ills[indx].sctp_ill_list,
761*1d19ca10Svi 				    (void *)sctp_ill);
762*1d19ca10Svi 				sctps->sctps_g_ills[indx].ill_count--;
763*1d19ca10Svi 				list_insert_tail(
764*1d19ca10Svi 				    &sctps->sctps_g_ills[nindx].sctp_ill_list,
765*1d19ca10Svi 				    (void *)sctp_ill);
766*1d19ca10Svi 				sctps->sctps_g_ills[nindx].ill_count++;
767*1d19ca10Svi 			}
768*1d19ca10Svi 			if (once)
769*1d19ca10Svi 				break;
770*1d19ca10Svi 			/* We might have one for v4 and for v6 */
771*1d19ca10Svi 			once = B_TRUE;
772*1d19ca10Svi 		}
773*1d19ca10Svi 		sctp_ill = nxt_sill;
774*1d19ca10Svi 	}
775*1d19ca10Svi 	rw_exit(&sctps->sctps_g_ills_lock);
776*1d19ca10Svi }
777*1d19ca10Svi 
7787c478bd9Sstevel@tonic-gate /* move ipif from f_ill to t_ill */
7797c478bd9Sstevel@tonic-gate void
7807c478bd9Sstevel@tonic-gate sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	sctp_ill_t	*fsctp_ill = NULL;
7837c478bd9Sstevel@tonic-gate 	sctp_ill_t	*tsctp_ill = NULL;
7847c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
785e35d2278Svi 	uint_t		hindex;
7867c478bd9Sstevel@tonic-gate 	int		i;
787f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
788f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
7897c478bd9Sstevel@tonic-gate 
790f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
791f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
7927c478bd9Sstevel@tonic-gate 
793e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
794e35d2278Svi 	fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
795e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
796*1d19ca10Svi 		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
797*1d19ca10Svi 		    fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
7987c478bd9Sstevel@tonic-gate 			break;
799*1d19ca10Svi 		}
800e35d2278Svi 		fsctp_ill = list_next(
801e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 
804e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
805e35d2278Svi 	tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
806e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
807*1d19ca10Svi 		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
808*1d19ca10Svi 		    tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
8097c478bd9Sstevel@tonic-gate 			break;
810*1d19ca10Svi 		}
811e35d2278Svi 		tsctp_ill = list_next(
812e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 
815e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
816e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
817e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
818e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
8197c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid)
8207c478bd9Sstevel@tonic-gate 			break;
821f4b3ec61Sdh 		sctp_ipif = list_next(
822e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 	/* Should be an ASSERT? */
8257c478bd9Sstevel@tonic-gate 	if (fsctp_ill == NULL || tsctp_ill == NULL || sctp_ipif == NULL) {
8267c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_move_ipif: error moving ipif %p from %p to %p\n",
8277c478bd9Sstevel@tonic-gate 		    (void *)ipif, (void *)f_ill, (void *)t_ill));
828f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
829f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
8307c478bd9Sstevel@tonic-gate 		return;
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 	rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
8337c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ipif->sctp_ipif_ill == fsctp_ill);
8347c478bd9Sstevel@tonic-gate 	sctp_ipif->sctp_ipif_ill = tsctp_ill;
8357c478bd9Sstevel@tonic-gate 	rw_exit(&sctp_ipif->sctp_ipif_lock);
8367c478bd9Sstevel@tonic-gate 	(void) atomic_add_32_nv(&fsctp_ill->sctp_ill_ipifcnt, -1);
8377c478bd9Sstevel@tonic-gate 	atomic_add_32(&tsctp_ill->sctp_ill_ipifcnt, 1);
838f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
839f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
842e35d2278Svi /*
843e35d2278Svi  * Walk the list of SCTPs and find each that has oipif in it's saddr list, and
844e35d2278Svi  * if so replace it with nipif.
845e35d2278Svi  */
846e35d2278Svi void
847e35d2278Svi sctp_update_saddrs(sctp_ipif_t *oipif, sctp_ipif_t *nipif, int idx,
848e35d2278Svi     sctp_stack_t *sctps)
849e35d2278Svi {
850e35d2278Svi 	sctp_t			*sctp;
851e35d2278Svi 	sctp_t			*sctp_prev = NULL;
852e35d2278Svi 	sctp_saddr_ipif_t	*sobj;
853e35d2278Svi 	int			count;
854e35d2278Svi 
855e35d2278Svi 	sctp = sctps->sctps_gsctp;
856e35d2278Svi 	mutex_enter(&sctps->sctps_g_lock);
857e35d2278Svi 	while (sctp != NULL && oipif->sctp_ipif_refcnt > 0) {
858e35d2278Svi 		mutex_enter(&sctp->sctp_reflock);
859e35d2278Svi 		if (sctp->sctp_condemned ||
860e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count <= 0) {
861e35d2278Svi 			mutex_exit(&sctp->sctp_reflock);
862e35d2278Svi 			sctp = list_next(&sctps->sctps_g_list, sctp);
863e35d2278Svi 			continue;
864e35d2278Svi 		}
865e35d2278Svi 		sctp->sctp_refcnt++;
866e35d2278Svi 		mutex_exit(&sctp->sctp_reflock);
867e35d2278Svi 		mutex_exit(&sctps->sctps_g_lock);
868e35d2278Svi 		if (sctp_prev != NULL)
869e35d2278Svi 			SCTP_REFRELE(sctp_prev);
870e35d2278Svi 
871e35d2278Svi 		RUN_SCTP(sctp);
872e35d2278Svi 		sobj = list_head(&sctp->sctp_saddrs[idx].sctp_ipif_list);
873e35d2278Svi 		for (count = 0; count <
874e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count; count++) {
875e35d2278Svi 			if (sobj->saddr_ipifp == oipif) {
876e35d2278Svi 				SCTP_IPIF_REFHOLD(nipif);
877e35d2278Svi 				sobj->saddr_ipifp = nipif;
878e35d2278Svi 				ASSERT(oipif->sctp_ipif_refcnt > 0);
879e35d2278Svi 				/* We have the writer lock */
880e35d2278Svi 				oipif->sctp_ipif_refcnt--;
881e35d2278Svi 				/*
882e35d2278Svi 				 * Can't have more than one referring
883e35d2278Svi 				 * to the same sctp_ipif.
884e35d2278Svi 				 */
885e35d2278Svi 				break;
886e35d2278Svi 			}
887e35d2278Svi 			sobj = list_next(&sctp->sctp_saddrs[idx].sctp_ipif_list,
888e35d2278Svi 			    sobj);
889e35d2278Svi 		}
890e35d2278Svi 		WAKE_SCTP(sctp);
891e35d2278Svi 		sctp_prev = sctp;
892e35d2278Svi 		mutex_enter(&sctps->sctps_g_lock);
893e35d2278Svi 		sctp = list_next(&sctps->sctps_g_list, sctp);
894e35d2278Svi 	}
895e35d2278Svi 	mutex_exit(&sctps->sctps_g_lock);
896e35d2278Svi 	if (sctp_prev != NULL)
897e35d2278Svi 		SCTP_REFRELE(sctp_prev);
898e35d2278Svi }
899e35d2278Svi 
900e35d2278Svi /*
901e35d2278Svi  * Given an ipif, walk the hash list in the global ipif table and for
902e35d2278Svi  * any other SCTP ipif with the same address and non-zero reference, walk
903e35d2278Svi  * the SCTP list and update the saddr list, if required, to point to the
904e35d2278Svi  * new SCTP ipif.
905e35d2278Svi  */
906e35d2278Svi void
907e35d2278Svi sctp_chk_and_updt_saddr(int hindex, sctp_ipif_t *ipif, sctp_stack_t *sctps)
908e35d2278Svi {
909e35d2278Svi 	int		cnt;
910e35d2278Svi 	sctp_ipif_t	*sipif;
911e35d2278Svi 
912e35d2278Svi 	ASSERT(sctps->sctps_g_ipifs[hindex].ipif_count > 0);
913e35d2278Svi 	ASSERT(ipif->sctp_ipif_state == SCTP_IPIFS_UP);
914e35d2278Svi 
915e35d2278Svi 	sipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
916e35d2278Svi 	for (cnt = 0; cnt < sctps->sctps_g_ipifs[hindex].ipif_count; cnt++) {
917e35d2278Svi 		rw_enter(&sipif->sctp_ipif_lock, RW_WRITER);
918e35d2278Svi 		if (sipif->sctp_ipif_id != ipif->sctp_ipif_id &&
919e35d2278Svi 		    IN6_ARE_ADDR_EQUAL(&sipif->sctp_ipif_saddr,
920e35d2278Svi 		    &ipif->sctp_ipif_saddr) && sipif->sctp_ipif_refcnt > 0) {
921e35d2278Svi 			/*
922e35d2278Svi 			 * There can only be one address up at any time
923e35d2278Svi 			 * and we are here because ipif has been brought
924e35d2278Svi 			 * up.
925e35d2278Svi 			 */
926e35d2278Svi 			ASSERT(sipif->sctp_ipif_state != SCTP_IPIFS_UP);
927e35d2278Svi 			/*
928e35d2278Svi 			 * Someone has a reference to this we need to update to
929e35d2278Svi 			 * point to the new sipif.
930e35d2278Svi 			 */
931e35d2278Svi 			sctp_update_saddrs(sipif, ipif, hindex, sctps);
932e35d2278Svi 		}
933e35d2278Svi 		rw_exit(&sipif->sctp_ipif_lock);
934e35d2278Svi 		sipif = list_next(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
935e35d2278Svi 		    sipif);
936e35d2278Svi 	}
937e35d2278Svi }
938e35d2278Svi 
939e35d2278Svi /*
940e35d2278Svi  * Insert a new SCTP ipif using 'ipif'. v6addr is the address that existed
941e35d2278Svi  * prior to the current address in 'ipif'. Only when an existing address
942e35d2278Svi  * is changed on an IPIF, will v6addr be specified. If the IPIF already
943e35d2278Svi  * exists in the global SCTP ipif table, then we either removed it, if
944e35d2278Svi  * it doesn't have any existing reference, or mark it condemned otherwise.
945e35d2278Svi  * If an address is being brought up (IPIF_UP), then we need to scan
946e35d2278Svi  * the SCTP list to check if there is any SCTP that points to the *same*
947e35d2278Svi  * address on a different SCTP ipif and update in that case.
948e35d2278Svi  */
949e35d2278Svi void
950e35d2278Svi sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
951e35d2278Svi {
952e35d2278Svi 	ill_t		*ill = ipif->ipif_ill;
953e35d2278Svi 	int		i;
954e35d2278Svi 	sctp_ill_t	*sctp_ill;
955e35d2278Svi 	sctp_ill_t	*osctp_ill;
956e35d2278Svi 	sctp_ipif_t	*sctp_ipif = NULL;
957e35d2278Svi 	sctp_ipif_t	*osctp_ipif = NULL;
958e35d2278Svi 	uint_t		ill_index;
959e35d2278Svi 	int		hindex;
960e35d2278Svi 	sctp_stack_t	*sctps;
961e35d2278Svi 
962e35d2278Svi 
963e35d2278Svi 	sctps = ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp;
964e35d2278Svi 
965e35d2278Svi 	/* Index for new address */
966e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr, ill->ill_isv6);
967e35d2278Svi 
968e35d2278Svi 	/*
969e35d2278Svi 	 * The address on this IPIF is changing, we need to look for
970e35d2278Svi 	 * this old address and mark it condemned, before creating
971e35d2278Svi 	 * one for the new address.
972e35d2278Svi 	 */
973e35d2278Svi 	osctp_ipif = sctp_lookup_ipif_addr(&v6addr, B_FALSE,
974e35d2278Svi 	    ipif->ipif_zoneid, B_TRUE, SCTP_ILL_TO_PHYINDEX(ill),
975e35d2278Svi 	    ipif->ipif_seqid, B_FALSE, sctps);
976e35d2278Svi 
977e35d2278Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
978e35d2278Svi 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
979e35d2278Svi 
980e35d2278Svi 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
981e35d2278Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
982e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
983*1d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
984*1d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
985e35d2278Svi 			break;
986*1d19ca10Svi 		}
987e35d2278Svi 		sctp_ill = list_next(
988e35d2278Svi 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
989e35d2278Svi 	}
990e35d2278Svi 
991e35d2278Svi 	if (sctp_ill == NULL) {
992*1d19ca10Svi 		ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
993e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
994e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
995*1d19ca10Svi 		return;
996e35d2278Svi 	}
997e35d2278Svi 
998e35d2278Svi 	if (osctp_ipif != NULL) {
999e35d2278Svi 
1000e35d2278Svi 		/* The address is the same? */
1001e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &v6addr)) {
1002e35d2278Svi 			boolean_t	chk_n_updt = B_FALSE;
1003e35d2278Svi 
1004e35d2278Svi 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
1005e35d2278Svi 			rw_enter(&osctp_ipif->sctp_ipif_lock, RW_WRITER);
1006e35d2278Svi 			if (ipif->ipif_flags & IPIF_UP &&
1007e35d2278Svi 			    osctp_ipif->sctp_ipif_state != SCTP_IPIFS_UP) {
1008e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1009e35d2278Svi 				chk_n_updt = B_TRUE;
1010e35d2278Svi 			} else {
1011e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1012e35d2278Svi 			}
1013e35d2278Svi 			osctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1014e35d2278Svi 			rw_exit(&osctp_ipif->sctp_ipif_lock);
1015e35d2278Svi 			if (chk_n_updt) {
1016e35d2278Svi 				sctp_chk_and_updt_saddr(hindex, osctp_ipif,
1017e35d2278Svi 				    sctps);
1018e35d2278Svi 			}
1019e35d2278Svi 			rw_exit(&sctps->sctps_g_ipifs_lock);
1020e35d2278Svi 			rw_exit(&sctps->sctps_g_ills_lock);
1021e35d2278Svi 			return;
1022e35d2278Svi 		}
1023e35d2278Svi 		/*
1024e35d2278Svi 		 * We are effectively removing this address from the ILL.
1025e35d2278Svi 		 */
1026e35d2278Svi 		if (osctp_ipif->sctp_ipif_refcnt != 0) {
1027e35d2278Svi 			osctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1028e35d2278Svi 		} else {
1029e35d2278Svi 			list_t		*ipif_list;
1030e35d2278Svi 			int		ohindex;
1031e35d2278Svi 
1032e35d2278Svi 			osctp_ill = osctp_ipif->sctp_ipif_ill;
1033e35d2278Svi 			/* hash index for the old one */
1034e35d2278Svi 			ohindex = SCTP_IPIF_ADDR_HASH(
1035e35d2278Svi 			    osctp_ipif->sctp_ipif_saddr,
1036e35d2278Svi 			    osctp_ipif->sctp_ipif_isv6);
1037e35d2278Svi 
1038e35d2278Svi 			ipif_list =
1039e35d2278Svi 			    &sctps->sctps_g_ipifs[ohindex].sctp_ipif_list;
1040e35d2278Svi 
1041e35d2278Svi 			list_remove(ipif_list, (void *)osctp_ipif);
1042e35d2278Svi 			sctps->sctps_g_ipifs[ohindex].ipif_count--;
1043e35d2278Svi 			sctps->sctps_g_ipifs_count--;
1044e35d2278Svi 			rw_destroy(&osctp_ipif->sctp_ipif_lock);
1045e35d2278Svi 			kmem_free(osctp_ipif, sizeof (sctp_ipif_t));
1046e35d2278Svi 			(void) atomic_add_32_nv(&osctp_ill->sctp_ill_ipifcnt,
1047e35d2278Svi 			    -1);
1048e35d2278Svi 		}
1049e35d2278Svi 	}
1050e35d2278Svi 
1051e35d2278Svi 	sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
1052e35d2278Svi 	/* Try again? */
1053e35d2278Svi 	if (sctp_ipif == NULL) {
1054*1d19ca10Svi 		cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
1055*1d19ca10Svi 		    "IPIF %p to SCTP's IPIF list", (void *)ipif);
1056e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1057e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
1058e35d2278Svi 		return;
1059e35d2278Svi 	}
1060e35d2278Svi 	sctps->sctps_g_ipifs_count++;
1061e35d2278Svi 	rw_init(&sctp_ipif->sctp_ipif_lock, NULL, RW_DEFAULT, NULL);
1062e35d2278Svi 	sctp_ipif->sctp_ipif_saddr = ipif->ipif_v6lcl_addr;
1063e35d2278Svi 	sctp_ipif->sctp_ipif_ill = sctp_ill;
1064e35d2278Svi 	sctp_ipif->sctp_ipif_isv6 = ill->ill_isv6;
1065e35d2278Svi 	sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1066e35d2278Svi 	sctp_ipif->sctp_ipif_id = ipif->ipif_seqid;
1067e35d2278Svi 	if (ipif->ipif_flags & IPIF_UP)
1068e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1069e35d2278Svi 	else
1070e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1071e35d2278Svi 	sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1072e35d2278Svi 	/*
1073e35d2278Svi 	 * We add it to the head so that it is quicker to find good/recent
1074e35d2278Svi 	 * additions.
1075e35d2278Svi 	 */
1076e35d2278Svi 	list_insert_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
1077e35d2278Svi 	    (void *)sctp_ipif);
1078e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count++;
1079e35d2278Svi 	atomic_add_32(&sctp_ill->sctp_ill_ipifcnt, 1);
1080e35d2278Svi 	if (sctp_ipif->sctp_ipif_state == SCTP_IPIFS_UP)
1081e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif, sctps);
1082e35d2278Svi 	rw_exit(&sctps->sctps_g_ipifs_lock);
1083e35d2278Svi 	rw_exit(&sctps->sctps_g_ills_lock);
1084e35d2278Svi }
1085e35d2278Svi 
10867c478bd9Sstevel@tonic-gate /* Insert, Remove,  Mark up or Mark down the ipif */
10877c478bd9Sstevel@tonic-gate void
10887c478bd9Sstevel@tonic-gate sctp_update_ipif(ipif_t *ipif, int op)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	ill_t		*ill = ipif->ipif_ill;
10917c478bd9Sstevel@tonic-gate 	int		i;
10927c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
10937c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
10947c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
1095e35d2278Svi 	uint_t		hindex;
1096f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
1097f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	ip2dbg(("sctp_update_ipif: %s %d\n", ill->ill_name, ipif->ipif_seqid));
11007c478bd9Sstevel@tonic-gate 
1101f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1102f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1105f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1106f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
1107*1d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
1108*1d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
11097c478bd9Sstevel@tonic-gate 			break;
1110*1d19ca10Svi 		}
1111f4b3ec61Sdh 		sctp_ill = list_next(
1112f4b3ec61Sdh 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 	if (sctp_ill == NULL) {
1115f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1116f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11177c478bd9Sstevel@tonic-gate 		return;
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 
1120e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
1121e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
1122e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
1123e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
1124e35d2278Svi 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid) {
1125e35d2278Svi 			ASSERT(IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
1126e35d2278Svi 			    &ipif->ipif_v6lcl_addr));
11277c478bd9Sstevel@tonic-gate 			break;
1128e35d2278Svi 		}
1129f4b3ec61Sdh 		sctp_ipif = list_next(
1130e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11317c478bd9Sstevel@tonic-gate 		    sctp_ipif);
11327c478bd9Sstevel@tonic-gate 	}
1133e35d2278Svi 	if (sctp_ipif == NULL) {
11347c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_update_ipif: null sctp_ipif for %d\n", op));
1135f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1136f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11377c478bd9Sstevel@tonic-gate 		return;
11387c478bd9Sstevel@tonic-gate 	}
1139e35d2278Svi 	ASSERT(sctp_ill == sctp_ipif->sctp_ipif_ill);
11407c478bd9Sstevel@tonic-gate 	switch (op) {
11417c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_REMOVE:
11427c478bd9Sstevel@tonic-gate 	{
11437c478bd9Sstevel@tonic-gate 		list_t		*ipif_list;
11447c478bd9Sstevel@tonic-gate 		list_t		*ill_list;
11457c478bd9Sstevel@tonic-gate 
1146f4b3ec61Sdh 		ill_list = &sctps->sctps_g_ills[ill_index].sctp_ill_list;
1147e35d2278Svi 		ipif_list = &sctps->sctps_g_ipifs[hindex].sctp_ipif_list;
11487c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_refcnt != 0) {
11497c478bd9Sstevel@tonic-gate 			sctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1150f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ipifs_lock);
1151f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
11527c478bd9Sstevel@tonic-gate 			return;
11537c478bd9Sstevel@tonic-gate 		}
11547c478bd9Sstevel@tonic-gate 		list_remove(ipif_list, (void *)sctp_ipif);
1155e35d2278Svi 		sctps->sctps_g_ipifs[hindex].ipif_count--;
1156f4b3ec61Sdh 		sctps->sctps_g_ipifs_count--;
11577c478bd9Sstevel@tonic-gate 		rw_destroy(&sctp_ipif->sctp_ipif_lock);
11587c478bd9Sstevel@tonic-gate 		kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
11597c478bd9Sstevel@tonic-gate 		(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
1160f4b3ec61Sdh 		if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
1161f4b3ec61Sdh 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
11627c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_ipifcnt == 0 &&
11637c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
11647c478bd9Sstevel@tonic-gate 				list_remove(ill_list, (void *)sctp_ill);
1165f4b3ec61Sdh 				sctps->sctps_ills_count--;
1166f4b3ec61Sdh 				sctps->sctps_g_ills[ill_index].ill_count--;
11677c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill->sctp_ill_name,
11687c478bd9Sstevel@tonic-gate 				    sctp_ill->sctp_ill_name_length);
11697c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill, sizeof (sctp_ill_t));
11707c478bd9Sstevel@tonic-gate 			}
11717c478bd9Sstevel@tonic-gate 		}
11727c478bd9Sstevel@tonic-gate 		break;
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UP:
11767c478bd9Sstevel@tonic-gate 
1177f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
11787c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
11797c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1180f551bb10Svi 		sctp_ipif->sctp_ipif_mtu = ipif->ipif_mtu;
1181e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
11827c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
1183e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif,
1184e35d2278Svi 		    ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		break;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UPDATE:
11897c478bd9Sstevel@tonic-gate 
1190f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
11917c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
11927c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_mtu = ipif->ipif_mtu;
11937c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1194f551bb10Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
11957c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 		break;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_DOWN:
12007c478bd9Sstevel@tonic-gate 
1201f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12027c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12037c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1204e35d2278Svi 		sctp_ipif->sctp_ipif_mtu = ipif->ipif_mtu;
1205e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12067c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 		break;
12097c478bd9Sstevel@tonic-gate 	}
1210f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
1211f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate /*
12157c478bd9Sstevel@tonic-gate  * SCTP source address list manipulaton, locking not used (except for
12167c478bd9Sstevel@tonic-gate  * sctp locking by the caller.
12177c478bd9Sstevel@tonic-gate  */
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate /* Remove a specific saddr from the list */
12207c478bd9Sstevel@tonic-gate void
12217c478bd9Sstevel@tonic-gate sctp_del_saddr(sctp_t *sctp, sctp_saddr_ipif_t *sp)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12247c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12277c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	sctp_ipif_hash_remove(sctp, sp->saddr_ipifp);
12307c478bd9Sstevel@tonic-gate 
1231f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
12327c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12357c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12387c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate /*
12427c478bd9Sstevel@tonic-gate  * Delete source address from the existing list. No error checking done here
12437c478bd9Sstevel@tonic-gate  * Called with no locks held.
12447c478bd9Sstevel@tonic-gate  */
12457c478bd9Sstevel@tonic-gate void
12467c478bd9Sstevel@tonic-gate sctp_del_saddr_list(sctp_t *sctp, const void *addrs, int addcnt,
12477c478bd9Sstevel@tonic-gate     boolean_t fanout_locked)
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
12507c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
12517c478bd9Sstevel@tonic-gate 	int			cnt;
12527c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
12537c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
12541d8c4025Svi 	int			ifindex = 0;
12557c478bd9Sstevel@tonic-gate 
12561d8c4025Svi 	ASSERT(sctp->sctp_nsaddrs >= addcnt);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
12597c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
12607c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12617c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
12627c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addcnt; cnt++) {
12667c478bd9Sstevel@tonic-gate 		switch (sctp->sctp_family) {
12677c478bd9Sstevel@tonic-gate 		case AF_INET:
12687c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
12697c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &addr);
12707c478bd9Sstevel@tonic-gate 			break;
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 		case AF_INET6:
12737c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
12747c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
12751d8c4025Svi 			ifindex = sin6->sin6_scope_id;
12767c478bd9Sstevel@tonic-gate 			break;
12777c478bd9Sstevel@tonic-gate 		}
1278e35d2278Svi 		sctp_ipif = sctp_lookup_ipif_addr(&addr, B_FALSE,
1279e35d2278Svi 		    sctp->sctp_zoneid, !sctp->sctp_connp->conn_allzones,
1280e35d2278Svi 		    ifindex, 0, B_TRUE, sctp->sctp_sctps);
12817c478bd9Sstevel@tonic-gate 		ASSERT(sctp_ipif != NULL);
12827c478bd9Sstevel@tonic-gate 		sctp_ipif_hash_remove(sctp, sctp_ipif);
12837c478bd9Sstevel@tonic-gate 	}
1284f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
12857c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
12887c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
12897c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12907c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
12917c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12927c478bd9Sstevel@tonic-gate 	}
12937c478bd9Sstevel@tonic-gate }
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate /*
12967c478bd9Sstevel@tonic-gate  * Given an address get the corresponding entry from the list
12977c478bd9Sstevel@tonic-gate  * Called with no locks held.
12987c478bd9Sstevel@tonic-gate  */
12997c478bd9Sstevel@tonic-gate sctp_saddr_ipif_t *
13001d8c4025Svi sctp_saddr_lookup(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
13017c478bd9Sstevel@tonic-gate {
1302e35d2278Svi 	int			cnt;
1303e35d2278Svi 	sctp_saddr_ipif_t	*ipif_obj;
1304e35d2278Svi 	int			hindex;
13057c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13067c478bd9Sstevel@tonic-gate 
1307e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1308e35d2278Svi 	if (sctp->sctp_saddrs[hindex].ipif_count == 0)
13097c478bd9Sstevel@tonic-gate 		return (NULL);
13107c478bd9Sstevel@tonic-gate 
1311e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
1312e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
1313e35d2278Svi 		sctp_ipif = ipif_obj->saddr_ipifp;
1314e35d2278Svi 		/*
1315e35d2278Svi 		 * Zone check shouldn't be needed.
1316e35d2278Svi 		 */
1317e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(addr, &sctp_ipif->sctp_ipif_saddr) &&
1318e35d2278Svi 		    (ifindex == 0 ||
1319e35d2278Svi 		    ifindex == sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
1320e35d2278Svi 		    SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state)) {
1321e35d2278Svi 			return (ipif_obj);
1322e35d2278Svi 		}
1323e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
1324e35d2278Svi 		    ipif_obj);
1325e35d2278Svi 	}
1326e35d2278Svi 	return (NULL);
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate 
1329f551bb10Svi /* Given an address, add it to the source address list */
1330f551bb10Svi int
13311d8c4025Svi sctp_saddr_add_addr(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
1332f551bb10Svi {
1333f551bb10Svi 	sctp_ipif_t		*sctp_ipif;
1334f551bb10Svi 
1335e35d2278Svi 	sctp_ipif = sctp_lookup_ipif_addr(addr, B_TRUE, sctp->sctp_zoneid,
1336e35d2278Svi 	    !sctp->sctp_connp->conn_allzones, ifindex, 0, B_TRUE,
1337e35d2278Svi 	    sctp->sctp_sctps);
1338f551bb10Svi 	if (sctp_ipif == NULL)
1339f551bb10Svi 		return (EINVAL);
1340f551bb10Svi 
1341e35d2278Svi 	if (sctp_ipif_hash_insert(sctp, sctp_ipif, KM_NOSLEEP, B_FALSE,
1342e35d2278Svi 	    B_FALSE) != 0) {
1343f551bb10Svi 		SCTP_IPIF_REFRELE(sctp_ipif);
1344f551bb10Svi 		return (EINVAL);
1345f551bb10Svi 	}
1346f551bb10Svi 	return (0);
1347f551bb10Svi }
1348f551bb10Svi 
1349f551bb10Svi /*
1350f551bb10Svi  * Remove or mark as dontsrc addresses that are currently not part of the
1351f551bb10Svi  * association. One would delete addresses when processing an INIT and
1352f551bb10Svi  * mark as dontsrc when processing an INIT-ACK.
1353f551bb10Svi  */
1354f551bb10Svi void
1355f551bb10Svi sctp_check_saddr(sctp_t *sctp, int supp_af, boolean_t delete)
1356f551bb10Svi {
1357f551bb10Svi 	int			i;
1358f551bb10Svi 	int			l;
1359f551bb10Svi 	sctp_saddr_ipif_t	*obj;
1360f551bb10Svi 	int			scanned = 0;
1361f551bb10Svi 	int			naddr;
1362f551bb10Svi 	int			nsaddr;
1363f551bb10Svi 
1364f551bb10Svi 	ASSERT(!sctp->sctp_loopback && !sctp->sctp_linklocal && supp_af != 0);
1365f551bb10Svi 
1366f551bb10Svi 	/*
1367f551bb10Svi 	 * Irregardless of the supported address in the INIT, v4
1368f551bb10Svi 	 * must be supported.
1369f551bb10Svi 	 */
1370f551bb10Svi 	if (sctp->sctp_family == AF_INET)
1371f551bb10Svi 		supp_af = PARM_SUPP_V4;
1372f551bb10Svi 
1373f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
1374f551bb10Svi 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1375f551bb10Svi 		if (sctp->sctp_saddrs[i].ipif_count == 0)
1376f551bb10Svi 			continue;
1377f551bb10Svi 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1378f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1379f551bb10Svi 		for (l = 0; l < naddr; l++) {
1380f551bb10Svi 			sctp_ipif_t	*ipif;
1381f551bb10Svi 
1382f551bb10Svi 			ipif = obj->saddr_ipifp;
1383f551bb10Svi 			scanned++;
1384f551bb10Svi 
1385f551bb10Svi 			/*
1386f551bb10Svi 			 * Delete/mark dontsrc loopback/linklocal addresses and
1387f551bb10Svi 			 * unsupported address.
13881d8c4025Svi 			 * On a clustered node, we trust the clustering module
13891d8c4025Svi 			 * to do the right thing w.r.t loopback addresses, so
13901d8c4025Svi 			 * we ignore loopback addresses in this check.
1391f551bb10Svi 			 */
13921d8c4025Svi 			if ((SCTP_IS_IPIF_LOOPBACK(ipif) &&
13931d8c4025Svi 			    cl_sctp_check_addrs == NULL) ||
13941d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(ipif) ||
1395f551bb10Svi 			    SCTP_UNSUPP_AF(ipif, supp_af)) {
1396f551bb10Svi 				if (!delete) {
1397f551bb10Svi 					obj->saddr_ipif_unconfirmed = 1;
1398f551bb10Svi 					goto next_obj;
1399f551bb10Svi 				}
1400f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1401f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1402f551bb10Svi 				if (scanned < nsaddr) {
1403f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1404f551bb10Svi 					    sctp_ipif_list, obj);
1405f551bb10Svi 					sctp_ipif_hash_remove(sctp, ipif);
1406f551bb10Svi 					continue;
1407f551bb10Svi 				}
1408f551bb10Svi 				sctp_ipif_hash_remove(sctp, ipif);
1409f551bb10Svi 			}
1410f551bb10Svi 	next_obj:
1411f551bb10Svi 			if (scanned >= nsaddr)
1412f551bb10Svi 				return;
1413f551bb10Svi 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
1414f551bb10Svi 			    obj);
1415f551bb10Svi 		}
1416f551bb10Svi 	}
1417f551bb10Svi }
1418f551bb10Svi 
1419f551bb10Svi 
14207c478bd9Sstevel@tonic-gate /* Get the first valid address from the list. Called with no locks held */
14217c478bd9Sstevel@tonic-gate in6_addr_t
14227c478bd9Sstevel@tonic-gate sctp_get_valid_addr(sctp_t *sctp, boolean_t isv6)
14237c478bd9Sstevel@tonic-gate {
14247c478bd9Sstevel@tonic-gate 	int			i;
14257c478bd9Sstevel@tonic-gate 	int			l;
14267c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
14277c478bd9Sstevel@tonic-gate 	int			scanned = 0;
14287c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
14317c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
14327c478bd9Sstevel@tonic-gate 			continue;
14337c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
14347c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
14357c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
1438f551bb10Svi 			if (!SCTP_DONT_SRC(obj) &&
14397c478bd9Sstevel@tonic-gate 			    ipif->sctp_ipif_isv6 == isv6 &&
1440f551bb10Svi 			    ipif->sctp_ipif_state == SCTP_IPIFS_UP) {
14417c478bd9Sstevel@tonic-gate 				return (ipif->sctp_ipif_saddr);
14427c478bd9Sstevel@tonic-gate 			}
14437c478bd9Sstevel@tonic-gate 			scanned++;
14447c478bd9Sstevel@tonic-gate 			if (scanned >= sctp->sctp_nsaddrs)
14457c478bd9Sstevel@tonic-gate 				goto got_none;
14467c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
14477c478bd9Sstevel@tonic-gate 			    obj);
14487c478bd9Sstevel@tonic-gate 		}
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate got_none:
14517c478bd9Sstevel@tonic-gate 	/* Need to double check this */
14527c478bd9Sstevel@tonic-gate 	if (isv6 == B_TRUE)
14537c478bd9Sstevel@tonic-gate 		addr =  ipv6_all_zeros;
14547c478bd9Sstevel@tonic-gate 	else
14557c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(0, &addr);
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	return (addr);
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate /*
14617c478bd9Sstevel@tonic-gate  * Return the list of local addresses of an association.  The parameter
14627c478bd9Sstevel@tonic-gate  * myaddrs is supposed to be either (struct sockaddr_in *) or (struct
14637c478bd9Sstevel@tonic-gate  * sockaddr_in6 *) depending on the address family.
14647c478bd9Sstevel@tonic-gate  */
14657c478bd9Sstevel@tonic-gate int
14667c478bd9Sstevel@tonic-gate sctp_getmyaddrs(void *conn, void *myaddrs, int *addrcnt)
14677c478bd9Sstevel@tonic-gate {
14687c478bd9Sstevel@tonic-gate 	int			i;
14697c478bd9Sstevel@tonic-gate 	int			l;
14707c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
14717c478bd9Sstevel@tonic-gate 	sctp_t			*sctp = (sctp_t *)conn;
14727c478bd9Sstevel@tonic-gate 	int			family = sctp->sctp_family;
14737c478bd9Sstevel@tonic-gate 	int			max = *addrcnt;
14747c478bd9Sstevel@tonic-gate 	size_t			added = 0;
14757c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
14767c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
14777c478bd9Sstevel@tonic-gate 	int			scanned = 0;
14787c478bd9Sstevel@tonic-gate 	boolean_t		skip_lback = B_FALSE;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
14817c478bd9Sstevel@tonic-gate 		return (EINVAL);
14827c478bd9Sstevel@tonic-gate 
14831d8c4025Svi 	/*
14841d8c4025Svi 	 * Skip loopback addresses for non-loopback assoc., ignore
14851d8c4025Svi 	 * this on a clustered node.
14861d8c4025Svi 	 */
14871d8c4025Svi 	if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback &&
14881d8c4025Svi 	    (cl_sctp_check_addrs == NULL)) {
14897c478bd9Sstevel@tonic-gate 		skip_lback = B_TRUE;
14901d8c4025Svi 	}
14911d8c4025Svi 
14927c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
14937c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
14947c478bd9Sstevel@tonic-gate 			continue;
14957c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
14967c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
14977c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif = obj->saddr_ipifp;
14987c478bd9Sstevel@tonic-gate 			in6_addr_t	addr = ipif->sctp_ipif_saddr;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 			scanned++;
15017c478bd9Sstevel@tonic-gate 			if ((ipif->sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
1502f551bb10Svi 			    SCTP_DONT_SRC(obj) ||
15031d8c4025Svi 			    (SCTP_IS_IPIF_LOOPBACK(ipif) && skip_lback)) {
15047c478bd9Sstevel@tonic-gate 				if (scanned >= sctp->sctp_nsaddrs)
15057c478bd9Sstevel@tonic-gate 					goto done;
15067c478bd9Sstevel@tonic-gate 				obj = list_next(&sctp->sctp_saddrs[i].
15077c478bd9Sstevel@tonic-gate 				    sctp_ipif_list, obj);
15087c478bd9Sstevel@tonic-gate 				continue;
15097c478bd9Sstevel@tonic-gate 			}
15107c478bd9Sstevel@tonic-gate 			switch (family) {
15117c478bd9Sstevel@tonic-gate 			case AF_INET:
15127c478bd9Sstevel@tonic-gate 				sin4 = (struct sockaddr_in *)myaddrs + added;
15137c478bd9Sstevel@tonic-gate 				sin4->sin_family = AF_INET;
15147c478bd9Sstevel@tonic-gate 				sin4->sin_port = sctp->sctp_lport;
15157c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
15167c478bd9Sstevel@tonic-gate 				break;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 			case AF_INET6:
15197c478bd9Sstevel@tonic-gate 				sin6 = (struct sockaddr_in6 *)myaddrs + added;
15207c478bd9Sstevel@tonic-gate 				sin6->sin6_family = AF_INET6;
15217c478bd9Sstevel@tonic-gate 				sin6->sin6_port = sctp->sctp_lport;
15227c478bd9Sstevel@tonic-gate 				sin6->sin6_addr = addr;
15237c478bd9Sstevel@tonic-gate 				break;
15247c478bd9Sstevel@tonic-gate 			}
15257c478bd9Sstevel@tonic-gate 			added++;
15267c478bd9Sstevel@tonic-gate 			if (added >= max || scanned >= sctp->sctp_nsaddrs)
15277c478bd9Sstevel@tonic-gate 				goto done;
15287c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
15297c478bd9Sstevel@tonic-gate 			    obj);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 	}
15327c478bd9Sstevel@tonic-gate done:
15337c478bd9Sstevel@tonic-gate 	*addrcnt = added;
15347c478bd9Sstevel@tonic-gate 	return (0);
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate /*
1538df19b344Svi  * Given the supported address family, walk through the source address list
1539df19b344Svi  * and return the total length of the available addresses. If 'p' is not
1540df19b344Svi  * null, construct the parameter list for the addresses in 'p'.
1541f551bb10Svi  * 'modify' will only be set when we want the source address list to
1542f551bb10Svi  * be modified. The source address list will be modified only when
1543f551bb10Svi  * generating an INIT chunk. For generating an INIT-ACK 'modify' will
1544f551bb10Svi  * be false since the 'sctp' will be that of the listener.
15457c478bd9Sstevel@tonic-gate  */
15467c478bd9Sstevel@tonic-gate size_t
1547f551bb10Svi sctp_saddr_info(sctp_t *sctp, int supp_af, uchar_t *p, boolean_t modify)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate 	int			i;
15507c478bd9Sstevel@tonic-gate 	int			l;
15517c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
1552df19b344Svi 	size_t			paramlen = 0;
15537c478bd9Sstevel@tonic-gate 	sctp_parm_hdr_t		*hdr;
15547c478bd9Sstevel@tonic-gate 	int			scanned = 0;
1555f551bb10Svi 	int			naddr;
1556f551bb10Svi 	int			nsaddr;
15571d8c4025Svi 	boolean_t		del_ll = B_FALSE;
15581d8c4025Svi 	boolean_t		del_lb = B_FALSE;
15591d8c4025Svi 
15601d8c4025Svi 
15611d8c4025Svi 	/*
15621d8c4025Svi 	 * On a clustered node don't bother changing anything
15631d8c4025Svi 	 * on the loopback interface.
15641d8c4025Svi 	 */
15651d8c4025Svi 	if (modify && !sctp->sctp_loopback && (cl_sctp_check_addrs == NULL))
15661d8c4025Svi 		del_lb = B_TRUE;
1567f551bb10Svi 
15681d8c4025Svi 	if (modify && !sctp->sctp_linklocal)
15691d8c4025Svi 		del_ll = B_TRUE;
15707c478bd9Sstevel@tonic-gate 
1571f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
15727c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
15737c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
15747c478bd9Sstevel@tonic-gate 			continue;
15757c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1576f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1577f551bb10Svi 		for (l = 0; l < naddr; l++) {
15787c478bd9Sstevel@tonic-gate 			in6_addr_t	addr;
15797c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
15801d8c4025Svi 			boolean_t	ipif_lb;
15811d8c4025Svi 			boolean_t	ipif_ll;
1582f551bb10Svi 			boolean_t	unsupp_af;
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
15857c478bd9Sstevel@tonic-gate 			scanned++;
1586f551bb10Svi 
15871d8c4025Svi 			ipif_lb = SCTP_IS_IPIF_LOOPBACK(ipif);
15881d8c4025Svi 			ipif_ll = SCTP_IS_IPIF_LINKLOCAL(ipif);
1589f551bb10Svi 			unsupp_af = SCTP_UNSUPP_AF(ipif, supp_af);
1590f551bb10Svi 			/*
1591f551bb10Svi 			 * We need to either delete or skip loopback/linklocal
15921d8c4025Svi 			 * or unsupported addresses, if required.
1593f551bb10Svi 			 */
15941d8c4025Svi 			if ((ipif_ll && del_ll) || (ipif_lb && del_lb) ||
15951d8c4025Svi 			    (unsupp_af && modify)) {
1596f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1597f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1598f551bb10Svi 				if (scanned < nsaddr) {
1599f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1600f551bb10Svi 					    sctp_ipif_list, obj);
1601f551bb10Svi 					sctp_ipif_hash_remove(sctp, ipif);
1602f551bb10Svi 					continue;
1603f551bb10Svi 				}
1604f551bb10Svi 				sctp_ipif_hash_remove(sctp, ipif);
1605f551bb10Svi 				goto next_addr;
16061d8c4025Svi 			} else if (ipif_ll || unsupp_af ||
16071d8c4025Svi 			    (ipif_lb && (cl_sctp_check_addrs == NULL))) {
1608df19b344Svi 				goto next_addr;
16097c478bd9Sstevel@tonic-gate 			}
1610f551bb10Svi 
1611f551bb10Svi 			if (!SCTP_IPIF_USABLE(ipif->sctp_ipif_state))
1612f551bb10Svi 				goto next_addr;
1613df19b344Svi 			if (p != NULL)
1614df19b344Svi 				hdr = (sctp_parm_hdr_t *)(p + paramlen);
16157c478bd9Sstevel@tonic-gate 			addr = ipif->sctp_ipif_saddr;
1616f551bb10Svi 			if (!ipif->sctp_ipif_isv6) {
16177c478bd9Sstevel@tonic-gate 				struct in_addr	*v4;
16187c478bd9Sstevel@tonic-gate 
1619df19b344Svi 				if (p != NULL) {
1620df19b344Svi 					hdr->sph_type = htons(PARM_ADDR4);
1621df19b344Svi 					hdr->sph_len = htons(PARM_ADDR4_LEN);
1622df19b344Svi 					v4 = (struct in_addr *)(hdr + 1);
1623df19b344Svi 					IN6_V4MAPPED_TO_INADDR(&addr, v4);
1624df19b344Svi 				}
1625df19b344Svi 				paramlen += PARM_ADDR4_LEN;
1626f551bb10Svi 			} else {
1627df19b344Svi 				if (p != NULL) {
1628df19b344Svi 					hdr->sph_type = htons(PARM_ADDR6);
1629df19b344Svi 					hdr->sph_len = htons(PARM_ADDR6_LEN);
1630df19b344Svi 					bcopy(&addr, hdr + 1, sizeof (addr));
1631df19b344Svi 				}
1632df19b344Svi 				paramlen += PARM_ADDR6_LEN;
16337c478bd9Sstevel@tonic-gate 			}
1634df19b344Svi next_addr:
1635f551bb10Svi 			if (scanned >= nsaddr)
1636df19b344Svi 				return (paramlen);
16377c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
16387c478bd9Sstevel@tonic-gate 			    obj);
16397c478bd9Sstevel@tonic-gate 		}
16407c478bd9Sstevel@tonic-gate 	}
1641df19b344Svi 	return (paramlen);
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate 
16441d8c4025Svi /*
16451d8c4025Svi  * This is used on a clustered node to obtain a list of addresses, the list
16461d8c4025Svi  * consists of sockaddr_in structs for v4 and sockaddr_in6 for v6. The list
16471d8c4025Svi  * is then passed onto the clustering module which sends back the correct
16481d8c4025Svi  * list based on the port info. Regardless of the input, i.e INADDR_ANY
16491d8c4025Svi  * or specific address(es), we create the list since it could be modified by
16501d8c4025Svi  * the clustering module. When given a list of addresses, we simply
16511d8c4025Svi  * create the list of sockaddr_in or sockaddr_in6 structs using those
16521d8c4025Svi  * addresses. If there is an INADDR_ANY in the input list, or if the
16531d8c4025Svi  * input is INADDR_ANY, we create a list of sockaddr_in or sockaddr_in6
16541d8c4025Svi  * structs consisting all the addresses in the global interface list
16551d8c4025Svi  * except those that are hosted on the loopback interface. We create
16561d8c4025Svi  * a list of sockaddr_in[6] structs just so that it can be directly input
16571d8c4025Svi  * to sctp_valid_addr_list() once the clustering module has processed it.
16581d8c4025Svi  */
16591d8c4025Svi int
16601d8c4025Svi sctp_get_addrlist(sctp_t *sctp, const void *addrs, uint32_t *addrcnt,
16611d8c4025Svi     uchar_t **addrlist, int *uspec, size_t *size)
16621d8c4025Svi {
16631d8c4025Svi 	int			cnt;
16641d8c4025Svi 	int			icnt;
16651d8c4025Svi 	sctp_ipif_t		*sctp_ipif;
16661d8c4025Svi 	struct sockaddr_in	*s4;
16671d8c4025Svi 	struct sockaddr_in6	*s6;
16681d8c4025Svi 	uchar_t			*p;
16691d8c4025Svi 	int			err = 0;
1670f4b3ec61Sdh 	sctp_stack_t		*sctps = sctp->sctp_sctps;
16711d8c4025Svi 
16721d8c4025Svi 	*addrlist = NULL;
16731d8c4025Svi 	*size = 0;
16741d8c4025Svi 
16751d8c4025Svi 	/*
16761d8c4025Svi 	 * Create a list of sockaddr_in[6] structs using the input list.
16771d8c4025Svi 	 */
16781d8c4025Svi 	if (sctp->sctp_family == AF_INET) {
16791d8c4025Svi 		*size = sizeof (struct sockaddr_in) * *addrcnt;
16801d8c4025Svi 		*addrlist = kmem_zalloc(*size,  KM_SLEEP);
16811d8c4025Svi 		p = *addrlist;
16821d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
16831d8c4025Svi 			s4 = (struct sockaddr_in *)addrs + cnt;
16841d8c4025Svi 			/*
16851d8c4025Svi 			 * We need to create a list of all the available
16861d8c4025Svi 			 * addresses if there is an INADDR_ANY. However,
16871d8c4025Svi 			 * if we are beyond LISTEN, then this is invalid
16881d8c4025Svi 			 * (see sctp_valid_addr_list(). So, we just fail
16891d8c4025Svi 			 * it here rather than wait till it fails in
16901d8c4025Svi 			 * sctp_valid_addr_list().
16911d8c4025Svi 			 */
16921d8c4025Svi 			if (s4->sin_addr.s_addr == INADDR_ANY) {
16931d8c4025Svi 				kmem_free(*addrlist, *size);
16941d8c4025Svi 				*addrlist = NULL;
16951d8c4025Svi 				*size = 0;
16961d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
16971d8c4025Svi 					*addrcnt = 0;
16981d8c4025Svi 					return (EINVAL);
16991d8c4025Svi 				}
17001d8c4025Svi 				if (uspec != NULL)
17011d8c4025Svi 					*uspec = 1;
17021d8c4025Svi 				goto get_all_addrs;
17031d8c4025Svi 			} else {
17041d8c4025Svi 				bcopy(s4, p, sizeof (*s4));
17051d8c4025Svi 				p += sizeof (*s4);
17061d8c4025Svi 			}
17071d8c4025Svi 		}
17081d8c4025Svi 	} else {
17091d8c4025Svi 		*size = sizeof (struct sockaddr_in6) * *addrcnt;
17101d8c4025Svi 		*addrlist = kmem_zalloc(*size, KM_SLEEP);
17111d8c4025Svi 		p = *addrlist;
17121d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
17131d8c4025Svi 			s6 = (struct sockaddr_in6 *)addrs + cnt;
17141d8c4025Svi 			/*
17151d8c4025Svi 			 * Comments for INADDR_ANY, above, apply here too.
17161d8c4025Svi 			 */
17171d8c4025Svi 			if (IN6_IS_ADDR_UNSPECIFIED(&s6->sin6_addr)) {
17181d8c4025Svi 				kmem_free(*addrlist, *size);
17191d8c4025Svi 				*size = 0;
17201d8c4025Svi 				*addrlist = NULL;
17211d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
17221d8c4025Svi 					*addrcnt = 0;
17231d8c4025Svi 					return (EINVAL);
17241d8c4025Svi 				}
17251d8c4025Svi 				if (uspec != NULL)
17261d8c4025Svi 					*uspec = 1;
17271d8c4025Svi 				goto get_all_addrs;
17281d8c4025Svi 			} else {
17291d8c4025Svi 				bcopy(addrs, p, sizeof (*s6));
17301d8c4025Svi 				p += sizeof (*s6);
17311d8c4025Svi 			}
17321d8c4025Svi 		}
17331d8c4025Svi 	}
17341d8c4025Svi 	return (err);
17351d8c4025Svi get_all_addrs:
17361d8c4025Svi 
17371d8c4025Svi 	/*
17381d8c4025Svi 	 * Allocate max possible size. We allocate the max. size here because
17391d8c4025Svi 	 * the clustering module could end up adding addresses to the list.
17401d8c4025Svi 	 * We allocate upfront so that the clustering module need to bother
17411d8c4025Svi 	 * re-sizing the list.
17421d8c4025Svi 	 */
1743f4b3ec61Sdh 	if (sctp->sctp_family == AF_INET) {
1744f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in) *
1745f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1746f4b3ec61Sdh 	} else {
1747f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in6) *
1748f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1749f4b3ec61Sdh 	}
17501d8c4025Svi 	*addrlist = kmem_zalloc(*size, KM_SLEEP);
17511d8c4025Svi 	*addrcnt = 0;
17521d8c4025Svi 	p = *addrlist;
1753f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
17541d8c4025Svi 
17551d8c4025Svi 	/*
17561d8c4025Svi 	 * Walk through the global interface list and add all addresses,
17571d8c4025Svi 	 * except those that are hosted on loopback interfaces.
17581d8c4025Svi 	 */
17591d8c4025Svi 	for (cnt = 0; cnt <  SCTP_IPIF_HASH; cnt++) {
1760f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[cnt].ipif_count == 0)
17611d8c4025Svi 			continue;
1762f4b3ec61Sdh 		sctp_ipif = list_head(
1763f4b3ec61Sdh 		    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list);
1764f4b3ec61Sdh 		for (icnt = 0;
1765f4b3ec61Sdh 		    icnt < sctps->sctps_g_ipifs[cnt].ipif_count;
1766f4b3ec61Sdh 		    icnt++) {
17671d8c4025Svi 			in6_addr_t	addr;
17681d8c4025Svi 
17691d8c4025Svi 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
17701d8c4025Svi 			addr = sctp_ipif->sctp_ipif_saddr;
17711d8c4025Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
17721d8c4025Svi 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
17731d8c4025Svi 			    SCTP_IS_IPIF_LOOPBACK(sctp_ipif) ||
17741d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(sctp_ipif) ||
17755d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
17761d8c4025Svi 			    (sctp->sctp_ipversion == IPV4_VERSION &&
17771d8c4025Svi 			    sctp_ipif->sctp_ipif_isv6) ||
17781d8c4025Svi 			    (sctp->sctp_connp->conn_ipv6_v6only &&
17791d8c4025Svi 			    !sctp_ipif->sctp_ipif_isv6)) {
17801d8c4025Svi 				rw_exit(&sctp_ipif->sctp_ipif_lock);
17811d8c4025Svi 				sctp_ipif = list_next(
1782f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
17831d8c4025Svi 				    sctp_ipif);
17841d8c4025Svi 				continue;
17851d8c4025Svi 			}
17861d8c4025Svi 			rw_exit(&sctp_ipif->sctp_ipif_lock);
17871d8c4025Svi 			if (sctp->sctp_family == AF_INET) {
17881d8c4025Svi 				s4 = (struct sockaddr_in *)p;
17891d8c4025Svi 				IN6_V4MAPPED_TO_INADDR(&addr, &s4->sin_addr);
17901d8c4025Svi 				s4->sin_family = AF_INET;
17911d8c4025Svi 				p += sizeof (*s4);
17921d8c4025Svi 			} else {
17931d8c4025Svi 				s6 = (struct sockaddr_in6 *)p;
17941d8c4025Svi 				s6->sin6_addr = addr;
17951d8c4025Svi 				s6->sin6_family = AF_INET6;
17961d8c4025Svi 				s6->sin6_scope_id =
17971d8c4025Svi 				    sctp_ipif->sctp_ipif_ill->sctp_ill_index;
17981d8c4025Svi 				p += sizeof (*s6);
17991d8c4025Svi 			}
18001d8c4025Svi 			(*addrcnt)++;
1801f4b3ec61Sdh 			sctp_ipif = list_next(
1802f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
18031d8c4025Svi 			    sctp_ipif);
18041d8c4025Svi 		}
18051d8c4025Svi 	}
1806f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
18071d8c4025Svi 	return (err);
18081d8c4025Svi }
18091d8c4025Svi 
18101d8c4025Svi /*
18111d8c4025Svi  * Get a list of addresses from the source address list. The  caller is
18121d8c4025Svi  * responsible for allocating sufficient buffer for this.
18131d8c4025Svi  */
18141d8c4025Svi void
18151d8c4025Svi sctp_get_saddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
18161d8c4025Svi {
18171d8c4025Svi 	int			cnt;
18181d8c4025Svi 	int			icnt;
18191d8c4025Svi 	sctp_saddr_ipif_t	*obj;
18201d8c4025Svi 	int			naddr;
18211d8c4025Svi 	int			scanned = 0;
18221d8c4025Svi 
18231d8c4025Svi 	for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
18241d8c4025Svi 		if (sctp->sctp_saddrs[cnt].ipif_count == 0)
18251d8c4025Svi 			continue;
18261d8c4025Svi 		obj = list_head(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
18271d8c4025Svi 		naddr = sctp->sctp_saddrs[cnt].ipif_count;
18281d8c4025Svi 		for (icnt = 0; icnt < naddr; icnt++) {
18291d8c4025Svi 			sctp_ipif_t	*ipif;
18301d8c4025Svi 
18311d8c4025Svi 			if (psize < sizeof (ipif->sctp_ipif_saddr))
18321d8c4025Svi 				return;
18331d8c4025Svi 
18341d8c4025Svi 			scanned++;
18351d8c4025Svi 			ipif = obj->saddr_ipifp;
18361d8c4025Svi 			bcopy(&ipif->sctp_ipif_saddr, p,
18371d8c4025Svi 			    sizeof (ipif->sctp_ipif_saddr));
18381d8c4025Svi 			p += sizeof (ipif->sctp_ipif_saddr);
18391d8c4025Svi 			psize -= sizeof (ipif->sctp_ipif_saddr);
18401d8c4025Svi 			if (scanned >= sctp->sctp_nsaddrs)
18411d8c4025Svi 				return;
1842f4b3ec61Sdh 			obj = list_next(
1843f4b3ec61Sdh 			    &sctp->sctp_saddrs[icnt].sctp_ipif_list,
18441d8c4025Svi 			    obj);
18451d8c4025Svi 		}
18461d8c4025Svi 	}
18471d8c4025Svi }
18481d8c4025Svi 
18491d8c4025Svi /*
18501d8c4025Svi  * Get a list of addresses from the remote address list. The  caller is
18511d8c4025Svi  * responsible for allocating sufficient buffer for this.
18521d8c4025Svi  */
18531d8c4025Svi void
18541d8c4025Svi sctp_get_faddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
18551d8c4025Svi {
18561d8c4025Svi 	sctp_faddr_t	*fp;
18571d8c4025Svi 
18581d8c4025Svi 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
18591d8c4025Svi 		if (psize < sizeof (fp->faddr))
18601d8c4025Svi 			return;
18611d8c4025Svi 		bcopy(&fp->faddr, p, sizeof (fp->faddr));
18621d8c4025Svi 		p += sizeof (fp->faddr);
18631d8c4025Svi 		psize -= sizeof (fp->faddr);
18641d8c4025Svi 	}
18651d8c4025Svi }
18667c478bd9Sstevel@tonic-gate 
1867f4b3ec61Sdh static void
1868f4b3ec61Sdh sctp_free_ills(sctp_stack_t *sctps)
1869f4b3ec61Sdh {
1870f4b3ec61Sdh 	int			i;
1871f4b3ec61Sdh 	int			l;
1872f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1873f4b3ec61Sdh 
1874f4b3ec61Sdh 	if (sctps->sctps_ills_count == 0)
1875f4b3ec61Sdh 		return;
1876f4b3ec61Sdh 
1877f4b3ec61Sdh 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1878f4b3ec61Sdh 		sctp_ill = list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1879f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ills[i].ill_count; l++) {
1880f4b3ec61Sdh 			ASSERT(sctp_ill->sctp_ill_ipifcnt == 0);
1881f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[i].sctp_ill_list,
1882f4b3ec61Sdh 			    sctp_ill);
1883f4b3ec61Sdh 			sctps->sctps_ills_count--;
1884f4b3ec61Sdh 			kmem_free(sctp_ill->sctp_ill_name,
1885f4b3ec61Sdh 			    sctp_ill->sctp_ill_name_length);
1886f4b3ec61Sdh 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
1887f4b3ec61Sdh 			sctp_ill =
1888f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1889f4b3ec61Sdh 		}
1890f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
1891f4b3ec61Sdh 	}
1892f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0);
1893f4b3ec61Sdh }
1894f4b3ec61Sdh 
1895f4b3ec61Sdh static void
1896f4b3ec61Sdh sctp_free_ipifs(sctp_stack_t *sctps)
1897f4b3ec61Sdh {
1898f4b3ec61Sdh 	int			i;
1899f4b3ec61Sdh 	int			l;
1900f4b3ec61Sdh 	sctp_ipif_t	*sctp_ipif;
1901f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1902f4b3ec61Sdh 
1903f4b3ec61Sdh 	if (sctps->sctps_g_ipifs_count == 0)
1904f4b3ec61Sdh 		return;
1905f4b3ec61Sdh 
1906f4b3ec61Sdh 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1907f4b3ec61Sdh 		sctp_ipif = list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
1908f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ipifs[i].ipif_count; l++) {
1909f4b3ec61Sdh 			sctp_ill = sctp_ipif->sctp_ipif_ill;
1910f4b3ec61Sdh 
1911f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
1912f4b3ec61Sdh 			    sctp_ipif);
1913f4b3ec61Sdh 			sctps->sctps_g_ipifs_count--;
1914f4b3ec61Sdh 			(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt,
1915f4b3ec61Sdh 			    -1);
1916f4b3ec61Sdh 			kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1917f4b3ec61Sdh 			sctp_ipif =
1918f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
1919f4b3ec61Sdh 		}
1920f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
1921f4b3ec61Sdh 	}
1922f4b3ec61Sdh 	ASSERT(sctps->sctps_g_ipifs_count == 0);
1923f4b3ec61Sdh }
1924f4b3ec61Sdh 
1925f4b3ec61Sdh 
19267c478bd9Sstevel@tonic-gate /* Initialize the SCTP ILL list and lock */
19277c478bd9Sstevel@tonic-gate void
1928f4b3ec61Sdh sctp_saddr_init(sctp_stack_t *sctps)
19297c478bd9Sstevel@tonic-gate {
19307c478bd9Sstevel@tonic-gate 	int	i;
19317c478bd9Sstevel@tonic-gate 
1932f4b3ec61Sdh 	sctps->sctps_g_ills = kmem_zalloc(sizeof (sctp_ill_hash_t) *
1933f4b3ec61Sdh 	    SCTP_ILL_HASH, KM_SLEEP);
1934f4b3ec61Sdh 	sctps->sctps_g_ipifs = kmem_zalloc(sizeof (sctp_ipif_hash_t) *
1935f4b3ec61Sdh 	    SCTP_IPIF_HASH, KM_SLEEP);
1936f4b3ec61Sdh 
1937f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ills_lock, NULL, RW_DEFAULT, NULL);
1938f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ipifs_lock, NULL, RW_DEFAULT, NULL);
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1941f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
1942f4b3ec61Sdh 		list_create(&sctps->sctps_g_ills[i].sctp_ill_list,
1943f4b3ec61Sdh 		    sizeof (sctp_ill_t),
19447c478bd9Sstevel@tonic-gate 		    offsetof(sctp_ill_t, sctp_ills));
19457c478bd9Sstevel@tonic-gate 	}
19467c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1947f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
1948f4b3ec61Sdh 		list_create(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
19497c478bd9Sstevel@tonic-gate 		    sizeof (sctp_ipif_t), offsetof(sctp_ipif_t, sctp_ipifs));
19507c478bd9Sstevel@tonic-gate 	}
19517c478bd9Sstevel@tonic-gate }
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate void
1954f4b3ec61Sdh sctp_saddr_fini(sctp_stack_t *sctps)
19557c478bd9Sstevel@tonic-gate {
19567c478bd9Sstevel@tonic-gate 	int	i;
19577c478bd9Sstevel@tonic-gate 
1958f4b3ec61Sdh 	sctp_free_ipifs(sctps);
1959f4b3ec61Sdh 	sctp_free_ills(sctps);
1960f4b3ec61Sdh 
19617c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++)
1962f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ills[i].sctp_ill_list);
19637c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++)
1964f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
1965f4b3ec61Sdh 
1966f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0 && sctps->sctps_g_ipifs_count == 0);
1967f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ills, sizeof (sctp_ill_hash_t) *
1968f4b3ec61Sdh 	    SCTP_ILL_HASH);
1969f4b3ec61Sdh 	sctps->sctps_g_ills = NULL;
1970f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ipifs, sizeof (sctp_ipif_hash_t) *
1971f4b3ec61Sdh 	    SCTP_IPIF_HASH);
1972f4b3ec61Sdh 	sctps->sctps_g_ipifs = NULL;
1973f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ills_lock);
1974f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ipifs_lock);
19757c478bd9Sstevel@tonic-gate }
1976